为什么RSA公钥每次加密得到的结果都不一样?

原文地址:https://blog.csdn.net/guyongqiangx/article/details/74930951

原作者:guyongqiangx 

RSA加密算法是一种非对称加密算法 是由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。RSA密钥至少为500位长,一般推荐使用1024位。RSA密钥长度随着保密级别提高,增加很快。由于RSA的特性,一个1024位的密钥只能加密117位字节数据,当数据量超过117位字节的时候,程序就会抛出异常。

< OpenSSL和Python实现RSA Key公钥加密私钥解密>中提到,发现使用RSA公钥对同一数据加密,每次的结果都不一样。百度一下,很多人都有这个疑问,但并没有看到详细的分析解答,即使有人说是因为padding填充的原因,也都是一带而过。

为什么私钥对同一数据进行签名加密的结果是一样的,使用公钥进行加密就不一样了呢?

是的,这个问题跟对数据的padding即填充有关,详细说来,是跟PKCS #1 v1.5指定的padding方式有关,下面对这个问题进行详细的说明。

1. 问题的来源

重复下这个问题的来源:

1.1 准备测试数据

将字符串”I Love China!”保存到msg.bin作为测试数据

$ echo -n "I Love China!" > msg.bin

$ hexdump -Cv msg.bin

00000000  49 20 4c 6f 76 65 20 43  68 69 6e 61 21          |I Love China!|

0000000d

随机生成测试用的私钥key.pem,并导出公钥key_pub.pem:

$ openssl genrsa -out key.pem -f4 2048

Generating RSA private key, 2048 bit long modulus

........+++

.......+++

e is 65537 (0x10001)

$ openssl rsa -in key.pem -pubout -out key_pub.pem

writing RSA key

1.2 使用私钥对同一数据签名

使用私钥key.pem对msg.bin进行两次签名,签名结果分别为msg.bin.sig1和msg.bin.sig2:

$ openssl dgst -sha256 -out msg.bin.sig1 -sign key.pem msg.bin

$ openssl dgst -sha256 -out msg.bin.sig2 -sign key.pem msg.bin

$ md5sum msg.bin.sig1 msg.bin.sig2

4d10a2163f92f90f114126de2371deb8  msg.bin.sig1

4d10a2163f92f90f114126de2371deb8  msg.bin.sig2

从签名数据的md5校验和看,msg.bin.sig1和msg.bin.sig2的md5值一样,其内容显然是一样的。

1.3 使用公钥对同一数据加密

使用公钥key_pub.pem对msg.bin进行两次加密,加密结果分别为msg.bin.enc1和msg.bin.enc2:

$ openssl rsautl -in msg.bin -out msg.bin.enc1 -inkey key_pub.pem -pubin -encrypt

$ openssl rsautl -in msg.bin -out msg.bin.enc2 -inkey key_pub.pem -pubin -encrypt

$ md5sum msg.bin.enc1 msg.bin.enc2

19c3bf692e94eaf87770001181c5eb10  msg.bin.enc1

f576f31a796332fcd3c4d3627ef4ad5d  msg.bin.enc2

显然msg.bin.enc1与msg.bin.enc2的md5不一样,二者的内容也不一样,也就是说,使用同一个RSA公钥对同一段数据加密,两次加密的结果不一样。

2. PKCS #1 v1.5指定的填充方式

除了PKCS #1 v1.5指定的填充方式外,后续版本对填充方式进行了更新:

PKCS #1 v2.0 指定了针对加密使用的OAEP填充方式

PKCS #1 v2.1 又进一步指定了针对签名使用的PSS填充方式

这里只讨论早期PKCS #1 v1.5指定的简单的填充方式,也是目前最常见的填充方式。

RSA建议,为提高安全性,在新的应用中应逐步采用OAEP和PSS方式的进行填充。

2.1 填充方式的描述

不管是使用RSA私钥进行签名还是公钥进行加密,操作中都需要对待处理的数据先进行填充,然后再对填充后的数据进行加密处理。针对如何对内容进行填充,”[RFC2313] PKCS #1: RSA Encryption Version 1.5“的”8.1 Encryption-block formatting“节提供了详细的说明,原文如下:

