- 非对称加密算法也称为公开密钥算法,其解决了对称加密算法密钥需要预分配的难题,使得现代密码学的研究和应用取得了重大发展。
- 非对称加密算法的基本特点如下:
- 加密密钥和解密密钥不相同;
- 密钥对中的一个密钥可以公开(称为公开密钥);
- 根据公开密钥很难推算出私人密钥。
- 根据非对称加密算法的这些特点,我们可以使用非对称加密算法进行数字签名、密钥交换及数据加密等。但是,由于非对称加密算法的加密速度相对于对称加密算法来说慢很多,所以一般不直接用于大量数据的加密,而是用于数据加密密钥的交换和数字签名。并非所有非对称加密算法都可以同时用于密钥交换和数字签名,根据特点不一样,有的只能用于密钥交换,有的只能用于数字签名,而有的可能两者都可以。
- 数字签名和密钥交换对公开密钥算法的要求有一定的区别,主要有如下两点。
- 密钥交换算法使用公开密钥进行加密,使用私人密钥进行解密;而数字签名算法则使用私人密钥进行加密,使用公开密钥进行解密。
- 密钥交换算法要求从加密密钥(公开密钥)很难推算出解密密钥(私人密钥);而数字签名算法则要求从解密密钥(公开密钥)很难推算出加密密钥(私人密钥)。
- 目前来说,常用的非对称加密算法有RSA、DH和DSA三种。其中RSA既可以用于密钥交换,也可以用于数字签名,因为它能够同时满足上述两种不同的要求。DH算法一般来说只能用于密钥交换,而DSA算法则是专用于数字签名的算法。
- OpenSSL对于上述三种方法都支持,在指令里面也提供了相当丰富的应用,这些应用包括DH密钥参数的生成和解析,DSA密钥参数的生成和解析,DSA密钥生成,RSA密钥生成和使用RSA密钥进行加密和解密。
- 如表所示 是目前OpenSSL支持的非对称加密算法指令。
RSA
- 同时具备签名和密钥交换特性的公开密钥算法
- RSA加密的特点是输入数据不可以超过RSA密钥的长度(利用不同的补齐方式能够加密的长度不一样),输出数据的长度和RSA密钥长度相同,数据量很大的需要预先分隔
- 但是解密的时候输入的密文数据需要和密钥长度相等,如果密文长度很大,对每一块分别进行解密,再将所有的数据链接起来可以得到明文
- 签名的时候,先使用信息摘要函数比如(MD5,SHA1)生成160位或者128位文件的摘要信息,再使用RSA算法对摘要信息进行加密完成文件的数字签名过程
- 验签的时候,使用相同的摘要算法生成文件的摘要信息 和 使用RSA公钥解密得到的签名方的摘要信息 进行比对
- Openssl案例:rsautl 和 dgst
genrsa 指令格式
- 生成RSA密钥
- 参数 -f4 和 -3 得出 genrsa可以生成基于不同指数的RSA密钥,并可以使用不同的对称密钥对输出的密钥进行保护
- 还可以使用第三方加密软件 加密硬件设备替代OpenSSL原本的库生成RSA密钥
输出文件选项 out
- out指定密钥输出的文件名,输出的是RSA私钥,OpenSSL输出的RSA私钥会包含公钥的模数n和指数e,在需要使用公钥的时候需要从私钥中读取模数n和指数e,并进行格式的转换
- 虽然RSA密钥是成对的,包含私钥和公钥。其中公钥包含了模数n和指数e,私钥包含了d。
- OpenSSL输出的文件名和后缀并没有特殊的含义,可以取任意的名字
口令输入选项 passout
- 输入密钥文件的加密口令,和Openssl通用口令输入的格式是相同的,输入源可以为指令输入、文件、提示输入、环境变量等等
- 如果使用的时候没有输入加密口令但是指定了需要使用加密算法的选项,程序会会在指令行界面提示输入加密口令
- 如果不需要加密就可以忽略 加密口令
- 除非是测试,否则输入的加密口令一定要足够复杂、程度越长越好
加密算法的类型选项 des 3des idea aes128 aes192 aes256
- 使用对称加密算法保护RSA私钥
- 算法的类型:des 3des idea aes128 aes192 aes256
- 加密的模式都是 CBC
- 加密的密钥和初始向量都是从提供的口令中提取出来的
指数参数 f4 和 3
- RSA算法的指数e 是公开的参数,属于公钥参数中的一部分,常用的数值有 3、17、65537
- OpenSSL支持 3 和 65537
- 很多硬件设备仅仅支持 65537
- 如果使用65537作为指数数值,就可以使用或省略 f4,因为默认是65537;使用-3选项会指定指数数值为3,二者不可以同时使用
密钥的长度选项 numbits
- 密钥长度影响加密的强度 ,强度与长度成正比,与加密时间成正比
- 原则:密钥的使用周期越长 密钥要求的长度越长
其他选项
- 使用engine指定第三方软件加密库或者硬件加密设备
- 目前常常使用硬件设备来生成和存放RSA密钥,比如smart card、USBKey、加密机等硬件设备,他们具备自己的算法处理芯片,具备RSA算法的加密、解密、签名和验证等功能,使得RSA私钥永远不需要导出硬件设备就可以正常使用,其安全性要高于存储在计算机磁盘
- engine选项后面是engine ID,这个ID是编写engine接口的时候提供的,一般是一个描述性的字符串,只有正确加载engine设备和对应的驱动程序才可以正确使用
- 使用engine -t 测试目前有效的engine设备并获取对应的ID名称
- 随机数文件选项rand提供产生随机数的参考种子文件,可以进一步增加生成RSA密钥的随机性,增加安全性
- 如果没有指定,程序会从标准输出设备的状态读取信息作为随机数的种子,随机数文件可以为任意类型的文件
- 也可以调用engine设备的随机数产生函数
应用实例
管理RSA密钥
RSA指令格式
- 具体使用的时候需要对密钥进行一些处理,比如重新设置加密口令或者对称加密方法、解析私钥输出公钥参数、格式转换
- 使用rsa指令完成密钥管理的功能
- * 密钥学常用的密钥管理涉及的是安全存放和安全传输 和这里的密钥管理还存在很大的差异
- RSA还可以通过engine处理存储在硬件设备中的私钥
密钥的格式转换 inform和outform
- 早期的Openssl只提供了REM、DER和NET三种类型
- 如果输入的是RSA私钥,支持的格式包括DER编码格式、PEM编码格式、PKCS#12编码格式、Netscape编码格式、旧版的IISSGC编码格式及ENGINE格式。如果输入的是RSA公钥,则比RSA私钥少支持一种PKCS#12格式,这是因为PKCS#12格式一般用来封装证书和私钥,而不直接用于封装公钥。
- 表格所示 是0.9.7版本支持的密钥格式,最新的需要参考官网
- 指令字符串参数是只在inform或outform选项后面填写的参数,它们一般对大小写不敏感,比如对于DER编码,可以指定为“-inform D”或者“-inform d”,它们是相同的。
- 如果指定密钥的输入格式为ENGINE,那么密钥输入文件(in选项指定的文件)的内容及其含义依具体的Engine接口代码而定,可能是一个ID值,也可能是一个公钥文件,甚至可能毫无意义。
- rsa指令支持的密钥输出格式(outform选项指定)比较少,仅包含DER编码格式、PEM编码格式、NET编码格式及SGC编码格式。其中,SGC编码格式的指定需要使用-sgckey选项。
输入和输出文件选项in和out
- in 指定了输入密钥的文件的名称,默认情况下是RSA私钥文件
- 如果参数指定了 -pubin 即输入文件是包含了RSA的公钥的文件
- 文件的具体格式可以使用-inform选项指定,如果在inform选项中指定输入的文件格式是ENGINE格式并且使用了engine选项,那么输入文件的内容和意义视具体的Engine接口代码而定。
- out指定了输出的文件的名称,默认情况输出的是RSA私钥,但是使用了-pubout选项或者输入为公钥,输出内容是RSA的公钥
- 使用noout选项,本选项会被简单的忽略掉
输入和输出口令选项 passin 和 passout
- 加密保护使用的口令包含加密保护使用的密钥和初始向量,因此使用RSA的时候也需要输入对应的口令
- passin选型指定了获取RSA私钥解密口令的源;passout选项指定了输出RSA私钥时进行加密的口令的源
- 如果输入和输出的是公钥,那么passout选项会被简单的忽略
- 如果输入的密钥文件需要口令进行解密而没有使用pasin选项提供口令,那么程序会在指令行提示用户输入解密口令。
加密算法选项
- 跟genrsa指令一样,rsa指令也提供了六种常用的分组加密算法用于加密RSA私钥,这些算法包括DES、DES3、IDEA、128位AES、192位AES和256位AES算法。如果输入使用了这些加密选项之一但是却没有使用pasout提供加密口令,那么将会在指令行提示输入加密口令。
- 如果输入的是公钥或者输出的是公钥文件,那么该加密选项将会被忽略。
- 如果使用engine选项指定了有效的Engine设备,而Engine设备正好支持选定的加密算法,那么将采用Engine设备提供的加密算法加密生成密钥,而不再是使用OpenSSL算法库进行密钥的加密。
信息输出选项 text、noout、modules
- 使用text选项将会以明文的形式输出密钥各个参数的值
- 使用modulus选项则专门输出模数值
- 如果使用了noout选项,那么就不会输出任何密钥到文件中,即便使用了out选项指定了输出文件也会被忽略。
密钥输入和输出的类型的选项 pubin和pubout
- 默认情况下输入文件应该是RSA私钥文件
- 如果要输入的是RSA公钥文件,则应该使用-pubin选项,该选项没有参数
- 如果输入的是RSA私钥想得到一个与之对应的公钥,需要指定pubout;任何和密钥加密相关的选项都不会忽略,比如passout、des等。因为公钥是公开的,不能泄密,也不需要对其进行保护
使用第三方加密库或者硬件密钥
- 使用engine选项指定要使用的第三方加密库或者硬件。engine选项后面的参数是Engine的ID,通常是一个简短的描述字符串,由相应的Engine接口代码决定。
- 使用Engine选项后,rsa指令中两个部分可能受到影响。首先是输入密钥,如果在inform中也指定了输入密钥格式是ENGINE格式,那么指令将试图从Engine设备中加载密钥而不是直接从文件中读取密钥,当然,这时候in选项提供的文件可能包含了一些加载密钥需要的有用信息,也可能是Engine设备里面RSA私钥对应的公钥参数。其次,如果选定的密钥加密算法在Engine中支持,那么将会使用Engine中的密钥加密算法加密密钥,而不再是使用OpenSSL默认的算法库加密RSA私钥。
其他选项
- check选项使用后,指令将会检测输入RSA密钥的正确性和一致性。如果输入或者输出的密钥是SGC格式,那么应该使用sgckey选项进行格式的转换和调整。
- SGC选项目前一般不使用,它是一种经过修改的NET格式,用于旧版本的IS服务器
例子
使用RSA密钥
rsautl指令格式
- 由于rsautl指令的签名功能没有使用信息摘要算法,所以不能用来实现对文件或者其他大量的数据体进行真正意义上的数字签名,而只能对符合表的输入数据长度条件的小量数据进行数字签名操作,也就是RSA私钥加密操作。
- OpenSSL的rsautl指令的格式如下:
数据输入和输出文件选项in和out
- in选项指定了存储输入数据的文件选项,需要注意的是,如果执行的是加密操作(sign或者encrypt),那么输入数据的长度一定要符合输入数据长度的要求,否则rsautl指令将不能成功执行。
- 如果是解密操作(verify或者decrypt),那么输入数据长度总是跟RSA密钥长度相同。
- out选项指定了接收输出数据的文件选项,对于rsautl指令来说,如果是加密操作(sign或者encrypt),那么输出数据长度总是跟密钥长度相同,比如对于1024位的RSA密钥,输出数据长度就总是128字节(1024位)。
- 默认的输入输出设备是标准输入和输出设备。
操作类型选项sign、verify、encrypt和decrypt
- rsautl指令通过inkey选项指定加密或解密操作中要使用的密钥的存储文件。默认情况下,无论是上述四种操作中的哪一种,输入的密钥都应该为PEM格式的RSA私钥。实际上,因为OpenSSL的PEM编码,RSA私钥里面包含了公钥参数,所以即便在执行公钥加密或者解密操作时输入的是RSA私钥,那么也能够正确执行,因为指令程序会自动使用RSA私钥里面的公钥参数进行相应的公钥操作。
- RSA密钥的输入格式可以是多样的,默认的是PEM编码格式,其具体的格式可以通过keyform选项来指定,keyform选项支持的参数可以上表。目前来说,如果输入的是RSA私钥,rsautl指令支持的格式包括DER编码格式、PEM编码格式、PKCS#12编码格式、Netscape编码格式、旧版的IISSGC编码格式及ENGINE密钥格式。如果输入的是RSA公钥,则比RSA私钥少支持一种PKCS#12格式。如果keyform指定输入的密钥是ENGINE格式(-keyfrome),那么inkey指定的密钥文件内容及意义要根据具体的Engine接口而定,可能是一个密钥ID字符串,可能是一个公钥文件,也可能是没有任何意义的文件。如果你在执行公钥解密(verify)操作或者公钥加密(encrypt)操作,那么可以从nkey参数输入一个公钥而不是私钥,使用pubin选项就可以告诉指令程序将要输入的文件是公钥文件。如果你希望使用一个证书里面的公钥文件,那么可以使用-certin选项告诉指令程序inkey选项指定将要输入的文件是一个证书文件。同样,证书文件的格式可以通过keyform选项来指定,目前支持的证书格式包括DER编码、PEM编码、NET编码和PKCS#12编码格式四种。
数据补齐方式选项pkcs、ssl、oaep和raw
- 所谓数据补齐方式是指在利用RSA密钥进行数据加密的时候,总是要求被加密数据长度跟RSA密钥长度相同,但是输入数据通常不是正好跟RSA密钥长度相同,所以需要将不同长度的被加密数据补齐成跟密钥长度相同的数据然后再进行加密;
- 当然,如果数据超出RSA密钥长度,则需要自己预先分割。
- OpenSSL目前支持的补齐方式包括PKCS#1v1.5规定的方式、SSL协议规定的补齐方式、OAEP补齐方式和不使用补齐的方式。默认的数据补齐方式是PKCS#1v1.5。
- PKCS#1v1.5补齐方式是目前使用最广泛的补齐方式,如果要用PKCS#1v1.5补齐方式,那么可以在指令中使用-pkcs选项。SSL协议规定的补齐方式是PKCS#1v1.5的修订版,本质上区别不大,使用-ssl选项调用该种方式。这两种基于PKCS#1v1.5的补齐方式都要求每次加密输入的实际数据长度小于密钥长度-11字节。
- OAEP方式是PKCS#1v2.0规定的新补齐方式,对于新的应用程序,一般来说推荐这种新的方式。要用这种方式,在指令中使用-oaep选项。该种补齐方式要求每次加密输入的数据长度不能超过密钥长度-41字节的长度。
- 最后,如果你不愿意使用任何补齐方式,那么-raw选项是你的选择。但是,如不使用补齐方式,数据长度必须跟RSA密钥长度相同。需要注意的是,如果执行的是签名操作(RSA私钥加密),那么只能使用PKCS#1v1.5的补齐方式或者不使用补齐方式。
engine选项
- 与其他OpenSSL指令一样,rsautl指令也提供了对Engine的支持,可以通过Engine机制使用第三方算法库或者硬件设备而不是OpenSSL本身的RSA算法进行加密、解密、签名和验证信息。
- engine选项后面应该给出有数的Engine设备ID,该ID一般是一个简短的描述字符串,由Engine接口代码决定。在该选项给定了有效的Engine接口设备之后,rsautl有两个方面会受到影响。首先是RSA密钥的获取会受到影响。如果在使用了engine选项后,keyform中指定了密钥的输入格式是Engine格式,那么指令将试图从Engine设备中获取加密密钥。这时候inkey选项指定的密钥文件内容就根据具体的Engine接口要求而定。其次,如果使用了engine选项,而且Engine设备支持RSA的公钥加密、私钥解密、私钥加密和公钥解密的函数的全部或其中一部分,那么就会启用Engine设备执行加密或者解密的操作,而不是使用OpenSSL的RSA算法。当然,如果Engine不支持或者只支持其中的一部分加密操作,那么不支持的部分就会调用OpenSSL算法库本身的RSA加密操作。
其他选项
- 如果你希望输出数据的十六进制的解析信息,那么可以使用hexdump选项来实现。使用asn1 parse可以看到使用ASN.1编码(事实上一般是DER编码)的数据对象的明文解析和对应的编码数据,该选项在跟verify选项一起使用的时候比较有用,可以用来查看验证的签名的信息。上述两个选项一般来说在执行解密操作的时候意义更大一些,否则只是一些看起来没有意义的乱码。有时候你可能想把输入的数据颠倒顺序后再进行加密或解密操作,比如把“123456789”变成“987654321”,那么可以使用rev选项实现你这个奇怪的想法。也就是说,如果你使用了rev选项,虽然你输入的数据是“123456789”,事实上你加密的数据是“987654321”。