RSA密钥格式解析

原文:https://www.jianshu.com/p/c93a993f8997

一、前言

在开发过程中,我们常常遇到用RSA进行加密、解密、签名及验签处理,而在进行这些处理的时候,必须首先到导入我们的密钥(公钥或私钥),而我们拿到的密钥有各种形式,例如:pem、der、cer、Pfx、p12、p7b等等。这里我们常常会有很多疑问,我们的处理代码需要那种格式的密钥?这些不同格式的密钥之间如何相互转化?在格式转化中,往往有牵扯到各种概念,象x509、PKCS#1、PKCS#7、PKCS#8、PKCS12,它们又是什么意思呢?接下来,这篇文章会为你一一梳理这些概念。

二、从分析一个RSA公钥开始

2.1、RSA密钥组成

关于RSA算法的原理这里就不做解释了,这边有一篇阮一峰的文章解释的很清楚,有兴趣的朋友可以去了解一下。RSA密码由三个整数组成,我们分别称之为n、e、d

(n、d):私钥,这个我们要私密保存。
(n、e):公钥,可以对外公布。
n:模数(Modulus),私钥和公钥都包含有这个数。
e:公钥指数(publicExponent),一般是固定值65537。
d:私钥指数(privateExponent)。

2.2、使用OpenSSL生成一个RSA公钥

使用OpenSSL命名生成一个RSA公钥非常简单,只需要两个命令。

  1. 生成一个RSA密钥
openssl genrsa -out private_pkcs1.pem 2048
  1. 从生成的RSA密钥中提取RSA公钥
openssl rsa -in private_pkcs1.pem -out public_pkcs1.pem -pubout -RSAPublicKey_out

我们得到了一个PKCS#1形式、PEM格式文件的RSA公钥:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAnLdoA3ba57YHBAenYbLGTcdC48VVvVVDXV6N/W+1FztBRjvNPV1D
MOcIJBrveTlgKug2PCVynaIttaNql6p/+Bm4G41kyZYy7RSaUCaJ3ryjcXsKfClt
nG9vCwbIN+bVchxRzj739zIA1tBHn9v22PhFcEfsSAy2G2EwM4bQ38n2UrMse9wb
LUGT0kzyquwPQs7vriU+1XBkrdssoAqbwgW5yUqxDosYB5h7D1YTW0qKkJ6PPNnL
XbMv2Meyjxq1sbWoF/m8uboaKklqal1ep5UqTp9OFNOaTrVyXY4Gkt7wq3OoNvk9
2cJ1fHz9wnriGo+oNut9gQr1WVjOzRkAwwIDAQAB
-----END RSA PUBLIC KEY-----

下面我们节开始分析这串数据,为了方便,我们这串数据成为 数据2-1

2.3、RSA公钥解析

拿到 数据2-1 我们可以先提几个问题:

  1. 这段数据中包含了哪些信息?
  2. 什么叫做PKCS#1形式?
  3. 什么叫做PEM格式?
  4. 如何从这段数据中提取n、e的值?

2.3.1、什么叫做PEM格式?

我们可以通过OpenSSL命令,导出一个DER格式的公钥

openssl rsa -in private_pkcs1.pem -out public_pkcs1.der -pubout -RSAPublicKey_out -outform DER

public_pkcs1.der是个二进制文件,我们用二级制查看器查看:

public_pkcs1.pem 实际与 public_pkcs1.der 包含了完全相同的信息。回顾一下 数据2-1,我们发现这个数据有三部分:“-----BEGIN RSA PUBLIC KEY-----”、中间的数据、“-----END RSA PUBLIC KEY-----”。下面我们把 数据2-1 中间的数据用base解码:

可以看到,解码后和 public_pkcs1.der 里面的数据完全相同!

实际上,PEM就是把DER格式的数据用base64编码后,然后再在头尾加上一段“-----”开始的标记而已。

2.3.2、ASN.1

上一节我们提到,DER格式的密钥是二进制的数据,那么这段二进制的数据还有没有结构?通过查阅 RFC 8017,我们得到了一个PKCS#1形式的RSA公钥的定义:

RSAPublicKey ::= SEQUENCE {
   modulus           INTEGER,  -- n
   publicExponent    INTEGER   -- e
}

可以看到,PKCS#1形式的RSA公钥定义很简单,只包含n、e值。那这个定义如何帮助我们进一步解析DER格式公钥的二进制数据呢?实际上,上面的定义用的是ASN.1抽象语法标记(Abstract Syntax Notation One),ASN.1用来描述一段二级制数据的结构信息,就像我们用XML来描述文本文件的结构信息一样。我们不能把n、e两个值直接拼接在一起形成二进制公钥,因为这样做公钥的使用者在解析这段公钥的时候就会懵逼。这是什么类型的二级制数据?如果是是一个公钥,那么这个公钥是长度是多少?那段数据是n值,那一段是e值?所以实际上,DER格式公钥除了包含n、e信息以外,还包含了一些结构信息。这些信息我们都是根据上面的ASN.1定义的结构来进行编码和解析。同样的ASN.1定义,可以有多种编码方式:基本编码规则(BER)、可辨别编码规则(DER),这两种编码采取的是同样的规则,只不过BER编码结果不唯一,而DER对BER的规则加了约束使得结果唯一。BER编码的基本原理就是TLV(Type、Length、Value),一段二级制数据,开头几个字节指定了接下来的数据时什么类型的,随后几个字节给出Value部分的长度。然后Value部分里面又可以嵌套TLV,就这样编码下去...