8.1 Encryption-block formatting

  A block type BT, a padding string PS, and the data D shall be

  formatted into an octet string EB, the encryption block.

              EB = 00 || BT || PS || 00 || D .          (1)

  The block type BT shall be a single octet indicating the structure of

  the encryption block. For this version of the document it shall have

  value 00, 01, or 02. For a private- key operation, the block type

  shall be 00 or 01. For a public-key operation, it shall be 02.

  The padding string PS shall consist of k-3-||D|| octets. For block

  type 00, the octets shall have value 00; for block type 01, they

  shall have value FF; and for block type 02, they shall be

  pseudorandomly generated and nonzero. This makes the length of the

  encryption block EB equal to k.

由于篇幅的原因,这里没有列出针对这段话的”Notes”部分,可以通过点击原文链接查看。

简单说来,PKCS #1 v1.5规定的填充格式为:

EB = 00 || BT || PS || 00 || D

其中:

D: data (指待处理数据,即填充前的原始数据)

PS: padding string (填充字符串)

BT: block type (数据块类型)

EB: encryption block (待加密的数据块,经过填充后结果)

||: 表示连接操作 (X||Y表示将X和Y的内容连接到一起)

所以:

"填充后数据" = "00" + "数据块类型" + "填充字符串" + "00" + "原始数据"

“填充块类型”BT决定了紧挨着的”填充字符串”PS的内容。

BT的可能取值包括00, 01和02:

   ◆ 针对私钥处理的数据,BT取值为00或01;

       ◆ BT取值为00时,PS为全00的字符串

       ◆ BT取值为01时,PS为全FF的字符串,通过填充得到的整数会足够大,可以阻止某些攻击,因此也是推荐的填充方式

  ◆ 针对公钥处理的数据,BT取值为02;

       ◆ 使用伪随机的16进制字符串填充PS,而且每次操作进行填充的伪随机书都是独立的

重点来了,针对公钥处理的数据,其填充内容为伪随机的16进制字符串,每次操作的填充内容都不一样。这就是为什么每次使用公钥加密数据得到的结果都不一样了。

下面还是以本文开始的公钥加密数据进行说明。

2.2 检查公钥加密的填充数据

第1节中,使用公钥key_pub.pem对数据msg.bin进行了加密,我们使用私钥key.pem解密看看加密前填充的数据。

2.2.1 解密msg.bin.enc1到msg.bin.enc1.dec

$ openssl rsautl -in msg.bin.enc1 -out msg.bin.enc1.dec -inkey key.pem -decrypt -raw

为了显示填充结构,这里用UltraEdit打开解密后的数据:

2.2.2 解密msg.bin.enc2到msg.bin.enc2.dec

$ openssl rsautl -in msg.bin.enc2 -out msg.bin.enc2.dec -inkey key.pem -decrypt -raw

为了显示填充结构,这里用UltraEdit打开解密后的数据:


上面两张图都是对数据msg.bin进行填充后,并且在使用公钥key_pub.pem加密前的内容:

  ◆ 两个绿色部分是指定的“00”填充;

 ◆ 紫色部分指定BT为02, 说明后续使用公钥处理的数据;

 ◆ 灰色部分为PS,其根据BT=02,填充了伪随机数;

 ◆ 橙色部分为原始数据。

可见,两次填充的伪随机数是不一样,这样在使用公钥加密后其结果自然就不一样了。

我看网上有帖子说JAVA下可以通过设置,使每次填充生成同样的内容,但这样似乎不够安全。

我在openssl工具下没有找到相应的针对公钥操作时数据的填充设置选项。

2.3 检查私钥加密的填充数据

在第1节的签名例子中,使用私钥签名时,会先对数据计算SHA256编码,然后对SHA256哈希进行BER编码,再进行填充。

我们可以通过对签名数据使用公钥解密后,看看填充数据的内容:

