RSA签名验签学习笔记

  RSA私钥签名时要基于某个HASH算法,比如MD5或者SHA1等。之前我一直认为签名的过程是:先对明文做HASH计算,然后用私钥直接对HASH值加密。最近才发现不是那么简单,需要对HASH后的数据进行BER编码再加密。

先看一个例子。

公钥模:89 54 E6 61 C1 52 DB ED 07 57 50 04 AD B3 D2 A7 A9 8F E8 D8 20 5B 01 B2 E5 E4 7A 7B EE 80 E3 C0 13 11 D2 F9 AD C3 CC 5F 1D 96 AC B2 AB BE 9C 14 9E 76 31 06 B2 E6 FA 01 52 A7 2E 53 C2 1D 3B 7B 9B 68 05 D2 5E 35 31 98 0E 02 93 E0 D9 0C 38 2D 3D EE 10 E6 87 53 79 DF B2 1E 12 D9 9E EF 89 6D 01 59 0D 13 94 DB 05 B7 09 34 D3 5B AB ED 7C FE 0E BE 87 EE E8 DD 01 39 3A CA 3A A7 17 B8 AA E3

公钥指数:01 00 01

私钥指数:01 FE B1 BA 09 CC E2 54 F7 1E 55 93 3B D2 B8 E4 A6 99 E8 8F FB 28 57 45 FA 00 EF A6 8D 38 62 16 90 30 5A 18 36 65 F9 BA 07 FC 00 56 38 18 74 BB F7 F1 4F 95 01 54 49 9D 6B 4D F2 66 55 13 87 A1 A6 95 74 72 6A D8 3A EA 34 A8 F8 40 5F 27 11 30 4F 96 3A 2E 7B E6 B6 47 3C 3B 4D 24 E8 FA 51 19 59 FB 52 E0 9B D2 24 B3 B5 8A 36 BF 34 20 E9 2A AB 5D 55 9B 60 01 D5 04 81 E8 E7 EC B2 5F 81 41

私钥P:BF 36 08 66 63 74 6A 79 D0 77 64 21 73 6D 1A B9 13 BB 35 13 BE A6 73 84 C8 7D 83 67 BE C2 F5 0C 3A 7F 5F EF 6E 73 E2 BC 31 D2 0C 78 06 D7 38 85 7E F5 06 40 62 A6 1D 53 CC 97 34 30 58 EE E2 05

私钥Q:B7 DD 46 99 58 B2 52 4B 87 FB E1 F1 09 44 AB 9A AD D1 93 90 9C 40 E0 2F 36 63 F4 7F 49 CB 36 E3 2C DA 85 5C 6E CE 41 AC CB 09 6C 27 B6 44 2B D8 26 5F D5 63 DF 2A C8 60 57 3B 23 13 2B 5F 65 C7

私钥DP:A6 EF C4 9B A7 9E DE CA E5 2F 27 33 71 33 C3 0D EC 65 18 2C D9 D9 36 A7 A9 E6 B2 CF E3 A3 10 10 12 0E 5C B2 8C 2B 0E BC 21 7E F2 35 E4 3B 08 74 BC 67 AD 82 8E DD DA 62 EC 0E E2 98 87 3C 60 05

私钥DQ:B6 A0 8B A7 75 7A 6A 53 AB D6 7D 2E 35 CE 87 C5 34 31 9F 29 5C 8A F4 22 F1 1B 87 97 87 6C DA 2F FC 35 71 91 C6 5E 08 CD E1 3E 92 B7 3F 4B A7 61 23 7C BD 30 5E 52 D8 85 19 20 1C 4E C6 1E 13 B1

私钥InvQ:B4 12 D6 05 1C 2C 2B 6F B5 73 99 F3 B7 A7 08 6F A3 E8 2D 6F 33 A6 AE E5 BE 7B 89 86 7F 48 3B DD BC 4A 07 BF A4 A1 BB 96 BD 0E 46 F1 43 FA FB DE A0 1B AB 38 7D 49 59 45 EE 8C F9 3D 89 CF EB AC

明文:11 22 33 44 55

通过调用.NET的RSA签名接口,产生基于MD5的签名后数据:56 E1 5E 29 84 D6 BC FB 87 7F 55 93 B4 E1 F3 75 2C 64 A5 BC 04 3A D7 0A DB 84 AD 8B 9C 4D D8 E6 8A 56 85 7B 2C 5E 50 E5 81 EB DC 40 D8 9A 29 64 54 19 5B F0 2B 77 D3 DB CF A2 17 BF 33 3F 19 19 B0 FF 36 53 D3 C2 36 1D 90 43 27 2C 0F 54 34 54 F7 E8 D2 09 75 E4 F1 A0 8B F5 38 EA 66 D6 53 14 E4 C5 B6 5A C7 74 52 6E 0A 16 C6 9B B7 81 0B 06 61 8A E7 41 BB 97 E6 EE 3E 6A 1C 7A E6 32 18 60

