深入剖析 RSA 密钥原理及实践

一、前言

在经历了人生的很多至暗时刻后,你读到了这篇文章,你会后悔甚至愤怒:为什么你没有早点写出这篇文章?!

你的至暗时刻包括:

1.你所在的项目需要对接银行,对方需要你提n g 8 ( ,供一个加密证书。你手上只有一个六级英语证书,不确定这3 G g个是k D } } S Q t否满足对方需求。由于你迟迟无法提供正确的证书,项= E t 7目因此. ] # $ N O延期,加薪计划泡汤,月供断了,女朋友分手了,你感觉人生完了。

2. 你老骥伏枥 2 个月,终于搞懂了.crt 格式证书。加入到新项目,项目在进行证书托管改造。哈哈,这题我会% H A k ! 3 P [ O,就是把证书文件上传到托管系统。你对项目组成员大] O u M l C h m喝一声,放开那些证书,X l i ! u X 4让我来!挤进去一看,是陈年老项目了,根本没有证书,当时使s h M _用是公钥和私钥,如何公钥和私钥变成证书⋯⋯由于你5 ? # H M }迟迟无法提供正确的证书,项目因此延期,加薪计划泡汤,月供断了,女朋友分手了,你感觉人生完了。

3. 你卧薪尝胆 3 个月,摸清楚了 SSL 证书的来龙去脉。踌躇满志加入O 4 *到新项B e o U m {目,你向项目经理痛陈血泪史,经此一役,你已经成长为V q _ M安全证书方面的专家。项目经理喜出望外,正Q . %好项目在进行数据安全改造,数据库需要启用 SSL,来得正是时候,不着急,明天下班前提供几[ U q密钥文件就行。越明日,下班前半小时,你缓缓走向项目经理,“你要的货到了b & 1 # {”,便排出三个证书,这个是 key 文件,这个是公钥文件,这个是证a T M 8 o l 0 ^书文件。项目经理点点头又摇摇头,我要的是JKS 文件呀。你说,明天提供。越明日,下班前的半个小时,你把 JKS 格式文件交给项目经理,项目经理点点头又摇摇头,密码呢?没有密码怎么行?F I | L D $由于你迟迟无法提供正确的证书,项目因此延期,加薪计划泡汤,月供断了,女朋友分手了,你感觉L W a u M _ : O人生完了。

本文将从以下几部分来揭示 RSA 密钥文件的鲜为人知A x 2 h u ! n 0 =的秘密:

  • RSA 算法数学基础
  • RSA秘钥体系六层模型
  • RSA 工具使用
  • RSA密钥使用场景

注:虽然密钥与证书严格意义上并不等同,但为了表述方便,没有v , %特殊指定的话,本文中的密钥一词涵盖了公钥,私钥,证书等概念。

二、RSA 算法数学基础

RSA 算法是基于数论的,RSA算法的复杂性的基础在于g o a Z ` e L一个大数的素数分解是NP难题,非常难破解。RSA 算法相关的数学概念:

深入剖析 RSA 密钥原理及实践

对于任意一个数 x,可以计算出 y:

深入剖析 RSA 密钥原理及实践

通过 y,可以计算出 x:

深入剖析 RSA 密钥原理及实践

也就是说,x 通过数对 (m,e) 生成了 y 后,可以] i ` + f E r V通过数对 (m, d) 将 y 还原成 x。

这里,我们实际上演示了RSA加密解密的数学过程。通过公式 (1),根据 x 计算得出 y 的过程就是加密,通过T ) ? V R o公式 (2),根据 y 计算得出 x 的过程就是解密。

在实际应用中,Rk = m .SA 算法通过公钥进行加密,私钥进行解密,因此数对 (M W 0 @ G *m,e) 就是公钥,(m, d) 就是私钥。

实际上为了Q e y o M X提高私钥解密速度,私钥会保存一些中间结果,例如 p, q, e, 等等。

所以在实 9 v y h y1 ~ O U $应用中,可以通过私钥导出公钥。

三、RSA秘钥六层模型

为了方便理解RSA密钥的r } L Z T原理,本人创造性地发明了RSA密^ O ; 9 u = W 钥六层模型概念。每一层定义了自己的职责和边界,层级越低P 0 ;,其表示的内容越倾向于抽象和理论;层级越高,其表示的内容越倾向于实际应用。