我们的public_pkcs1.der就是采用可辨别编码规则(DER)编码方式。 下面就是我把der里面的二级制数据按照TLV进行格式化一下:

30 82 01 0A 
    02 82 01 01 
        00 9C B7 68 03 76 DA E7 B6 07 04 07 A7 61 B2 C6 4D C7 42 E3 C5 55 BD 55 43 5D 5E 8D FD 6F B5 17 3B 41 46 3B CD 3D 5D 43 30 E7 08 24 1A EF 79 39 60 2A E8 36 3C 25 72 9D A2 2D B5 A3 6A 97 AA 7F F8 19 B8 1B 8D 64 C9 96 32 ED 14 9A 50 26 89 DE BC A3 71 7B 0A 7C 29 6D 9C 6F 6F 0B 06 C8 37 E6 D5 72 1C 51 CE 3E F7 F7 32 00 D6 D0 47 9F DB F6 D8 F8 45 70 47 EC 48 0C B6 1B 61 30 33 86 D0 DF C9 F6 52 B3 2C 7B DC 1B 2D 41 93 D2 4C F2 AA EC 0F 42 CE EF AE 25 3E D5 70 64 AD DB 2C A0 0A 9B C2 05 B9 C9 4A B1 0E 8B 18 07 98 7B 0F 56 13 5B 4A 8A 90 9E 8F 3C D9 CB 5D B3 2F D8 C7 B2 8F 1A B5 B1 B5 A8 17 F9 BC B9 BA 1A 2A 49 6A 6A 5D 5E A7 95 2A 4E 9F 4E 14 D3 9A 4E B5 72 5D 8E 06 92 DE F0 AB 73 A8 36 F9 3D D9 C2 75 7C 7C FD C2 7A E2 1A 8F A8 36 EB 7D 81 0A F5 59 58 CE CD 19 00 C3 

    02 03 
        01 00 01 

然后我们用OpenSSL查看我们密钥的n、e、d值

openssl rsa -in private_pkcs1.pem -text -noout

两相比对,我们就可以看出public_pkcs1.der文件的结构。

三、私钥解析

3.1、PKCS#1形式的私钥结构

RFC 2347中,我们可以得到RSA私钥的ASN.1定义,如下:

RSAPrivateKey ::= SEQUENCE {
 version Version,
 modulus INTEGER, -- n
 publicExponent INTEGER, -- e
 privateExponent INTEGER, -- d
 prime1 INTEGER, -- p
 prime2 INTEGER, -- q
 exponent1 INTEGER, -- d mod (p-1)
 exponent2 INTEGER, -- d mod (q-1)
 coefficient INTEGER -- (inverse of q) mod p 
}

里面包含了n、e、d值,其他参数都可以通过n、e、d计算得到,这里应该是为了方便用户使用,减少因用户计算方式不正确而导致一些操作的失败,故而直接把各种形式的参数定义在私钥里面。

我们把该私钥的二进制数据格式化,得到如下所示:

