1.1 三类常见填充方式
RSA加密常用的填充模式有三种:RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING, RSA_NO_PADDING。
其他的还有:ISO10126Padding、OAEPPadding、PKCS5Padding、SSL3Padding,OAEPPadding。
与对称加密算法DES,AES一样,RSA算法也是一个块加密算法( block cipher algorithm),总是在一个固定长度的块上进行操作。但跟AES等不同的是,block length是跟key length有关的。
每次RSA加密的明文的长度是受RSA填充模式限制的,但是RSA每次加密的块长度就是key length。
填充方式 | 输入 | 输出 | 条件 |
RSA_PKCS1_PADDING | 必须 比 RSA 钥模长(modulus) 短至少11个字节, 也就是 RSA_size(rsa) – 11 | 和modulus一样长 | |
RSA_PKCS1_OAEP_PADDING | RSA_size(rsa) – 41 | 和modulus一样长 | |
RSA_NO_PADDING | 可以和RSA钥模长一样长,如果输入的明文过长,必须切割, 然后填充 | 和modulus一样长 | |
RSA_size(rsa) = key length/8。
各个长度密钥单次加密最大明文字节512bit/8 -11=64-11=53bytes; 1024bit/8 -11=128-11= 117bytes; 2048bit/8-11=256-11=245bytes;明文超过最大长度,需要分段加密解密,然后再拼装。
1.2 不同模式下的加密的最大数据长度
- 在不同的padding模式下,使用相同长度的密钥可以加密的数据最大长度不同;
- 在不同密钥长度下,使用相同的padding模式可以加密的数据最大长度也不同;
因此,脱离了密钥长度而讨论padding模式可以加密的最大长度是不严谨的。
常用的密钥长度有1024bits,2048bits等,理论上1024bits的密钥可以加密的数据最大长度为1024bits(即1024/8 = 128bytes)。2048bits的密钥可以加密的数据最大长度为2048bits(2048/8 = 256bytes),但是RSA在实际应用中不可能使用这种“教科书式的RSA”系统。实际应用中RSA经常与填充技术(padding)一起使用,可以增加RSA的安全性。填充技术实现的不好,RSA也不会安全。原因如下:
- RSA加密是确定的,即给定一个密钥,特定明文总会映射到特定的密文。攻击者可以根据密文中统计信息获取明文的一些信息。
- 填充技术如果比较弱,那么较小的明文和小型公开指数e将易于受到攻击。
- RSA有个特性叫做延展性,如果攻击者可以将一种密文转换为另一种密文,儿这种新密文会导致对明文的转换变得可知,这种特性并没有解密明文,而是以一种可预测的方式操纵了明文,比如:银行交易系统中,攻击者根据新密文,直接去修改原密文中金额的数据,可以在用户和接受方无法感知的情况下进行修改。
所以,填充技术关系到RSA的安全性的高低。最优非对称填充(OAEP)就是一种优秀的填充方式,对应上述表格中RSA_PKCS1_OAEP_PADDING填充方式。
在BouncyCastle实现RSA的PKCS1V1.5模式中,如果是公钥加密信息(forEncryption=true),密钥长度为1024位,那么输出的密文块长度为128个字节,输入的明文块长度为127-10,即输入的明文块最大是117位,如果输入的明文块小于117位,比如输入的明文块长度为64位,那么会对这个明文块进行补位,在明文块前添加一位的0x02字节(代表公钥加密)然后后面的52位为随机的字节,在补位的最后一位,{即52(117-64-1),从零开始的},添加一位的字节0x00,在补位的后面添加实际的明文块。
这样做的目的就是使得明文块转化成与module差不多的大整数。
如果是私钥加密(forPrivateKey=true),密钥长度为1024位,那么输出 的密文块长度也是128字节,输入的明文块的长度为127-10,即输入的明文块最大是117位,如果输入的明文块小于117位,比如输入的明文块长度为64位,那么对这个明文块进行补位,在明文块前添加一位的0x01字节(代表私钥加密),然后在后面的52位为字节0xff,在最后一位{即52(117-64-1),从零开始),添加一位的字节0x00,在补位的后面添加时间的明文块。
RSA算法在运算时需要将数据填充至分组长度(与RSA密钥模长相等)。
PAD方式分下面两种:
私钥:私钥加密填充. 标志: 0x01. 填充:0xFF
EM = 0x00 || 0x01 || PS || 0x00 || T
PS : pad with 0xFF, length : Len(EM) - 3 - Len(T)
公钥:公钥加密填充. 标志: 0x02. 填充:非零随机数
EM = 0x00 || 0x02 || PS || 0x00 || M
PS : pad with random data, length : Len(EM) - 3 - Len(M)
无填充其实就是在高位填充 0x00.
填充串PS的长度最少为8个字节,这是RSA操作的一种安全措施。
所以RSA签名的数据长度不能超过分组长度-11字节。
填充数据算法进行如下理解:
PKCS #1 RSA Encryption Version 1.5
在进行RSA运算时需要将源数据D转化为Encryption block(EB)。其中pkcs1padding V1.5的填充模式安装以下方式进行
(1) EB = 00+ BT+PS +00 + D
说明
EB:为转化后Hex进制表示的数据块,长度为128个字节(密钥1024位的情况下)
00:开头为00。个人认为应该是一个保留位。因为目前BT的类型至于三种(00,01,02)一个字节就可以表示。
BT:用一个字节表示,在目前的版本上,有三个值00 01 02,如果使用公钥操作,BT永远为02,如果用私钥操作则可能为00或01。
PS:为填充位PS由k-3-D这么多个字节构成,k表示密钥的字节长度,如果我们用1024bit的RSA密钥,这个长度就是1024/8=128 ,D表示明文数据D的字节长度
对于BT为00的,则这些字节全部为00,对于BT为01的这些值全部为FF,对于BT为02的,这些字节的值随机产生但不能是0字节(就是00)。
00:在源数据D前一个字节用00表示
D:实际源数据
公式(1)整个EB的长度就是密钥字节的长度。
对于BT为00的,数据D中的数据就不能以00字节开头,要不然会有歧义,因为这时候你PS填充的也是00,就分不清哪些是填充数据哪些是明文数据了
但如果你的明文数据就是以00字节开头怎么办呢?对于私钥操作,你可以把BT的值设为01,这时PS填充的FF,那么用00字节就可以区分填充数据和明文数据对于公钥操作,填充的都是非00字节,也能够用00字节区分开。如果你使用私钥加密,建议你BT使用01,保证了安全性。
对于BT为02和01的,PS至少要有8个字节长,BT为02肯定是公钥加密,01肯定是私钥加密,要保证PS有八个字节长
因为EB= 00+BT+PS+00+D=k
所以D<=k-11,所以当我们使用128字节密钥对数据进行加密时,明文数据的长度不能超过过128-11=117字节
当RSA要加密数据大于 k-11字节时怎么办呢?把明文数据按照D的最大长度分块然后逐块加密,最后把密文拼起来就行。
除了PKCS #1 v1.5指定的填充方式外,后续版本对填充方式进行了更新:
- PKCS #1 v2.0 指定了针对加密使用的OAEP填充方式
- PKCS #1 v2.1 又进一步指定了针对签名使用的PSS填充方式
有兴趣研究 RSA算法的,可以参考英文文档:
V1.5:https://tools.ietf.org/html/rfc2313
V2.0:https://tools.ietf.org/html/rfc2437
V2.1:https://tools.ietf.org/html/rfc3447
V2.2:https://tools.ietf.org/html/rfc8017
友情提醒:国内都推国密了哦,用SM2算法吧 :)