RSA密钥格式解析

一、前言

在开发过程中,我们常常遇到用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是个二进制文件,我们用二级制查看器查看:

CF9739BD-4609-4789-B30B-B984C648336B.png

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

F87D8871-A002-475D-90BB-F2F05D9847C4.png

可以看到,解码后和 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
2F35414D-4C15-4D61-8AB1-FFF1B4CC1313.png

两相比对,我们就可以看出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公钥证书...以此类推,你需要一直验证到根证书为止。

5740AAFE-450B-4150-98CE-EBC1A9ADE838.png

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

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


DC755EA0-70C2-4607-B9F2-30279C687B3E.png

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

推荐阅读更多精彩内容

  • 最近,在写java读取key的时候遇到了一个version的问题。不解,就各种找资料,这里总结一下. ANS.1编...
    kamiSDY阅读 6,440评论 1 5
  • 1 基础 1.1 对称算法 描述:对称加密是指加密过程和解密过程使用相同的密码。主要分:分组加密、序列加密。 原理...
    御浅永夜阅读 890评论 0 2
  • 一. 证书 目前总的来说有三种常用的证书格式:X.509证书、PKCS#12证书和PKCS#7证书。X.509证书...
    飘荡着呢阅读 587评论 0 1
  • 数字证书就是网络通讯中标志通讯各方身份信息的一系列数据,其作用类似于现实生活中的身份证。它是由一个权威机构发行的,...
    拉肚阅读 11,149评论 0 13
  • 转:https://blog.csdn.net/mycoolx/article/details/6730435 O...
    right_33cb阅读 1,135评论 0 0