30 82 04 A2 
    02 01 
        00 

    02 82 01 01 
        00 9C B7 68 03 76 DA E7 B6 07 04 07 A7 61 B2 C6 4D C7 42 E3 C5 55 BD 55 43 5D 5E 8D FD 6F B5 17 3B 41 46 3B CD 3D 5D 43 30 E7 08 24 1A EF 79 39 60 2A E8 36 3C 25 72 9D A2 2D B5 A3 6A 97 AA 7F F8 19 B8 1B 8D 64 C9 96 32 ED 14 9A 50 26 89 DE BC A3 71 7B 0A 7C 29 6D 9C 6F 6F 0B 06 C8 37 E6 D5 72 1C 51 CE 3E F7 F7 32 00 D6 D0 47 9F DB F6 D8 F8 45 70 47 EC 48 0C B6 1B 61 30 33 86 D0 DF C9 F6 52 B3 2C 7B DC 1B 2D 41 93 D2 4C F2 AA EC 0F 42 CE EF AE 25 3E D5 70 64 AD DB 2C A0 0A 9B C2 05 B9 C9 4A B1 0E 8B 18 07 98 7B 0F 56 13 5B 4A 8A 90 9E 8F 3C D9 CB 5D B3 2F D8 C7 B2 8F 1A B5 B1 B5 A8 17 F9 BC B9 BA 1A 2A 49 6A 6A 5D 5E A7 95 2A 4E 9F 4E 14 D3 9A 4E B5 72 5D 8E 06 92 DE F0 AB 73 A8 36 F9 3D D9 C2 75 7C 7C FD C2 7A E2 1A 8F A8 36 EB 7D 81 0A F5 59 58 CE CD 19 00 C3 

    02 03 
        01 00 01 

    02 82 01 00 
        31 56 2C 10 AB 22 4F 40 27 05 45 C3 94 26 4B F7 C0 7B 76 69 71 8C A1 83 0B A9 F0 D9 90 89 5A 3E F5 55 BF 0D E5 FB AE 63 7E D8 39 45 A1 8E 70 59 AE 28 5C AA A2 BF 6A 90 DC 03 0A E7 4B C8 09 71 79 E7 54 05 37 6D 9F 33 79 1F BB 54 F0 4D 07 2A 2B EA 55 E9 FF 1C AB BD 4B F7 91 69 19 2F 40 24 82 40 18 20 EE 01 F2 78 73 7B 2D 26 DF 54 C8 69 95 FF 86 51 9E 39 30 87 44 27 5C 9D 5C 1B F5 D7 88 D4 9D E0 AD 0F 3C B0 A2 EC C8 A6 ED 60 CB DE 44 F9 B7 73 D8 29 4F 38 8C 24 91 29 56 B8 E0 94 0A E2 22 27 5B A4 51 90 BE A9 0E 66 EB A1 5C 68 93 D4 25 64 E3 97 B0 56 E1 9F 07 B6 AD 3F 5E 92 66 BB CC AC 4E 80 46 52 D7 3A 57 0D 52 E5 E9 49 37 62 F7 2E C0 0D C3 92 A6 A6 F6 0F D7 9F 1B 98 3E 20 8E F5 67 ED 19 A9 70 F0 82 F4 73 05 B8 30 01 5E 55 01 64 4E 29 BE 84 0A 38 BD EB F2 27 C1 

    02 81 81 
        00 D0 8E EF 5F F7 98 86 28 CC 96 71 53 0A 4D BB 84 02 68 0A E7 19 C6 82 7C 7F E4 F4 44 FB EF 6C 39 33 C1 33 F4 1A 28 72 A6 F3 32 09 6A 3A CD 25 3C A0 C1 28 96 87 2D 52 97 51 D5 9D 63 3A 74 73 D6 13 7B 60 A7 38 F3 84 D3 9D 2B 6E A4 71 DE 65 7F 5A 8F 0D 46 9F 2B F5 B0 64 83 F8 95 56 84 7B BF 04 DF 18 FD 0D DB 2A 55 15 2D 71 54 52 AC BD 19 45 2E 0B 84 AB BD 86 69 AE C0 BC 45 4C 31 4B CD 

    02 81 81 
        00 C0 5D 8A 29 17 C5 32 BF 92 B3 94 F1 B1 79 90 3E CE F1 B5 42 BB 4C F4 22 1B CF FB AD 46 92 9B AB 9E 60 73 12 EB 53 84 AC D5 58 7B F7 F7 56 63 FD 3B F1 18 8D 4B 67 BB 98 CB 4A D4 62 B8 5A 08 A0 38 E6 F4 74 7C 56 33 2C 99 38 A5 AB F0 83 C9 06 78 98 18 B9 F8 81 C9 5C 6F E1 82 A1 A1 D5 08 D6 BE 20 90 CA D6 E5 79 F9 DF E1 A7 A2 B0 1E D5 6F F9 3C 68 96 24 29 06 16 22 DA 2A 48 86 F5 8E CF 

    02 81 80 
        57 C2 EE 24 1A 12 8A D1 FC 55 8A 56 81 4D 78 8C F2 5E 49 C8 39 E6 78 DE 5F 0B 3F 67 10 05 0E 2B 7C 05 DF 10 E7 39 02 16 12 DC 89 6D B4 54 C3 48 A1 F4 E6 59 81 84 A6 EE 9A 37 23 C5 AF C1 75 45 2E 69 8A A0 93 AC 95 C6 5E AA FA 22 24 F0 8B 11 6E 50 28 2C 01 AB 03 F6 38 35 F8 93 0F 17 2C E3 92 EF 36 9A B6 0B F5 E2 5B C9 05 99 90 38 B4 52 3F F4 42 50 8F DC 6F 05 65 CE 20 EB A0 46 56 39 

    02 81 80 
        02 70 6D 33 0E 31 1A EE A0 EE 94 01 E8 8D 31 0E 0A D3 B7 C7 AB D6 52 F6 27 C2 20 5F D7 18 3E CF 13 48 07 CD 82 9C 61 7F 4B 89 3E B1 2B 3A B6 33 DC D1 B6 CC FB DA C9 DF 2B 1C BC CA AF A9 BC 98 43 80 72 33 13 EC 87 E3 95 E1 C9 00 00 21 BB A7 D0 59 A5 5E 9E 4F 0E FD 94 11 98 F5 71 B6 E0 D0 D0 42 5B 73 A6 FB EB EB 06 32 B7 4C 71 CD 42 49 94 30 76 E7 08 78 58 B2 69 28 B9 06 88 67 8E B3 

    02 81 80 
        0F 6D 4D 97 25 5A BC 9D F9 B4 4D FF AF 56 09 44 1A D6 CE 8D 27 AA B3 F8 D1 D3 E3 3B B2 77 D4 5A 45 6F DA 62 C3 1D B4 C9 AE 19 84 72 A4 91 A5 F1 5B F3 D6 BC 71 E9 FA 99 BD D5 03 E6 65 78 25 AE CD A8 5B 77 1F 15 60 AC 5F AA 7F C0 29 91 A1 9C 44 91 8B 82 9C 02 4C 4E 73 9A 6D 90 31 44 28 BA ED 5D 7D 1B 6E 4D E2 EB 66 C9 0B 49 FE A5 E7 7E 63 57 D9 BC 67 43 13 1D 26 CF 92 FD 17 74 77 5B 

