区块链中的数学 – PKCS和RSA填充标准

本节从实用角度讲了公钥密码学标准和RSA的padding标准及使用。可以总结如下: 每次RSA加密明文的长度是受RSA填充模式限制的,但是RSA每次加密的块长度是固定的,就是key length

## 写在前面 上一节整理了[RSA运算中的快速幂模运算](https://learnblockchain.cn/article/1573)。 本节介绍下PKCS标准和Java中相关实现, ## PKCS PKCS全称Public Key Cryptography Standers, 是RSA信息安全公司与其合作伙伴共同制定的,被信息界的产业广泛认同。 下面简要罗列下主要的PKCS内容: **PKCS#1**:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名和数字信封。 **PKCS#3**:定义Diffie-Hellman密钥交换协议。 **PKCS#5**:描述一种利用从口令派生出来的安全密钥加密字符串的方法。从口令中派生密钥,并采用DES-CBC模式加密。主要用于加密从一个计算机传送到另一个计算机的私人密钥,不能用于加密消息。 **PKCS#6**:描述了公钥证书的标准语法,主要描述X.509证书的扩展格式。 **PKCS#7**:定义一种通用的消息语法,包括数字签名和加密等用于增强的加密机制,PKCS#7与PEM兼容,所以不需其他密码操作,就可以将加密的消息转换成PEM消息。 **PKCS#8**:描述私有密钥信息格式,该信息包括公开密钥算法的私有密钥以及可选的属性集等。 **PKCS#9**:定义一些用于PKCS#6证书扩展、PKCS#7数字签名和PKCS#8私钥加密信息的属性类型。 **PKCS#10**:描述证书请求语法。 **PKCS#11**:称为Cyptoki,定义了一套独立于技术的程序设计接口,用于智能卡和PCMCIA卡之类的加密设备。 **PKCS#12**:描述个人信息交换语法标准。描述了将用户公钥、私钥、证书和其他相关信息打包的语法。 **PKCS#13**:椭圆曲线密码体制标准。 **PKCS#14**:伪随机数生成标准。 **PKCS#15**:密码令牌信息格式标准。 注:近年来RSA公司也与其他组织(比较知名的有IETF、PKIX)将标准的制定通过standards track程序来达成,并不包含在上面的列表中,感兴趣的可自行查阅。 简单知道一下,需要的时候再看具体内容。下面具体说下PKCS中RSA的padding方式。 ## RSA填充方式 RSA加密常用的填充模式有三种【注:其实第三种已经不常用了】: | 填充方式 | 输入明文最大值 | | :-- | :-- | | RSA_PKCS1_PADDING | RSA_size(rsa) – 11 | | RSA_PKCS1_OAEP_PADDING | RSA_size(rsa) – 41 | | RSA_NO_PADDING | 可同RSA钥模长一样,如过长,必须切割,然后填充 | 三者的输出都是模长的位数。 填充方式规范见于PKCS#1_v1.5 下面详细说说这三种方式: ### RSA_PKCS1_PADDING 这种方式是Java库中默认采用的填充方式,其格式如下: ***00 02 [R] 00 [M]*** 第一位默认为00 第二位是块类型:01表示签名,02表示加解密 第三部分是一串随机数R 第四部分是一个0 最后一部分就是明文, 其中随机R的位数大小是根据其他几个字段决定的,如下: R位数 = 公钥n位数 - 3 - 明文M位数 而PKCS#1建议最小的随机数R为8位才足够安全,可得明文最大是: 公钥n位数 - 11 * 8 下面列出不同公钥大小能加密的明文最大长度: 1024: (1024 - 11 * 8) / 8= 117 2048: (2048 - 11 * 8) /8 = 245 4096: (4096 - 11 * 8)/8 = 501 使用1024位的话,最大单次加密只能117个字节,这也通常被认为是RSA的一个缺点【虽然增加位数能提高支持明文长度,比如2048位,也最多245个字节,依然很小】,虽然在理论上可以支持大于n的数据加密(分组),实际应用中考虑各种因素并没有这么做。如果传入大于117字节数据,会抛出异常“javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes” 这一种方式已经比较安全了,唯一一点瑕疵是明文的完整性不好百分百确保,下面要说的OAEP方式又引入了hash校验。 #### RSA_PKCS1_OAEP_PADDING 这种方式安全性是最高的,和前面RSA_PKCS1_PADDING的区别就是加密前的编码方式不一样。 OAEP的组成由明文文的Hash + 随机数+分隔符+原文, 具体的操作参见[RSA密文攻击与OAEP](https://learnblockchain.cn/article/1562) 如何在代码中指定使用OAEP模式呢?图中展示了Java代码调用示例。 ![](https://img.learnblockchain.cn/2020/10/12/16024851075357.jpg) #### RSA_NO_PADDING 当你在客户端选择RSA_NO_PADDING填充模式时,如果明文不够128字节 加密的过程会在明文前面填充0。当然,解密后的明文也会包括前面填充的0,这时需要服务器把解密后的字段去掉前面的0,才是真正的明文。 当然如果本来明文就以0开头的,就难以区别是填充的0还是明文中的0,使用时要注意。截图是个实验实例:明文是“test no padding message!”, 前面都是被填充的0 ![](https://img.learnblockchain.cn/2020/10/12/16024851550771.jpg) 这种填充方式因为安全性低使用较少,Java代码中可按如下指定使用该方法,不再赘述。 ``` Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); ``` 填充技术关系到RSA的安全性的高低,这在之前安全分析文章可以看出。现在一般推荐OAEP的填充模式。 ## 小结 本节从实用角度讲了公钥密码学标准和RSA的padding标准及使用。可以总结如下: **每次RSA加密明文的长度是受RSA填充模式限制的,但是RSA每次加密的块长度是固定的,就是key length** 关于PCKS1.5&RSA的详细paper,参见:http://tools.ietf.org/html/rfc2313 关于RSA的主题还有一个是在VRF(Verified Random Function)可验证随机函数中的应用。以后找机会再说。 好了,下一篇继续说[schnorr经典签名机制](https://learnblockchain.cn/article/1527)。 欢迎关注公众号:blocksight