$ openssl rsautl -in msg.bin.sig1 -out msg.bin.sig1.dec -inkey key_pub.pem -pubin -verify -raw

注意:这里针对openssl rsault 命令使用-raw选项显示原始的数据结构,否则只会显示数据部分,而不会显示填充的内容

按照惯例,为了显示填充结构,这里用UltraEdit打开解密后的签名数据:


上图中是对SHA256数据进行BER编码填充,使用私钥key.pem加密前的内容:

   ◆ 两个绿色部分是指定的“00”填充;

   ◆ 紫色部分指定BT为01, 说明后续是使用私钥处理的数据;

   ◆ 灰色部分为PS,其根据BT=01,填充为全FF的数据;

   ◆ 橙色部分为原始数据(即SHA256数据经过BER编码的内容)。

再来假设下BT为00的情况:

当BT为00时,此时填充的内容PS部分为全00,又由于填充格式中指定了两个“00”的分隔符,如果此时原始数据又是以“00”开始的话,如何划分填充数据和原始数据呢?

显然此时是无法进行区分的,除非你知道原始数据由多长。幸运的是,我们基本上不会采用BT=00的填充方式,所以这种情况几乎不会发生。

3. 一个”openssl rsautl”的bug

最后,以我发现的一个”openssl rsautl”命令的bug来结束本文。

在进行RSA公钥加密私钥解密时,如果加密的原始数据为全00,解密时通过-hexdump选项,无法正确在控制台显示原始数据,问题的复现步骤如下:

生成16字节全0数据:

$ dd if=/dev/zero of=data.bin bs=1 count=32

32+0 records in

32+0 records out

32 bytes (32 B) copied, 0.000227422 s, 141 kB/s

$ hexdump -Cv data.bin

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

00000020

使用公钥key.pem对全0数据data.bin进行加密:

$ openssl rsautl -in data.bin -out data.bin.enc -inkey key_pub.pem -pubin -encrypt

使用私钥解密数据,并直接在控制台显示:

$ openssl rsautl -in data.bin.enc -inkey key.pem -decrypt -hexdump

0020 - <SPACES/NULS>

$ openssl rsautl -in data.bin.enc -inkey key.pem -decrypt -hexdump -raw

0000 - 00 02 49 d0 3d 94 b6 90-8b 4e 40 e7 e4 d1 e2 90  ..I.=....N@.....

0010 - e8 18 29 7f cf 5c c7 4a-bd cc 11 97 81 b3 a7 2b  ..)..\.J.......+

0020 - c3 83 43 60 6d f9 d5 1d-e9 29 ab 51 d1 98 58 49  ..C`m....).Q..XI

0030 - 22 5b ae d2 27 d4 da bd-2b 0d ba 54 7e 04 10 b1  "[..'...+..T~...

0040 - 3b c7 a1 7d 57 02 d8 1c-53 41 91 52 2d ac 0b da  ;..}W...SA.R-...

0050 - 1e 0e 0b 94 b3 90 0d 20-49 2c 94 84 22 87 30 c1  ....... I,..".0.

0060 - 31 36 6e 18 e0 52 5e ec-59 f9 36 47 37 c6 45 1e  16n..R^.Y.6G7.E.

0070 - 24 db dc 9a e4 d8 4e dc-b6 0b b2 57 f4 27 a9 56  $.....N....W.'.V

0080 - 05 11 2d 03 75 75 64 58-87 b8 86 8d 4c 3d d5 f4  ..-.uudX....L=..

0090 - 10 34 9d 24 ab 48 b4 27-58 59 f7 27 3b 9b 39 5a  .4.$.H.'XY.';.9Z

00a0 - b4 ed 2e fb 1f 6e 1f 13-b3 cd 67 78 5f ec f5 63  .....n....gx_..c

00b0 - ae 46 a7 17 87 f7 10 09-32 6d 30 dc 0e 1b 48 2a  .F......2m0...H*

00c0 - 2c 27 09 bc 42 32 38 22-8c 76 c9 cb 8c e9 0d f9  ,'..B28".v......

00d0 - 5e d0 c3 a8 af 8f cd 68-b6 96 3c 94 5c 3c d1      ^......h..<.\<.

0100 - <SPACES/NULS>

这里使用私钥解密后竟然没有原始数据,你说神奇不神奇?我第1次使用不带”-raw”选项操作,发现命令输出没有数据显示时简直大吃了一惊。

还好,如果将解密的数据送到指定文件再显示则没有问题:

$ openssl rsautl -in data.bin.enc -out data.bin.enc.dec -inkey key.pem -decrypt -raw

$ hexdump -Cv data.bin.enc.dec

00000000  00 02 49 d0 3d 94 b6 90  8b 4e 40 e7 e4 d1 e2 90  |..I.=....N@.....|

00000010  e8 18 29 7f cf 5c c7 4a  bd cc 11 97 81 b3 a7 2b  |..)..\.J.......+|

00000020  c3 83 43 60 6d f9 d5 1d  e9 29 ab 51 d1 98 58 49  |..C`m....).Q..XI|