我们通过OpenSSL来查看一下密钥的各参数情况:

openssl rsa -in private_pkcs1.pem -text -noout

Private-Key: (2048 bit)
modulus:
    00:9c:b7:68:03:76:da:e7:b6:07:04:07:a7:61:b2:
    c6:4d:c7:42:e3:c5:55:bd:55:43:5d:5e:8d:fd:6f:
    b5:17:3b:41:46:3b:cd:3d:5d:43:30:e7:08:24:1a:
    ef:79:39:60:2a:e8:36:3c:25:72:9d:a2:2d:b5:a3:
    6a:97:aa:7f:f8:19:b8:1b:8d:64:c9:96:32:ed:14:
    9a:50:26:89:de:bc:a3:71:7b:0a:7c:29:6d:9c:6f:
    6f:0b:06:c8:37:e6:d5:72:1c:51:ce:3e:f7:f7:32:
    00:d6:d0:47:9f:db:f6:d8:f8:45:70:47:ec:48:0c:
    b6:1b:61:30:33:86:d0:df:c9:f6:52:b3:2c:7b:dc:
    1b:2d:41:93:d2:4c:f2:aa:ec:0f:42:ce:ef:ae:25:
    3e:d5:70:64:ad:db:2c:a0:0a:9b:c2:05:b9:c9:4a:
    b1:0e:8b:18:07:98:7b:0f:56:13:5b:4a:8a:90:9e:
    8f:3c:d9:cb:5d:b3:2f:d8:c7:b2:8f:1a:b5:b1:b5:
    a8:17:f9:bc:b9:ba:1a:2a:49:6a:6a:5d:5e:a7:95:
    2a:4e:9f:4e:14:d3:9a:4e:b5:72:5d:8e:06:92:de:
    f0:ab:73:a8:36:f9:3d:d9:c2:75:7c:7c:fd:c2:7a:
    e2:1a:8f:a8:36:eb:7d:81:0a:f5:59:58:ce:cd:19:
    00:c3
publicExponent: 65537 (0x10001)
privateExponent:
    31:56:2c:10:ab:22:4f:40:27:05:45:c3:94:26:4b:
    f7:c0:7b:76:69:71:8c:a1:83:0b:a9:f0:d9:90:89:
    5a:3e:f5:55:bf:0d:e5:fb:ae:63:7e:d8:39:45:a1:
    8e:70:59:ae:28:5c:aa:a2:bf:6a:90:dc:03:0a:e7:
    4b:c8:09:71:79:e7:54:05:37:6d:9f:33:79:1f:bb:
    54:f0:4d:07:2a:2b:ea:55:e9:ff:1c:ab:bd:4b:f7:
    91:69:19:2f:40:24:82:40:18:20:ee:01:f2:78:73:
    7b:2d:26:df:54:c8:69:95:ff:86:51:9e:39:30:87:
    44:27:5c:9d:5c:1b:f5:d7:88:d4:9d:e0:ad:0f:3c:
    b0:a2:ec:c8:a6:ed:60:cb:de:44:f9:b7:73:d8:29:
    4f:38:8c:24:91:29:56:b8:e0:94:0a:e2:22:27:5b:
    a4:51:90:be:a9:0e:66:eb:a1:5c:68:93:d4:25:64:
    e3:97:b0:56:e1:9f:07:b6:ad:3f:5e:92:66:bb:cc:
    ac:4e:80:46:52:d7:3a:57:0d:52:e5:e9:49:37:62:
    f7:2e:c0:0d:c3:92:a6:a6:f6:0f:d7:9f:1b:98:3e:
    20:8e:f5:67:ed:19:a9:70:f0:82:f4:73:05:b8:30:
    01:5e:55:01:64:4e:29:be:84:0a:38:bd:eb:f2:27:
    c1
prime1:
    00:d0:8e:ef:5f:f7:98:86:28:cc:96:71:53:0a:4d:
    bb:84:02:68:0a:e7:19:c6:82:7c:7f:e4:f4:44:fb:
    ef:6c:39:33:c1:33:f4:1a:28:72:a6:f3:32:09:6a:
    3a:cd:25:3c:a0:c1:28:96:87:2d:52:97:51:d5:9d:
    63:3a:74:73:d6:13:7b:60:a7:38:f3:84:d3:9d:2b:
    6e:a4:71:de:65:7f:5a:8f:0d:46:9f:2b:f5:b0:64:
    83:f8:95:56:84:7b:bf:04:df:18:fd:0d:db:2a:55:
    15:2d:71:54:52:ac:bd:19:45:2e:0b:84:ab:bd:86:
    69:ae:c0:bc:45:4c:31:4b:cd