写在前面

上一节整理了RSA运算中的快速幂模运算。 本节介绍下PKCS标准和Java中相关实现,

PKCS

PKCS全称Public Key Cryptography Standers, 是RSA信息安全公司与其合作伙伴共同制定的,被信息界的产业广泛认同。 下面简要罗列下主要的PKCS内容:

PKCS#1:定义RSA公开密钥算法加密和签名机制,主要用于组织PKCS#7中所描述的数字签名和数字信封。 PKCS#3:定义Diffie-Hellman密钥交换协议。 PKCS#5:描述一种利用从口令派生出来的安全密钥加密字符串的方法。从口令中派生密钥,并采用DES-CBC模式加密。主要用于加密从一个计算机传送到另一个计算机的私人密钥,不能用于加密消息。 PKCS#6:描述了公钥证书的标准语法,主要描述X.509证书的扩展格式。 PKCS#7:定义一种通用的消息语法,包括数字签名和加密等用于增强的加密机制,PKCS#7与PEM兼容,所以不需其他密码操作,就可以将加密的消息转换成PEM消息。 PKCS#8:描述私有密钥信息格式,该信息包括公开密钥算法的私有密钥以及可选的属性集等。 PKCS#9:定义一些用于PKCS#6证书扩展、PKCS#7数字签名和PKCS#8私钥加密信息的属性类型。 PKCS#10:描述证书请求语法。 PKCS#11:称为Cyptoki,定义了一套独立于技术的程序设计接口,用于智能卡和PCMCIA卡之类的加密设备。 PKCS#12:描述个人信息交换语法标准。描述了将用户公钥、私钥、证书和其他相关信息打包的语法。 PKCS#13:椭圆曲线密码体制标准。 PKCS#14:伪随机数生成标准。 PKCS#15:密码令牌信息格式标准。