深入剖析 RSA 密钥原理及实践

  • Data:数据层,定S 7 D O / ~ } _义了RSA密钥的数学概念(m,e,p,q等)或者参与8 r ` k 9实体(subject, issue} c 7 ir等)。
  • Serialization:序列化层,定义了将复杂数据结构序列化的方法。
  • Structure:结构层,定义了不同格式的RSA密钥的Y [ A数据组织p h .形式。
  • Text:文本层,定义了@ 2 6 F 6 - lw T , [ % * f ?二进制的密钥转换成文本的方法。
  • Presentation:表现层,1 k [ v y定义了文本格式密钥的表现形式。
  • Application:应用层,定义了RSA密钥使用的各种场景。

下面对每一层进行具体说明。

3.2 数据层

从上文可知,秘钥是一个数据结构,每个结构包含了 2 个或更多的成员(公钥包含 m 和 e,私钥包含 m,d,e 以及其他一些中间结果)。为了将这些数据结构保存在文件中,需要定义某种格式对秘钥进行序列化。

3.3 序列, ` ? _ _化层

W 1 u e ^ @ = & q前常见的定义数据结构的格式包括 JSON 和 XML 等文本格式。

比如,8 ? N O理论上我们可以把公钥定义为一个 JSON:

JSON格式密钥

{
"m":"15",
"e":"3"
}

或者,也可以把私钥定义为一个 XML:

<?xml>
<key>
<modulR ^ ge>15</module>
<e>3</e>
<d&I 6 O 9 C P 3gt;3</d>
<p>3</p>
<q>5&lk V O A ? F v 0t;/q>
<key>

但是 RSA 发明的时候,这两种格式都还不存在。因此科学家们选择了当时比较流行的语法格式ASN.1。

3.3.1 ASN.1