prime2:
    00:c0:5d:8a:29:17:c5:32:bf:92:b3:94:f1:b1:79:
    90:3e:ce:f1:b5:42:bb:4c:f4:22:1b:cf:fb:ad:46:
    92:9b:ab:9e:60:73:12:eb:53:84:ac:d5:58:7b:f7:
    f7:56:63:fd:3b:f1:18:8d:4b:67:bb:98:cb:4a:d4:
    62:b8:5a:08:a0:38:e6:f4:74:7c:56:33:2c:99:38:
    a5:ab:f0:83:c9:06:78:98:18:b9:f8:81:c9:5c:6f:
    e1:82:a1:a1:d5:08:d6:be:20:90:ca:d6:e5:79:f9:
    df:e1:a7:a2:b0:1e:d5:6f:f9:3c:68:96:24:29:06:
    16:22:da:2a:48:86:f5:8e:cf
exponent1:
    57:c2:ee:24:1a:12:8a:d1:fc:55:8a:56:81:4d:78:
    8c:f2:5e:49:c8:39:e6:78:de:5f:0b:3f:67:10:05:
    0e:2b:7c:05:df:10:e7:39:02:16:12:dc:89:6d:b4:
    54:c3:48:a1:f4:e6:59:81:84:a6:ee:9a:37:23:c5:
    af:c1:75:45:2e:69:8a:a0:93:ac:95:c6:5e:aa:fa:
    22:24:f0:8b:11:6e:50:28:2c:01:ab:03:f6:38:35:
    f8:93:0f:17:2c:e3:92:ef:36:9a:b6:0b:f5:e2:5b:
    c9:05:99:90:38:b4:52:3f:f4:42:50:8f:dc:6f:05:
    65:ce:20:eb:a0:46:56:39
exponent2:
    02:70:6d:33:0e:31:1a:ee:a0:ee:94:01:e8:8d:31:
    0e:0a:d3:b7:c7:ab:d6:52:f6:27:c2:20:5f:d7:18:
    3e:cf:13:48:07:cd:82:9c:61:7f:4b:89:3e:b1:2b:
    3a:b6:33:dc:d1:b6:cc:fb:da:c9:df:2b:1c:bc:ca:
    af:a9:bc:98:43:80:72:33:13:ec:87:e3:95:e1:c9:
    00:00:21:bb:a7:d0:59:a5:5e:9e:4f:0e:fd:94:11:
    98:f5:71:b6:e0:d0:d0:42:5b:73:a6:fb:eb:eb:06:
    32:b7:4c:71:cd:42:49:94:30:76:e7:08:78:58:b2:
    69:28:b9:06:88:67:8e:b3
coefficient:
    0f:6d:4d:97:25:5a:bc:9d:f9:b4:4d:ff:af:56:09:
    44:1a:d6:ce:8d:27:aa:b3:f8:d1:d3:e3:3b:b2:77:
    d4:5a:45:6f:da:62:c3:1d:b4:c9:ae:19:84:72:a4:
    91:a5:f1:5b:f3:d6:bc:71:e9:fa:99:bd:d5:03:e6:
    65:78:25:ae:cd:a8:5b:77:1f:15:60:ac:5f:aa:7f:
    c0:29:91:a1:9c:44:91:8b:82:9c:02:4c:4e:73:9a:
    6d:90:31:44:28:ba:ed:5d:7d:1b:6e:4d:e2:eb:66:
    c9:0b:49:fe:a5:e7:7e:63:57:d9:bc:67:43:13:1d:
    26:cf:92:fd:17:74:77:5b

两相比对,结构一目了然。

3.2、PKCS#8形式的私钥结构

前面我们介绍了PKCS#1形式的公钥和私钥,那么什么是PKCS#1形式?什么又是PKCS#8形式呢?实际上,PKCS#1形式的密钥专指RSA的密钥,如果一个ECC的密钥就无法用PKCS#1形式来表达。那么有没有一个通过的机构既可以表示RSA密钥,又可以表示ECC的密钥呢?有,这个就是PKCS#8形式的密钥。

RFC 5208中,我们可以找到PKCS#8密钥的ASN.1定义,如下:

PrivateKeyInfo ::= SEQUENCE {
   version Version,
   privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
   privateKey PrivateKey,
   attributes [0] Attributes OPTIONAL 
}

二进制结构如下:

30 82 04 BC 
    02 01 00 

    30 0D 
        06 09 
            2A 86 48 86 F7 0D 01 01 01 

    05 00

    04 82 04 A6 
        30 82 04 A2 
            02 01 00 

            02 82 01 01 
                00 9C B7 68 03 76 DA E7 B6 07 04 07 A7 61 B2 C6 4D C7 42 E3 C5 55 BD 55 43 5D 5E 8D FD 6F B5 17 3B 41 46 3B CD 3D 5D 43 30 E7 08 24 1A EF 79 39 60 2A E8 36 3C 25 72 9D A2 2D B5 A3 6A 97 AA 7F F8 19 B8 1B 8D 64 C9 96 32 ED 14 9A 50 26 89 DE BC A3 71 7B 0A 7C 29 6D 9C 6F 6F 0B 06 C8 37 E6 D5 72 1C 51 CE 3E F7 F7 32 00 D6 D0 47 9F DB F6 D8 F8 45 70 47 EC 48 0C B6 1B 61 30 33 86 D0 DF C9 F6 52 B3 2C 7B DC 1B 2D 41 93 D2 4C F2 AA EC 0F 42 CE EF AE 25 3E D5 70 64 AD DB 2C A0 0A 9B C2 05 B9 C9 4A B1 0E 8B 18 07 98 7B 0F 56 13 5B 4A 8A 90 9E 8F 3C D9 CB 5D B3 2F D8 C7 B2 8F 1A B5 B1 B5 A8 17 F9 BC B9 BA 1A 2A 49 6A 6A 5D 5E A7 95 2A 4E 9F 4E 14 D3 9A 4E B5 72 5D 8E 06 92 DE F0 AB 73 A8 36 F9 3D D9 C2 75 7C 7C FD C2 7A E2 1A 8F A8 36 EB 7D 81 0A F5 59 58 CE CD 19 00 C3 

            02 03 
                01 00 01 

            02 82 01 00 
                31 56 2C 10 AB 22 4F 40 27 05 45 C3 94 26 4B F7 C0 7B 76 69 71 8C A1 83 0B A9 F0 D9 90 89 5A 3E F5 55 BF 0D E5 FB AE 63 7E D8 39 45 A1 8E 70 59 AE 28 5C AA A2 BF 6A 90 DC 03 0A E7 4B C8 09 71 79 E7 54 05 37 6D 9F 33 79 1F BB 54 F0 4D 07 2A 2B EA 55 E9 FF 1C AB BD 4B F7 91 69 19 2F 40 24 82 40 18 20 EE 01 F2 78 73 7B 2D 26 DF 54 C8 69 95 FF 86 51 9E 39 30 87 44 27 5C 9D 5C 1B F5 D7 88 D4 9D E0 AD 0F 3C B0 A2 EC C8 A6 ED 60 CB DE 44 F9 B7 73 D8 29 4F 38 8C 24 91 29 56 B8 E0 94 0A E2 22 27 5B A4 51 90 BE A9 0E 66 EB A1 5C 68 93 D4 25 64 E3 97 B0 56 E1 9F 07 B6 AD 3F 5E 92 66 BB CC AC 4E 80 46 52 D7 3A 57 0D 52 E5 E9 49 37 62 F7 2E C0 0D C3 92 A6 A6 F6 0F D7 9F 1B 98 3E 20 8E F5 67 ED 19 A9 70 F0 82 F4 73 05 B8 30 01 5E 55 01 64 4E 29 BE 84 0A 38 BD EB F2 27 C1 

            02 81 81 
                00 D0 8E EF 5F F7 98 86 28 CC 96 71 53 0A 4D BB 84 02 68 0A E7 19 C6 82 7C 7F E4 F4 44 FB EF 6C 39 33 C1 33 F4 1A 28 72 A6 F3 32 09 6A 3A CD 25 3C A0 C1 28 96 87 2D 52 97 51 D5 9D 63 3A 74 73 D6 13 7B 60 A7 38 F3 84 D3 9D 2B 6E A4 71 DE 65 7F 5A 8F 0D 46 9F 2B F5 B0 64 83 F8 95 56 84 7B BF 04 DF 18 FD 0D DB 2A 55 15 2D 71 54 52 AC BD 19 45 2E 0B 84 AB BD 86 69 AE C0 BC 45 4C 31 4B CD 

            02 81 81 
                00 C0 5D 8A 29 17 C5 32 BF 92 B3 94 F1 B1 79 90 3E CE F1 B5 42 BB 4C F4 22 1B CF FB AD 46 92 9B AB 9E 60 73 12 EB 53 84 AC D5 58 7B F7 F7 56 63 FD 3B F1 18 8D 4B 67 BB 98 CB 4A D4 62 B8 5A 08 A0 38 E6 F4 74 7C 56 33 2C 99 38 A5 AB F0 83 C9 06 78 98 18 B9 F8 81 C9 5C 6F E1 82 A1 A1 D5 08 D6 BE 20 90 CA D6 E5 79 F9 DF E1 A7 A2 B0 1E D5 6F F9 3C 68 96 24 29 06 16 22 DA 2A 48 86 F5 8E CF 

            02 81 80 
                57 C2 EE 24 1A 12 8A D1 FC 55 8A 56 81 4D 78 8C F2 5E 49 C8 39 E6 78 DE 5F 0B 3F 67 10 05 0E 2B 7C 05 DF 10 E7 39 02 16 12 DC 89 6D B4 54 C3 48 A1 F4 E6 59 81 84 A6 EE 9A 37 23 C5 AF C1 75 45 2E 69 8A A0 93 AC 95 C6 5E AA FA 22 24 F0 8B 11 6E 50 28 2C 01 AB 03 F6 38 35 F8 93 0F 17 2C E3 92 EF 36 9A B6 0B F5 E2 5B C9 05 99 90 38 B4 52 3F F4 42 50 8F DC 6F 05 65 CE 20 EB A0 46 56 39 

            02 81 80 
                02 70 6D 33 0E 31 1A EE A0 EE 94 01 E8 8D 31 0E 0A D3 B7 C7 AB D6 52 F6 27 C2 20 5F D7 18 3E CF 13 48 07 CD 82 9C 61 7F 4B 89 3E B1 2B 3A B6 33 DC D1 B6 CC FB DA C9 DF 2B 1C BC CA AF A9 BC 98 43 80 72 33 13 EC 87 E3 95 E1 C9 00 00 21 BB A7 D0 59 A5 5E 9E 4F 0E FD 94 11 98 F5 71 B6 E0 D0 D0 42 5B 73 A6 FB EB EB 06 32 B7 4C 71 CD 42 49 94 30 76 E7 08 78 58 B2 69 28 B9 06 88 67 8E B3 

            02 81 80 
                0F 6D 4D 97 25 5A BC 9D F9 B4 4D FF AF 56 09 44 1A D6 CE 8D 27 AA B3 F8 D1 D3 E3 3B B2 77 D4 5A 45 6F DA 62 C3 1D B4 C9 AE 19 84 72 A4 91 A5 F1 5B F3 D6 BC 71 E9 FA 99 BD D5 03 E6 65 78 25 AE CD A8 5B 77 1F 15 60 AC 5F AA 7F C0 29 91 A1 9C 44 91 8B 82 9C 02 4C 4E 73 9A 6D 90 31 44 28 BA ED 5D 7D 1B 6E 4D E2 EB 66 C9 0B 49 FE A5 E7 7E 63 57 D9 BC 67 43 13 1D 26 CF 92 FD 17 74 77 5B 