注:近年来RSA公司也与其他组织(比较知名的有IETF、PKIX)将标准的制定通过standards track程序来达成,并不包含在上面的列表中,感兴趣的可自行查阅。

简单知道一下,需要的时候再看具体内容。下面具体说下PKCS中RSA的padding方式。

RSA填充方式

RSA加密常用的填充模式有三种【注:其实第三种已经不常用了】:

填充方式 输入明文最大值
RSA_PKCS1_PADDING RSA_size(rsa) – 11
RSA_PKCS1_OAEP_PADDING RSA_size(rsa) – 41
RSA_NO_PADDING 可同RSA钥模长一样,如过长,必须切割,然后填充

三者的输出都是模长的位数。 填充方式规范见于PKCS#1_v1.5

下面详细说说这三种方式:

RSA_PKCS1_PADDING

这种方式是Java库中默认采用的填充方式,其格式如下:

00 02 [R] 00 [M]

第一位默认为00 第二位是块类型:01表示签名,02表示加解密 第三部分是一串随机数R 第四部分是一个0 最后一部分就是明文, 其中随机R的位数大小是根据其他几个字段决定的,如下: R位数 = 公钥n位数 - 3 - 明文M位数 而PKCS#1建议最小的随机数R为8位才足够安全,可得明文最大是: 公钥n位数 - 11 * 8 下面列出不同公钥大小能加密的明文最大长度:

1024: (1024 - 11 8) / 8= 117 2048: (2048 - 11 8) /8 = 245 4096: (4096 - 11 * 8)/8 = 501

使用1024位的话,最大单次加密只能117个字节,这也通常被认为是RSA的一个缺点【虽然增加位数能提高支持明文长度,比如2048位,也最多245个字节,依然很小】,虽然在理论上可以支持大于n的数据加密(分组),实际应用中考虑各种因素并没有这么做。如果传入大于117字节数据,会抛出异常“javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes”

这一种方式已经比较安全了,唯一一点瑕疵是明文的完整性不好百分百确保,下面要说的OAEP方式又引入了hash校验。

RSA_PKCS1_OAEP_PADDING

这种方式安全性是最高的,和前面RSA_PKCS1_PADDING的区别就是加密前的编码方式不一样。

OAEP的组成由明文文的Hash + 随机数+分隔符+原文, 具体的操作参见RSA密文攻击与OAEP

如何在代码中指定使用OAEP模式呢?图中展示了Java代码调用示例。

RSA_NO_PADDING

当你在客户端选择RSA_NO_PADDING填充模式时,如果明文不够128字节 加密的过程会在明文前面填充0。当然,解密后的明文也会包括前面填充的0,这时需要服务器把解密后的字段去掉前面的0,才是真正的明文。

当然如果本来明文就以0开头的,就难以区别是填充的0还是明文中的0,使用时要注意。截图是个实验实例:明文是“test no padding message!”, 前面都是被填充的0

这种填充方式因为安全性低使用较少,Java代码中可按如下指定使用该方法,不再赘述。

Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");

填充技术关系到RSA的安全性的高低,这在之前安全分析文章可以看出。现在一般推荐OAEP的填充模式。

小结

本节从实用角度讲了公钥密码学标准和RSA的padding标准及使用。可以总结如下: 每次RSA加密明文的长度是受RSA填充模式限制的,但是RSA每次加密的块长度是固定的,就是key length

关于PCKS1.5&RSA的详细paper,参见:http://tools.ietf.org/html/rfc2313

关于RSA的主题还有一个是在VRF(Verified Random Function)可验证随机函数中的应用。以后找机会再说。

好了,下一篇继续说schnorr经典签名机制。

欢迎关注公众号:blocksight

区块链技术网。

  • 发表于 2020-07-16 23:28
  • 阅读 ( 1175 )
  • 学分 ( 0 )
  • 分类:入门/理论

评论