用公钥对上面的数据解密后得到:30 20 30 0C 06 08 2A 86 48 86 F7 0D 02 05 05 00 04 10 28 3D 4F EA 5D DE D5 9C F8 37 D3 04 73 28 F5 AF

这是一段TLV格式的数据,解析后


TAG


名称


长度



30


Sequence组合类型


20

 
 
30


Sequence组合类型


0C

 
   
06


对象标识ObjectID


08


2A 86 48 86 F7 0D 02 05

   
05


空类型


00

 
 
04


字符串类型


10


28 3D 4F EA 5D DE D5 9C F8 37 D3 04 73 28 F5 AF

可以看到28 3D 4F EA 5D DE D5 9C F8 37 D3 04 73 28 F5 AF正好就是明文数据11 22 33 44 55的MD5值。

那么上面这段数据的其它内容表示什么意思呢?

这里使用的编码方法是BER(Basic Encoding Rule),BER的数据都是TLV格式的,每种TAG的定义如下:

0x01:BOOL

0x02:INT,整型

0x04:OCTSTR,字符串类型

0x05:NULL,空类型

0x06:OBJID,对象标识ObjectID(在这里就是对应的HASH算法的OID编码)

0x0A:ENUM

0x30:SEQ,Sequence组合类型

0x31:SETOF

0x40:IPADDR

0x41:COUNTER

0x42:GAUGE

0x43:TIMETICKS

0x44:OPAQUE

也就是说,每次基于不同的HASH算法对不同的数据进行签名时,构造的这一段BER数据的基本格式是固定不变的,只是HASH算法的OID和哈希值会变而已。

下面讲一下HASH算法的OID是怎么编码的。

每个算法的OID都是固定的一串十进制数据,是国际权威组织定的。比如MD5的OID 是 1.2.840.113549.2.5   ,表示为"iso(1) member-body (2) US (840) rsadsi(113549) digestAlgorithm (2) md5 (5)", 所以当解码程序看到这个OID时,就知道是MD5散列.

对OID的编码规则如下:前两部分如果定义为x.y, 那么它们将合成一个字40*x + y, 其余部分单独作为一个字节进行编码。每个字首先被分割为最少数量的没有头零数字的7位数字.这些数字以big-endian格式进行组织,并且一个接一个地组合成字节. 除了编码的最后一个字节外,其他所有字节的最高位(位8)都为1。举例: 30331 = 1 * 128^2 + 108 * 128 + 123   分割成7位数字(0x80)后为{1,108,123}设置最高位后变成{129,236,123}.如果该字只有一个7位数字,那么最高为0。

规则不太好懂,还是以MD5举例

一、将1.2.840.113549.2.5转换成字数组 {42, 840, 113549, 2, 5}(因为前两部分定义为1.2,那么合成一个字40*1+2=42)

二、将每个字分割为带有最高位的7位数字。

42=42,只有一个7位数字,那么最高为0,结果为{0x2A}

840= 6*128^1+72,除最后一个字节外,其他字节的BIT8都置1,结果为{0x86,0x48}

113549=6*128^2+119*128^1+13,除最后一个字节外,其他字节的BIT8都置1,结果为{0x86,0xF7,0x0D}

2=2, 只有一个7位数字,那么最高为0,结果为{0x02}

5=5, 只有一个7位数字,那么最高为0,结果为{0x05}

最终结果为{{0x2A},{0x86,0x48},{0x86,0xF7,0x0D},{0x02},{0x05}}

三、加上TAG和LEN,得到OID编码为 0x06 08 2A 86 48 86 F7 0D 02 05

RSA验签时的步骤:先用公钥解密,解析TLV数据从中得到HASH算法的OID和HASH值,根据OID选择相应的HASH算法对明文进行计算,最后比对HASH值。

常见的HASH算法在用于RSA签名时的BER数据编码格式为:


MD2


1.2.840.113549.2.2


30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 || H.


MD4


1.2.840.113549.2.4


30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 04 05 00 04 10 || H.


MD5


1.2.840.113549.2.5


30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10 || H


SHA1


1.3.14.3.2.26


30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H


SHA224


2.16.840.1.101.3.4.2.4

不确定是否这个OID


30 2D 30 0d 06 09 60 86 48 01 65 03 04 02 04 05 00 04 1C || H