00000030  22 5b ae d2 27 d4 da bd  2b 0d ba 54 7e 04 10 b1  |"[..'...+..T~...|

00000040  3b c7 a1 7d 57 02 d8 1c  53 41 91 52 2d ac 0b da  |;..}W...SA.R-...|

00000050  1e 0e 0b 94 b3 90 0d 20  49 2c 94 84 22 87 30 c1  |....... I,..".0.|

00000060  31 36 6e 18 e0 52 5e ec  59 f9 36 47 37 c6 45 1e  |16n..R^.Y.6G7.E.|

00000070  24 db dc 9a e4 d8 4e dc  b6 0b b2 57 f4 27 a9 56  |$.....N....W.'.V|

00000080  05 11 2d 03 75 75 64 58  87 b8 86 8d 4c 3d d5 f4  |..-.uudX....L=..|

00000090  10 34 9d 24 ab 48 b4 27  58 59 f7 27 3b 9b 39 5a  |.4.$.H.'XY.';.9Z|

000000a0  b4 ed 2e fb 1f 6e 1f 13  b3 cd 67 78 5f ec f5 63  |.....n....gx_..c|

000000b0  ae 46 a7 17 87 f7 10 09  32 6d 30 dc 0e 1b 48 2a  |.F......2m0...H*|

000000c0  2c 27 09 bc 42 32 38 22  8c 76 c9 cb 8c e9 0d f9  |,'..B28".v......|

000000d0  5e d0 c3 a8 af 8f cd 68  b6 96 3c 94 5c 3c d1 00  |^......h..<.\<..|

000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

00000100

看吧,通过后者得到的输出,其全0数据在结果的最后两行都好好的在呢,虚惊一场啊。

---------------------

作者:guyongqiangx

来源:CSDN

原文:https://blog.csdn.net/guyongqiangx/article/details/74930951

版权声明:本文为博主原创文章,转载请附上博文链接!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

  • 1.数据安全 01数据安全的原则1)在网络上"不允许"传输用户隐私数据的"明文"2.)在本地"不允许"保存用户隐私...
    小枫123阅读 447评论 0 1
  • 1 基础 1.1 对称算法 描述:对称加密是指加密过程和解密过程使用相同的密码。主要分:分组加密、序列加密。 原理...
    御浅永夜阅读 2,355评论 1 4
  • 1.数据安全 01数据安全的原则1)在网络上"不允许"传输用户隐私数据的"明文"2.)在本地"不允许"保存用户隐私...
    陈贺阅读 2,150评论 0 2
  • 最近两个月的时间都忙于赶项目进度,都没有时间好好总结,现在项目基本完成了,就剩下等待审核上线了,不过审核真的是相当...
    喵小帅阅读 1,722评论 2 13
  • 都说,大叔这称谓是成功成熟男人的专属,师傅,才是中年屌丝男的正确叫法。本人自称酒国大叔,有往自己脸上贴金之...
    酒国大叔阅读 1,130评论 0 0