ASN.] 3 ,1 全称是 Abstract Syntax Nou B 9 + station dot one,(@ o ? [ 9 1 9抽象语法记号第1版)。数字1被ISO加在ASN的后边,是为了保持ASN的开放性,可以 u i n h $让以后功能更加强大的ASN被命名为ASN.2等,但至今也没有出现。

ASN.1描述了一种对数据进行表示、编码、传输和解码的数据格式。它提供了一整套正规的格式用于描述对象的结构,而不管语言上如何执行及这些数据的具体指代,也不用去管到底N z R =是什么样的应用程序。

3.3.2 ASN.1 编码规则

ASN@ A : X B.1的具体语法q m O a r * N可以参考维基百科(https://zh.wikipedia.org/wi R D X h uki/ASN.1),在此只作简要说明。

ASN.1 中数据类型表示是 T-L-V 的形式:头 2 个字节代表数据类型,接下来的 2 个字节代表字节长度,V 代表具体值。常见的基础类型的值包括 Integer, UTF8String, 复w 1 d - * j 3 u合结构包括 SEQUENCE, SET.秘钥和证书都是 SEQUENCE 类型,而 SEQUENCE 的 type 是 0x30,且长度是大于 127 的,因此第2 个字节是 0x82. ASN.1 编码表示` e ^ ) g F的数据是二进制数据,通常通过 BASE64 转化成字符串保存在 pem 文件中,而 0x3- L A p K 6 M082 经过 BASE64 编码后,就是字符串 MI,因此所有 PEM 文件存储的秘钥开始的前两个字符是 MI。

BER, CER, DER 是 ASN.1 编码规则。其中 DK [ ` - k ^ fER(Distinguish Encode Rules) 是无歧义编码规则,保证相同的数据结构产生的序列化结果+ ? w z 5 7也相同的。

ASN.1 只是定义了抽象数据的序列化方式,但是具体的编码还需要进一步定义。

严格来说,ASN.1 还不是一种定义j 7 O B数据的格式,而是一种语法标准,按照这种标准,可以制定各种各S . l O E J U f样的格式。

3.4 结构层

根据秘钥文件用途不同,以下标准定义了不同的结构来对秘钥数据进行 ASN.1 编码。通常而言,不同格式的秘钥暗示了不同的结构。

  • pkcs#1用于定义 RSA 公钥、私钥结构
  • pkcs#7用于定义证书链
  • pkcs#8用于定义任何算法公私钥
  • pkcs#& 6 C 9 5 A w 8 o12用于定义私钥证书7 _ f ^ U ( P
  • X.509定义公钥证书

这些格式的具体区别比较参见下文3.5.2

3.5 表现层

可以看到 ASN.1 及其编码规则(BER, CER, DER)定义的是二进制规则,保存在文件中也是二进制格式。由于当时的电子邮件标准不支持二进制内容的传输,如果秘钥文件通过电子邮件传输,就需要将二进制文件转换成文d Q Y F 8 k本文件。这就是 PEM(Privacy-Enhanced Mail, 私密增强邮件)的由来。因此,PEM 文件中保存的秘@ { Z V h 5 t钥内容是 ASN.1 编码生成的二进制内容,再进行 base64 编0 s [ 5 * # 5码后的文本。

另外,为了方便用户识别是何种格式,中文件的首尾加上一行表示身份的文本。PEM 文件一般包含三部分:[ ~ H 6 C =首行标签,BASE64 编码的文本} a r B | z K T数据,尾行标签。

-----B1 * ~ [ , K S LEGIN <label>-----
<BA} H [ sSE64 ENCODED DATA>
-----END <label>-----

针对不同的格式,<label> 值不一样。

3.5.2 PEM 文件格式小结

深入剖析 RSA 密钥原理及实践

3.6 应用层

在实际使用中,不仅仅需要使用公私钥对数据进行加解密,还需要根据不同的使用场景,解决密钥的分发、验证等。第5节列举了RSA密钥的一些常见使A i B s K d H用场景。

四、工具

4.1 openssl

注意:下面的命令中-RSAPublh g a [ f ! : ^icKey_in, -RSAPublicKey_out选项需要openssl1.0以上版本支持,如果报错,请检查 openssl 版本。

4.1.1 创建秘钥文7 S F q * = 3

# 生成 pkcs#1 格5 I @ B t [ T =式2048位的私钥
openssl genr? B ; 3sa -out private.pem 2048
#从私钥中提取 pkcs#8 格式公钥
oQ ` U ` / (penssl rsa -in privao M ete.pem -ou! 7 [ @ Q  w Vt public.pem -pubout
#从私钥中提取 pkcs#1 格式公钥
openssl rsa -in private.pem -out public.pem -RSAPublicKey_out

4.1.2 秘钥文件格式转换

#pkM R k w F Ics#1 公钥转换成 pkcs#8 公钥
openssl rsa -in pub@ k elic.pem -out public-pkcs8.pem -RSAPublicKey_in
#pkcs#8 公钥转换成 pkcs#1 公钥, ;  A r | J p
openssl rsa -in public-pkcs8.pem -oi c ? . X P 5ut public-pkcs1.pem -pubin -RSAPublicKey_out
#pkcs#1 私钥转换成 pkcs#8 私钥
oJ - h Upenssl pkcs8 -in private.pem -out privatl # M 4 7 ce-pkcs8.pem -topk8
#pkcs#8 私钥转换成 pkcs#1 私钥
openssl rsa -in private-pkcs8.pem -out private-pkcs1.pem

4.1.3 查看秘钥文件信息

#查看公钥信息
openssl rsa -in public.pem -pubin -text -noo5 P 5 Q Iut
#查看私钥信息
openssl rsa -_ 5 [ Uin priT O 8 tvate.pem -( c ` Ptext -noout

4.1.4 证书

RSA证书

#从现有私钥创建 CSR 文件
openssl req -key private.pem -out request.csr -new
#从现有 CSR 文件和私钥中创建证书,有效期365天
openssl x509 -6 c R ^req -in requR a n I Test.csr -signkey private.pem -out cert.crt -days 365
#生成全新证书和私钥
openssl req -nodes -newkey rsa:2048 -keyout root.key -out root.crt -x509 -days 365h Z Y S s + ] A !
#通 过 现 有 证 书 和 私 钥 (作 为CA ) 为 其 他 CSR 文u _ & n Y * M ? a 件 签 名
openssl x509 -req -in child.csr -days 365 -Q ~ A SCA root.crt -CAkey root.kG E ` 9 [ k ] H )ey -set_serv 5 o ^ Aial 01 -out child.crt
#查看证书信息
open+ B E H 1 C ]ssl x509 -in child.crt -text -noout
#从证书中提取公钥] ` F V F X
openssl x509 -pubkey -noout -inn ) D 9 V g / 4 child.crt  > public.pem

4.1.5 JKS

#将CA证书转换成JKS格式
keytool -importcert -alias Cacert -file ca.crt  -keysto] } n j Nre truststoremys^ A y % 2 % =ql.jks -storepass password123
#将client.crt和client.key转g _ k t K h ?换成PKCS#12格式
openss- D R ` *l pkcs12 -export -in cli+ h I I $ @ V Hent.crt -inkey client.key -name "mysqlclient" -passout pass:mypassword -out client-keystoP 0 n 1 k I  Tre.p12
#将PKCS#12格式转换成JKS格式
keytool -importkeystore -srckeystore client-keystore.p12 -srcstoretype pkcs12 -srcstorepass mypassword -deM H 1 @ ` Hstkeystore clientstore.jks -deststoretype JKS -dests} : _toreA . 0pass password456

五、 RSA密钥使用场景

5.1 HTTPS单向认证

由于HTTP协议是明文传输,为了保证HTTP报文k C l t O不被泄露和篡改,HTTPS通过SSL/TLS协议对HTTk $ j ; u PP报文进行加解密。

简单来说,w Z + K QHTTPS协议要求客户端和服务端建立连接的过程( $ 2中,首先进行会话密钥交换,然后使用该会话密钥对通信报文进行加解密。整个通信过程如q a下:

  1. 服务端通过4.1.4所示方法创建RSA证书server.crt和私钥server.key,并在WEB服务器中进行配置。

  2. 客户端与服务端建立连接,服务端向客户端发送证书server.crt。

  3. 客户端对服务端证书进行校验,并随机生成会话密钥,将通过服务端证书对会话密钥进行加密,传给服务端。

  4. 服务端通过server.key对加密后的会话密钥进行解密,获z v ; l L 8 g `得会话密/ ! S Y 7 $ U钥原{ ( Y z f ,文。

  5. 客户端通过会话密钥对HTTP报文进行加密,传给服务端。

  6. 服务端通过会话密钥对HTTP加密报文进行解密,获得HTTP报文原文。

  7. 服务端通过会话密钥对HTTP响应报文进行加密,返回给客户端。

  8. 客户端s 0 @ 0 : e通过会话密钥对HTTP响应报文进行解密,获得HTTP响应报文1 ) . | z原文。

深入剖析 RSA 密钥原理及实践

(图1.| } Z HTTPS单向认证)

5.2 HTTPS双向认证

5.1节描述的HTTPS场景是一个通用场景,整个过程只有客户端对于服务端的验证,即客户端拿到服务端的证书后,会对证书进行有效性验证,比如是否是CA签名的,是否仍处于有效期内等。这种单向验证在浏览器访问等场景中没有问题,因为这种服$ + 8 N N务设计地目的就是对外数以万计的用户提供服务。但是在某些场景,比如说仅对特定企业、商户提供服务,服务端需要对客户端进3 5 Y 4 c s行验证,通过验证的受信客户端才能正常。

访问服务端时,就需要用到HTTPS双向认证。

HTTPS双向认证的过8 = a y程,就是在HTTPS单向认证的基础之上,增进服务端对客户端的认证。解决方案的思路就是,客户端保存客户端证书client.crt4 b | . i M,但是客户a 6 | (端证书不是客户端自己签名或者CA签名,而是由服务端的root.k9 ] W 5 L A j Tey进行签名。在# K rHTTPS双向认证过程中,_ 9 U A h = K 9 @客户端需要将客户端L [ O = Y s 9证书client.crt发送给服务端,服务端使用& W : = B H : } ,root.key进行验证无误D v = , T @ _ ( m后,方可进行后续通信;否则,该客户端即非受信客户端,服务端拒绝提供后续服务。

具体通信过程如下所示:

  1. 服务端通过4.1.4所示方法创建RSA证书serV } u ! A n t W 7ver.crt和私钥server.key,并在WEB服务器中进行配置。

  2. 客户端与服务端建立连接,服务端向客户端发送证书server.crt。

  3. 客户端对服 T o . c务端证书进行校验,验证通过后继续后续流程;验证不通过则断开连接,流程结束。

  4. 服务端向客户端发送报文,请求客户端发送客户端证书。

  5. 客户端向服务端发送客户端证书。

  6. 服务端通过root.kem # K o ~ ! 7 Oy对客户端证书进行验证,验证无误进行后续流程;否则断开连接,流程结束。

  7. 客户端随机生成会话密钥,将通过服务端证书对会话密钥进行加密,传给服务端。

  8. 服务端通过servej 5 8 d { e {rX Y s n Y Z *.key对加密后的会话密钥进行解密,获得会话密钥原文。

  9. 客户端通过会话密钥对HTTP报文进行加密,传给服务端。

  10. 服务端通过会话密钥对HTTP加密报文进行解密,获得HTTP报文原文。

  11. 服务端通过7 + 会话密钥对HTTP响应报文进行加密,返回给客户端。

  12. 客户端通过会话密钥对HTTP响应报文进行[ + f解密,获得HTTP响应报文原文。

可以w b a u / z 0 d 8看出,向较于HTTPS单向认证过程,HTTPS双向认证过程在客户端验证服务端证书之后,在向服务端发送加6 # l密的会话密钥之前,会增加客户端向服务端发送客户端证书client.crt,服务端对该证书进行验证的过程。

深入剖析 RSA 密钥原理及实践

(图2. HTTPS双向认证)

5.3 MySQL开启 SSL

MySQL提供SSL的原理,与HTTPS类似,不同之处在于MySQL提供的服务的对象不会是成千上万+ V j s _ 4 v的普通用户,因此对于CA的需求并不E j Z E 1 :高。

因此实际CA证书通常都是服务端自己生成。

与HTTPS类似,MySQL提供两种形式的SSL认证机制:单向认证和双向认证。

5.3.1 MySQL的SSL单向认证

(1)服务端, | 0 a I e m z配置文件:ca.crt, server.crt, server.key,其中server.crt由cag = P I d g.crt签名生成。

(2)客} . *户端配置文件:ca.crt,cat - v m.crt与服务端的ca.crt相同。

(3)客户端生成JKS文件

keytool -importcert -alias Cacert -file ca.crt -keystoreQ 9 O Q ? 8 L @ / truststoremysql.jks -stor^ V 2 aepass password123

(4)通过jdbc字符串配置SSL选项和JKS文件

verifyServerCertificate=true&useSSL=true&requireSSL=true&trustCertificateKeyStoreUrl=file:./truststoremysql.jks&trustCertificateKeyStorePassP ! Xword=password123

5.3.2 MySQL的SSL双向认证

(1)服务端配置文件:ca.crt, serK E R t e ver.crt, server.key, 其中server.crt由ca.crt签名生成。

7 ` 22)客户端配置文件:ca.crt, client.crt, client.key, 其中ca.crt与服务端的ca.crt相= _ U / * I同, client.c f i ; P ~ { ucrt由ca.crt签名生成。

(3)客d d j F u D , 1户端生成trustKeyStore文件

keytool -importcert -alias Cacert -file ca.crt -keystore truststore.jks -storepass password123

(4)客户端生成cliO 6 z ~ P m y ] 2entKeyStore文件

keytool -importcert -alias Cacert -file ca.crt -@ 2 b Bkeystore clientstore.jks -storepass password456

(5)通过jdbc字符串配置SSL选项和JKS文件

verifyServerCertificate=true&useSSL=true&requireSSL=true&trustCertificateKeySt$ O K A E e 9 p oreUrl=file:./trA &  Quststorem A K d F 7 : Z.jks&trustCertificateKeyStorePassword=password123&clientCertificateKeyStoreUrl=file:./clientstore.jks&clientCertifice u O ; l ) /atM X e $ R o & 1eKeySto2 } k : $ b r drePassword=password456

关于MySQL的SSL认证更多细节可以参考:

  • https:@ H ( T D @ H =//n Z 2 3 ewww.howtoforge.com/tutorial/how-to-enable-ssl-and-remote-connections-for-mysql-on-centos-7/

  • https://www.cnblogs.com/ccgood/p/13034426.html

附录A 不同格式的 ASN.1 编码

A: g J m S ,.1 pkcsb ( - #1

A.1.1 公钥

RSAPublicKey ::= SEQUENCE {
modulus INTEGER , -- no y z
publi7 C ( E y ` D )cExponent INTEGER -- e
}

A.1.2z Q D X 私钥+ } m ] 2 W D

RSAPrivateKey ::= SEQUENCE {
version Version ,Q l j a E ) V 5
modulus INTEGER , -- n
publicExponent INTEGER , -- e
privateExponent INTEG* x 1 n n G @ER , -- d
prime1 INTEGER , -- p
prime2 INTEGER , -- q
exponent1 INTEGER , -- d! W O & s n mod (p-1)
exponent2 INTEGER , -- d mod (q-1)
coefficient INTEGER , -- (inverse of qr g 4 [) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}

A.2 pkcs#8

A.2.1 pkcs#8 公钥

PublicKeyInfo ::= SEQUENCE {
ag j a RlgorS 1 u ; = 2 } sithm AlgorithmIdentifier ,
PublicKey BIT STRING
}
AlgorithmIdentifier6 . S - S A & + ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ,
parameters ANY DEFINE- 8 tD BY algorithm OPTIONAL
}

A.2.2 pkcs#8 私钥

OneAsymmetricKey ::= SEQUENCE {
version Version ,
pF 7 i Z N B { !ri _ H ovateKeyAlgorithm PrivateKeyAlgorithmIdentifier ,
privateKey Pri^ + { vateKey ,
attributes [0] Attributes OPTIONAL ,
...,
[[2: publicKey [1] PublicKey OPTIONAL ]],
...
}
PrivateKey ::= OCTET STRING
-- Content varies based on type of key. T2 = #he
-- algorithm identifier dictates the format of
-- the ke! 8 t ] { ly.

A.3 X.509

A.3.1 X.509 证书

Certifi[ p c X g R , % [cate ::= SEQ7 c F W NUE$ % 9 bNCE {
tbsCertificate TBSCertificate ,
signatureAlgorithm AlgorithmIdentifier ,
signatureValue BIT Sf } s iTRING
}
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber ,
signature AlgorithmI~ . # R -dentifier ,
iZ Y $ o  / assuer Name,
vam G  C 5lidity Validity ,
subject Name,
subjectPublicKeyInfo SubjectPubliw s - s l 0 HcKeyInfo ,
issuerUniqueID [1]& j i 9 w R | D IMPLI~ ^ ^ 6CIT UnT 7 + o k T hiqueIdentifier 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) P z m c @ w ] o Extensions OPTIONAL
-- If p= B 9resent , version MUST be v3
}
Version ::= INTEGER { v1(0), v2(1), v3(2) }
CertificateSerialNumber ::= INTEGER
Validity ::= SEQUENCE {
notBefore Time,
notAfter Time
}
Time ::= CHOICE {
utcTime UTCTime ,
gener$ 8 % z calTime Generali_ ` K Y 8 JzedTime
}
UniqueIdentifier ::= BIT STRING
SubjectPublicKeyInfo ::= SEQUE # Z ^NCE {
algorithm AlgorithmIdentifier ,
subjectPubli* f } [cKeyX | = M s A ( % h BITJ 6 + 7 # Y j ) STRING
}
Extensions ::= SEQUENCE SIZE (1..MAX) OF5 | } Y n Extension
Extension ::= SE# t g LQUENCE {
extnID OBJECT IDENTIFIER ,
criticf p ]al BOOLEAN DW O c 0 w l C EFAULT FALSE ,
extnValue OCTET STRIN7 w  N Y , * _ IG
-- cont, z ) O x ; A b aainsg s U the DER encoding of an ASN.1 value
-- corresponding to the exte Z K p ! H * rnsion type id= f Lentified
-- by extnID
}5 @ ) `

作者:Zhu Rans N : 8 q 9 g k ,来自vivo互联网技术团队