SHA256


2.16.840.1.101.3.4.2.1


30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H


SHA384


2.16.840.1.101.3.4.2.2


30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H


SHA512


2.16.840.1.101.3.4.2.3


30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H


SM3


1.2.156.197.1.504

不确定是否这个OID


30 30 30 0c 06 08 2a 81 1C 81 45 01 83 78 05 00 04 20 || H.

时间: 2024-11-05 22:26:02

RSA签名验签学习笔记的相关文章

RSA签名验签

import android.util.Base64; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * Author:JsonLu * DateTime:

JAVA 实现 基于RSA算法的签名验签

基本步骤 签名方: 1用sha1算出原文的摘要 2用私钥对摘要进行加密 3对密文进行BASE64编码 验证方: 1对密文进行BASE64解码 2用公钥对解码后的密文解密 3用sha1对原文计算摘要并和解密后的明文比对 上干货 //参数字符串         String userId="2312sd";         String orderId="232djfj";         String price="12312";         

.net core RSA 分段加密解密,签名验签(对接java)

参考地址: https://www.cnblogs.com/stulzq/p/7757915.html https://www.cnblogs.com/stulzq/p/8260873.html https://github.com/stulzq/RSAExtensions(XC.RSAUtil) https://www.cnblogs.com/stulzq/p/12053976.html https://github.com/stulzq/RSAExtensions (RSAExtension

eos中签名验签流程和eosjs中的加解密原理

关键词:eos 签名 验签 ecc dsa 加密 解密 eosjs aes 本文主要探讨两方面 1.eosjs中用密钥对进行加解密功能 2.eos中密钥对生成,签名和验签过程(私钥签名 公钥验签) 常用的加密算法 对称性加密算法 对称式加密就是加密和解密使用同一个密钥,信息接收双方都需事先知道密匙和加解密算法,之后便是对数据进行加解密了.对称加密算法用来对敏感数据等信息进行加密. 对称性加密算法有:AES.DES.3DES DES(Data EncryptionStandard):数据加密标准,

非对称加密解密与签名验签的关系

首先看一下各自的定义: 加密:发送方利用接收方的公钥对要发送的明文进行加密. 解密:接受方利用自己的私钥进行解密. 签名:发送方用一个哈希函数从报文文本中生成报文摘要,然后用自己的私人密钥对这个摘要进行加密,得到的就是这个报文对应的数字签名.通常来说,发送方会把数字签名和报文原文一并发送给接受者. 验签:接收方得到原始报文和数字签名后,用同一个哈希函数从报文中生成摘要A,另外,用发送方提供的公钥对数字签名进行解密,得到摘要B,对比A和B是否相同,就可以得知报文有没有被篡改过. 两者的目的不同,加

RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密

原文:RSACryptoServiceProvider加密解密签名验签和DESCryptoServiceProvider加解密 C#在using System.Security.Cryptography下有 DESCryptoServiceProvider RSACryptoServiceProvider  DESCryptoServiceProvider 是用于对称加密 RSACryptoServiceProvider是用于非对称加密  对称加密的意思:有一个密钥 相当于加密算法,加密用它来加

openresty中使用私钥/公钥进行加密/解密/签名/验签。

对于公钥私钥的提取,详细请看http://www.cnblogs.com/dreamer-One/p/5621134.html另外付在线加解密工具链接:http://tool.chacuo.net/cryptrsaprikey--公钥local RSA_PUBLIC_KEY = [[ -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAJ9YqFCTlhnmTYNCezMfy7yb7xwAzRinXup1Zl51517rhJq8W0wVwNt+ mcKwRzisA1S

RSA加解密&RSA加验签

开发语言与私钥证书的关系如下: 开发语言 私钥格式 证书格式 JAVA .key.p8 .crt PHP .key.pem .cert.pem .NET .key.der .crt 其它 .key.pem .cert.pem 我们是java语言,工程property配置:#商户私钥 PKCS#8标准的私钥 90000002.mer.prikey.path=cert/90000002.key.p8#平台公钥 X.509证书 plat.cert.path=cert/umpay.cert.crt RS

加解密/签名验签

一.我加密.签名的过程 1,生成18位随机密钥:rand 067870-544583-448433: 2,使用对方的公钥证书(cer文件),并使用“RSA”算法,对随机密钥的字节数组加密,得到一个字节数组,将其转化为小写的十六进制字符串:secretKey 07ed7542951980385e32c149039255aabf8009e1e98a9432db19755e45e07361d318b98393d431cad4f656df7bc254548bacc92c53aa9566fd9ca1105