四、证书

4.1、证书的类型

证书有三种类型:X.509证书、PKCS#7证书、PKCS#12证书

4.2、X.509证书

X.509只包含公钥,没有私钥,这种证书一般公开发布,可用于放在客服端使用,用于加密、验签。它的ASN.1定义如下:

Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING  
}

TBSCertificate  ::=  SEQUENCE  {
    version         [0]  EXPLICIT Version DEFAULT v1,
    serialNumber         CertificateSerialNumber,
    signature            AlgorithmIdentifier,
    issuer               Name,
    validity             Validity,
    subject              Name,
    subjectPublicKeyInfo SubjectPublicKeyInfo,
    issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                         -- If present, version MUST be v2 or v3
    subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                         -- If present, version MUST be v2 or v3
    extensions      [3]  EXPLICIT Extensions OPTIONAL
                         -- If present, version MUST be v3
}

SubjectPublicKeyInfo  ::=  SEQUENCE  {
    algorithm            AlgorithmIdentifier,
    subjectPublicKey     BIT STRING  
}

4.3、PKCS#12证书

因为X.509证书只包含公钥,但有些时候我们需要把私钥和公钥合并成一个证书,放在服务端使用,用于解密、签名。
PKCS#12就定义了这样一种证书,它既包含了公钥有包含了私钥。典型的入pfx、p12证书就是PKCS#12证书。

4.4、PKCS#7证书

当你收到一个网站的证书后,你需要验证其真实性。因为一个X.509证书包含了公钥、持有人信息、签名。为了验证其真实性,你需要签证其签名,而验证签名则需要签发的CA机构的公钥证书。同样原理,当你拿到CA机构的公钥证书后,你也需要验证该CA机构的真实性,而验证该CA机构的证书,你需要该CA上级机构的CA公钥证书...以此类推,你需要一直验证到根证书为止。

所以为了验证一个网站证书的真实性,你需要的不仅一张证书,而是一个证书链。而PKCS#7就定义了这样一个证书链的类型结构。典型如p7b后缀名的证书就是这样的格式。

下图是苹果网站的证书链:

5、用OpenSSL命令行处理各种类型间的转换

5.1、密钥处理

RSA私钥生成(==> PKCS#1)

openssl genrsa -out private_pkcs1.pem 2048

RSA公钥提取

openssl rsa -in private_pkcs1.pem -out public_pkcs8.pem -pubout
openssl rsa -in private_pkcs1.pem -out public_pkcs1.pem -pubout -RSAPublicKey_out

openssl rsa -in private_pkcs8.pem -out public_pkcs8.pem -pubout
openssl rsa -in private_pkcs8.pem -out public_pkcs1.pem -pubout -RSAPublicKey_out

RSA公钥格式转换(PKCS#8 ==> PKCS#1)

openssl rsa -in public_pkcs8.pem -out public_pkcs1.pem -pubin -RSAPublicKey_out

RSA私钥格式转换(PKCS#1 ==> PKCS#8)

openssl pkcs8 -in private_pkcs1.pem -out private_pkcs8.pem -topk8 -nocrypt

RSA私钥格式转换(PKCS#8 ==> PKCS#1)

openssl rsa -in private_pkcs8.pem -out private_pkcs1.pem

RSA公钥编码格式转换(PKCS#8:PEM ==> DER)

openssl rsa -pubin -in public_pkcs8.pem -out public_pkcs8.der -outform DER
openssl rsa -in private_pkcs8.pem -out private_pkcs1.der -outform DER

查看私钥及公钥n、e、d

输出到命令行窗口
openssl rsa -in private_pkcs8.pem -text
openssl rsa -in private_pkcs1.pem -text
openssl rsa -in public_pkcs8.pem -text -pubin
openssl rsa -in public_pkcs1.pem -text -pubin (命令报错,不可执行)

输出到文件
openssl rsa -in private_pkcs8.pem -text -out out.txt

从pfx文件中提取私钥(==> PKCS#8)

openssl pkcs12 -in demo_749054.pfx -nocerts -nodes -out private_pkcs8.pem

5.2、X.509证书处理

创建

 1.生成私钥
 openssl genrsa -out private_pkcs1.pem 4096
 
 2.生成证书签名请求(CSR)
 openssl req -new -key private_pkcs1.key -out certificate_csr.csr
 
 3.使用上一步的证书签名请求签发证书
 openssl x509 -req -days 365 -in certificate_csr.csr -signkey private_pkcs1.key -out certificate.pem
 
 openssl x509 -req -days 365 -in certificate_csr.csr -signkey private_pkcs1.key -out certificate.der -outform DER
 
 以上三个步骤也可以通一个简单的方法,实现一步创建私钥和证书(此种方式生成的私钥必须加密):
 openssl req -new -x509 -newkey rsa:4096 -keyout private_pkcs1.pem -out certificate.der

查看证书内容

openssl x509 -in certificate.pem -text
openssl x509 -in certificate.pem -text -noout (不输出文件本身内容)
openssl x509 -in certificate.der -inform DER -text

5.3、PKCS7证书处理

从 p7b 文件中提取所有证书(PKCS7 ==> X.509?)

openssl pkcs7 -inform DER -in certificate_pkcs7.p7b -out certificate.pem -print_certs

从提取的证书中提取公钥(X.509? ==> PKCS8)

openssl x509 -in certificate.pem -pubkey -noout > public_pkcs8.pem

5.4、PKCS12证书处理

移除 pfx 证书密钥

运行下面命令,第一次输入原证书密码,第二次数据新证书密码(直接回车表示无密码)
openssl pkcs12 -in encrypted.pfx -out decrypted.pfx

从 pfx 证书中导出密钥 (pfx ==> PKCS8)

openssl pkcs12 -in certificate_p12.pfx -out private_pkcs8.pem -nodes -nocerts

从 pfx 证书中导出密钥及证书 (pfx ==> PKCS8、X.509)

openssl pkcs12 -in certificate_p12.pfx -out private_pkcs8.pem -nodes

根据密钥及证书导出pfx

openssl pkcs12 -inkey private_pkcs1.pem -in certificate.pem -out p12.pfx -export

5.5、ASN.1 解析

解析公钥(PKCS#1)

openssl asn1parse -in public_pkcs1.pem
openssl ans1parse -in certificate.pem
openssl ans1parse -in certificate.der -inform DER

验证RSA公钥的常用方法是检查公钥参数是否符合规范和计算公钥的模数和指数是否正确。以下是一个简单的C语言示例代码,可以实现RSA公钥验证: ``` #include <openssl/rsa.h> #include <openssl/pem.h> int verify_rsa_pubkey(const char* pubkey_file) { RSA *rsa = NULL; BIO *pubkey_bio = NULL; // 读取公钥文件 pubkey_bio = BIO_new_file(pubkey_file, "rb"); if (pubkey_bio == NULL) { printf("[ERROR] Failed to open public key file: %s\n", pubkey_file); return -1; } // 解析公钥 rsa = PEM_read_bio_RSA_PUBKEY(pubkey_bio, NULL, NULL, NULL); if (rsa == NULL) { printf("[ERROR] Failed to parse public key: %s\n", pubkey_file); BIO_free(pubkey_bio); return -1; } // 检查公钥参数是否符合规范 if (RSA_check_key(rsa) != 1) { printf("[ERROR] Invalid public key: %s\n", pubkey_file); RSA_free(rsa); BIO_free(pubkey_bio); return -1; } // 检查公钥的模数和指数是否正确 if (RSA_public_check_key(rsa) != 1) { printf("[ERROR] Incorrect public key: %s\n", pubkey_file); RSA_free(rsa); BIO_free(pubkey_bio); return -1; } RSA_free(rsa); BIO_free(pubkey_bio); printf("[INFO] Public key verification succeeded: %s\n", pubkey_file); return 0; } ``` 在上面的代码中,我们使用OpenSSL库中的RSA_check_key和RSA_public_check_key函数来验证公钥的参数和正确性。RSA_check_key函数会检查公钥的参数是否符合规范,例如指数是否为奇数,模数是否为正整数等。RSA_public_check_key函数会计算公钥的模数和指数,如果计算结果不正确,则表示公钥有误。 以上代码仅供参考,实际应用中,需要根据具体的情况对代码进行修改和优化。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值