一. 简介 加密解密过程都会用到密钥,根据在加密解密过程中使用的密钥是否相同 ,我们将加密解密算法分为两种:对称加密算法和非对称加密算法。本文首先介绍两种加密算法——“对称加密算法”和”非对称加密算法”。
但今天的主角是非对称加密算法 ,我们将介绍非对称加密算法的一个前提 和两个特性 。
一个前提:公钥可公开,私钥只有自己持有
两个特性:公钥加密、私钥解密;私钥加密、公钥解密
我们将以最简单的公钥加密私钥解密场景来入手,使用图解的方式分析通信双方是如何安全地进行交流。
在此基础上,我们会分析这种场景下的两大安全隐患——消息源的身份认证 和公钥的归属性 。 由于无法确认消息源身份,就会导致消息被他人篡改或者消息源否认是自己发送的消息。 由于无法确认公钥的归属性,会导致公钥被调包,从而被第三方窃取消息。
我们针对这两个问题,很自然的引出了数字签名技术 和CA机构 。
最后,我们将使用strongswan提供的PKI工具,自己创建一个CA机构,使用自签名创建CA机构的根证书。使用CA机构的证书和私钥来为一个实体终端颁发一个”可信任的证书”。并为此证书验证合法性。
二. 对称加密算法 2.1 对称加密算法定义 对称加密算法使用相同的密钥进行加密和解密。假设明文为P,密文为C,密钥为K,EK 是加密算法,DK 是解密算法,则:
加密过程可以这样表示:C = EK (P)
解密过程可以这样表示:P = DK (C)
可以看到,加密和解密过程都使用密钥K,我们称这个密钥K为共享密钥
2.2 对称加密算法使用场景 我们假设A与B想要进行加密交流,那么他们一定会有一个分享密钥K的过程。
此后A将使用共享密钥K对信息进行加密,再发给B。 B收到密文后,先用共享密钥进行解密,就可以得到明文了。
1 2 3 4 5 A C = E(P) ----密文传输------> P = D(C) B
2.3 隐患 如果有一个窃听者C,截获了共享密钥K,那么他不仅可以查看明文,甚至可以修改明文。 所以对称加密中对共享密钥的保护是至关重要的 。
三. 非对称加密算法 3.1 非对称加密算法定义 非对称加密算法有两个密钥,称为公钥(K公 )和私钥(K私 )。 非对称加密算法有两个重要的特性 :
对明文使用公钥加密、可以使用私钥进行解密
对明文使用私钥加密、可以使用公钥进行解密
非对称加密算法还有一个重要前提 ,公钥是可以公开给所有人的,私钥只有自己持有,他人不应该获得。
我们接下来介绍使用非对称加密方式来保护通信安全的场景。
3.2 加密场景 加密场景使用的特性是公钥加密、私钥解密 根据非对称加密算法的重要前提——公钥可公开、私钥只有自己持有。这意味着A、B、C都持有B的公钥。
1 2 3 4 5 A B C |-----------| |-----------| |-----------| | pubkey(B) | | pubkey(B) | | pubkey(B) | | | | prikey(B) | | | |-----------| |-----------| |-----------|
A想要向B发送一条加密消息,只需要使用B的公钥对消息进行加密,发送给B即可。 B收到消息后使用自己的私钥解密,就可以得到明文。而C由于没有B的私钥,所以无法解密,这样就保证了通信的安全。
1 2 3 4 5 6 7 8 9 A 使用公钥B加密消息 ------------> 使用私钥B解密 B ------------> 没有私钥B、无法解密 C
3.3 加密场景的隐患 以上场景并不是无懈可击的,C无法解密的前提的A在加密时使用了正确的公钥B,如果在A加密前,C将A手中的公钥B调包为了公钥C又会如何呢?
1 2 3 4 5 A B C |-----------| |-----------| |-----------| | pubkey(C) | | pubkey(B) | | pubkey(B) | | | | prikey(B) | | prikey(C) | |-----------| |-----------| |-----------|
A在使用公钥加密时使用了错误的公钥C,那么C就可以使用自己得私钥C来解密这条消息(如下图)。
1 2 3 4 5 6 7 8 9 A 使用公钥C加密消息 ------------> 使用私钥B解密 B (解密失败) ------------> 使用私钥C解密 C (窃听成功)
此时,C窃听到了A发给B的消息,更可怕的是C也有B的公钥,意味着C不仅可以窃听、还可以篡改消息(如下图),将篡改后的消息使用公钥B加密,发给B。
1 2 3 4 5 C(窃听者) 篡改消息,使用公钥B加密 ------------> 使用私钥B解密 B (获取到被篡改的消息)
这其实是两种隐患,前一个隐患产生的原因是A无法核实手中的公钥的归属,而后者隐患产生的原因是B无法核实消息来源 。 接下来,我们将根据这两个安全隐患,一一进行解决.
四. 数字签名 4.1 签名介绍 数字签名技术就是为了解决信息完整性、身份认证和非否认性等问题 而设计的。
签名场景使用了非对称加密算法的特性是私钥加密、公钥解密
4.2 使用场景 根据非对称加密算法的重要前提——公钥可公开、私钥只有自己持有。这意味着私钥A只有自己持有,B和C都没有。
1 2 3 4 5 A B C |-----------| |-----------| |-----------| | pubkey(B) | | pubkey(B) | | pubkey(B) | | prikey(A) | | prikey(B) | | prikey(C) | |-----------| |-----------| |-----------|
B由于收到了被篡改的消息,但是A又不承认那个消息是自己发的,所以现在B要求,在开始会话前要首先验证会话发起者的身份,也就是要求A进行签名 。 签名的过程是这样的:
A将自己的身份”我是A”当作明文,使用仅自己持有的私钥A进行加密 。密文发给B之后,B使用A的公钥进行解密 ,可以得到明文”我是A”。这样,A就无法抵赖了。同时B也确定了会话的发起者确实是A,不会被C误导。
1 2 3 4 5 6 7 8 9 10 A 使用私钥A加密"我是A" ------------> 使用公钥A解密 B (得到"我是A",确认对端身份) C 使用私钥C加密"我是A" ------------> 使用私钥A解密 B (解密失败,确认对端身份存疑)
五. CA权威机构 5.1 解决公钥归属问题 我们使用数字签名可以校验数据的所有者。但是现在还剩下一个问题——如何确定公钥的归属? 这就需要引入一个第三方机构 ,该机构有足够的权威性,可以得到所有人的信任——CA 机构。
还记得我们这个隐患是怎么产生的吗? A使用了错误的公钥C(本应该使用公钥B),并将数据加密,被C截获流量后使用自己的私钥C进行解密导致了消息泄漏。
现在A吃一堑长一智,他在加密前会先向CA机构确认一下手里的公钥是否是B的 ,由于CA有足够的权威,如果A得到CA的确认,说这个公钥确实是公钥B,那么A就可以放心地使用这个公钥来加密数据。如果CA说这个公钥不是B的,A就意识到了自己持有一个不被信任的公钥。就不会使用这个公钥了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 A 这个公钥是pubkeyB吗? ------------------> CA 这个公钥被我信任 <------------------ A 使用公钥加密数据 ------------------> 使用私钥B解密 B (得到明文) 这个公钥是pubkeyB吗? ------------------> CA 这个公钥我不认识 <------------------ A (异常公钥)
至此,关于公钥归属的问题通过引入一个权威机构CA解决了,但实际上针对公钥的归属问题,并不是向上文一样在使用时咨询CA机构。接下来我们介绍证书。
5.2 证书 在实际场景中,公钥是以一种称为证书的形式来公之于众 的。证书记录了这个公钥的持有者的很多身份信息,例如国家、省市、IP、域名信息、合法日期等。 这里我举一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 zrf@ubuntu:~/git/strongswan/testing/hosts/moon/etc/swanctl/x509$ pki --print --in moonCert.pem subject: "C=CH, O=strongSwan Project, CN=moon.strongswan.org" issuer: "C=CH, O=strongSwan Project, CN=strongSwan Root CA" validity: not before Nov 29 11:21:11 2023, ok not after Nov 29 11:21:11 2031, ok (expires in 2915 days) serial: 03 altNames: moon.strongswan.org flags: CRL URIs: http://crl.strongswan.org/strongswan.crl authkeyId: 77:9c:16:d3:9c:25:d1:c4:5e:84:7c:8b:40:a5:1e:c6:f9:c0:de:6a subjkeyId: 84:81:42:19:2c:83:49:f2:8e:0b:cb:03:c0:f5:ac:a2:87:7e:b8:0c pubkey: RSA 3072 bits keyid: 5d:33:7b:8c:da:39:82:57:f6:67:6c:38:95:8c:15:ea:d7:e4:c8:3d subjkey: 84:81:42:19:2c:83:49:f2:8e:0b:cb:03:c0:f5:ac:a2:87:7e:b8:0c
这个证书记录了公钥信息和公钥属主信息,但是为了确保这种信息的正确的,每个合法证书都由权威机构CA签发 ,并且在证书中也可以查得到签发机构。
例如上面的属于"C=CH, O=strongSwan Project, CN=moon.strongswan.org"
的证书是由"C=CH, O=strongSwan Project, CN=strongSwan Root CA"
签发的。可以看到还有合法日期not before Nov 29 11:21:11 2023
和not after Nov 29 11:21:11 2031
。还包括了属主的域名信息moon.strongswan.org
。
5.3 颁发证书 在实际场景中,B会先生成自己的私钥,接下来将公钥和自己的身份进行绑定,生成一个未经CA机构签名的证书。
他需要向CA机构提交申请,希望得到CA的认证。
CA机构在审核之后如果发现公钥和公钥属主信息真实,就会使用自己的私钥对这个证书进行签名,B就得到了一个被权威机构信任的证书,此时,就可以向外界公布自己的证书了。
1 2 3 4 5 6 7 B 将公钥和个人信息绑定生成未经认证的证书 --------------------------------------> 审核证书 CA 使用CA的私钥签名,颁发合法证书 <-------------------------------------
5.4 验证证书 至此,我们了解到,对于验证者A,他并不是直接持有B的公钥,而是持有B的证书,B的证书中有B的身份信息和颁发证书的权威机构CA的名字。
所以当A使用这个证书时,会首先确认下这个证书是否合法——即验证这个证书否经过CA机构的认可 。
这个过程也很简单,每个被签发的证书都会被权威机构签名——权威机构使用自己的私钥加密这个证书的一部分。
A可以使用CA机构的公钥来验证签名 ,如果验签成功,意味着这个证书被权威机构认为是合法的正确的。所以,A就可以信任证书中的身份和公钥。
1 2 3 4 5 6 7 8 9 10 A 使用CA的公钥验签 ------------------> 验签成功 证书可信任 使用CA的公钥验签 ------------------> 验签不成功 证书不可信
5.5 信任链 当一个实体(例如,网站)提供其数字证书时,该证书通常由某个CA签发。为了建立对这个证书的信任,验证者需要检查证书是否由受信任的CA签发,以及中间是否有其他CA签发的证书。这一系列的证书链构成了信任链。
信任链的验证过程如下:
根证书: 验证者首先查看证书链中的根证书,这是信任的起点。根证书是预先安装在操作系统或应用程序中的。
中间证书: 验证者检查目标证书是否由某个受信任的CA签发。如果是,验证者将查找该CA的证书(中间证书),并验证它的合法性。
目标证书: 最终,验证者检查目标证书,确保它是由中间证书签发的,并且中间证书是由根证书签发的。如果所有证书都是有效的,且目标证书的签名有效,则建立了信任。
六. 创建CA并颁布证书实验 5.1 创建一个CA 我使用的是strongswan提供的PKI命令行
使用pki --gen
生成一个类型的ed25519
的密钥,其中type可选rsa|ecdsa|ed25519|ed448|bliss
,这是CA机构的私钥,一定要保存好。
1 2 3 4 5 zrf@debian:/tmp$ pki --gen --type ed25519 --outform pem > strongswanKey.pem zrf@debian:/tmp$ cat strongswanKey.pem -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIK0uCyvAxja4l+XcViuofSQwZXPjgAw4CTEfAk2q5vUe -----END PRIVATE KEY-----
使用pki --self
命令将相应的公钥打包成自签名的CA证书,其生命周期为 10 年(3652 天)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 zrf@debian:/tmp$ pki --self --ca --lifetime 3652 --in strongswanKey.pem \ --dn "C=CH, O=strongSwan, CN=strongSwan Root CA" \ --outform pem > strongswanCert.pem zrf@debian:/tmp$ cat strongswanCert.pem -----BEGIN CERTIFICATE----- MIIBdjCCASigAwIBAgIIdpbqQE52YcUwBQYDK2VwMD8xCzAJBgNVBAYTAkNIMRMw EQYDVQQKEwpzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0Ew HhcNMjMxMjA1MTEwNDA3WhcNMzMxMjA0MTEwNDA3WjA/MQswCQYDVQQGEwJDSDET MBEGA1UEChMKc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBSb290IENB MCowBQYDK2VwAyEA+g2agkMD3vbinYSC4zN+3sCxmURttTCW09yWKFkxmNKjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRc9qnq ufZKbAfoGlKP6oidsEWPDTAFBgMrZXADQQA+7lHofkL3XZwBAyJ8HD+6RMw9LHlN YcLRROfzUHma3m0ExR1I6mg5YNxUBNXc3jh2/CIOGY65Ma8Z9zjwWWIO -----END CERTIFICATE-----
1 2 3 4 5 6 7 8 9 10 11 zrf@debian:/tmp$ pki --print --in strongswanCert.pem subject: "C=CH, O=strongSwan, CN=strongSwan Root CA" issuer: "C=CH, O=strongSwan, CN=strongSwan Root CA" validity: not before Dec 05 19:04:07 2023, ok not after Dec 04 19:04:07 2033, ok (expires in 3651 days) serial: 76:96:ea:40:4e:76:61:c5 flags: CA CRLSign self-signed subjkeyId: 5c:f6:a9:ea:b9:f6:4a:6c:07:e8:1a:52:8f:ea:88:9d:b0:45:8f:0d pubkey: ED25519 256 bits keyid: 45:2f:1d:0b:28:7f:6f:9f:1d:09:96:7b:d6:ed:d1:02:d5:d1:b0:c8 subjkey: 5c:f6:a9:ea:b9:f6:4a:6c:07:e8:1a:52:8f:ea:88:9d:b0:45:8f:0d
至此,我们就生成了自签名的CA证书,作为我们信任链的根证书
5.2 为一个实体创建私钥 现在我们为一个实体moon创建证书
使用pki --gen
命令创建一个类型为ed25519的私钥
1 2 3 4 5 zrf@debian:/tmp$ pki --gen --type ed25519 --outform pem > moonKey.pem zrf@debian:/tmp$ cat moonKey.pem -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEICK+zDZ22cxz0c1mqs76+3ujfkIN3rOAlMK7QNZavBSa -----END PRIVATE KEY-----
使用pki --print --type
来打印私钥
1 2 3 4 zrf@debian:/tmp$ pki --print --type ed25519 --in moonKey.pem privkey: ED25519 256 bits keyid: 5b:4a:c8:a6:d4:21:8d:6c:08:1b:c2:17:c4:ef:e2:04:c3:40:42:48 subjkey: f3:02:c2:ba:0b:d7:97:53:b5:cc:ce:cb:8b:46:22:58:a4:2b:d6:c0
5.3 向CA提出证书请求
使用pki --req
向CA提出一个创建证书的请求,次过程中将私钥公钥和实体信息进行绑定
1 2 3 4 5 6 7 8 9 10 11 12 zrf@debian:/tmp$ pki --req --type priv --in moonKey.pem \ --dn "C=CH, O=strongswan, CN=moon.strongswan.org" \ --san moon.strongswan.org --outform pem > moonReq.pem zrf@debian:/tmp$ cat moonReq.pem -----BEGIN CERTIFICATE REQUEST----- MIHxMIGkAgEAMEAxCzAJBgNVBAYTAkNIMRMwEQYDVQQKEwpzdHJvbmdzd2FuMRww GgYDVQQDExNtb29uLnN0cm9uZ3N3YW4ub3JnMCowBQYDK2VwAyEAaidKIJJYTIwx HCnBX8YplBgMm0CcAuaytEsRyvXgMqqgMTAvBgkqhkiG9w0BCQ4xIjAgMB4GA1Ud EQQXMBWCE21vb24uc3Ryb25nc3dhbi5vcmcwBQYDK2VwA0EARVPxH4pSTKqNeKdj 5cBopNMVk5h07BT2cM0U/J53rxf/jYFitRxvbHhMEumea53mnT9for2Mx6M3Yp0E ARasDg== -----END CERTIFICATE REQUEST-----
5.4 CA为实体颁发证书
使用pki --issue
命令,基于moonReq.pem请求,CA将颁发moon实体的证书,可以看到我们需要CA的证书和私钥来一起完成这个动作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 zrf@debian:/tmp$ pki --issue --cacert strongswanCert.pem --cakey strongswanKey.pem \ --type pkcs10 --in moonReq.pem --serial 01 --lifetime 1826 \ --outform pem > moonCert.pem zrf@debian:/tmp$ cat moonCert.pem -----BEGIN CERTIFICATE----- MIIBcTCCASOgAwIBAgIBATAFBgMrZXAwPzELMAkGA1UEBhMCQ0gxEzARBgNVBAoT CnN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQTAeFw0yMzEy MDUxMTIwMzRaFw0yODEyMDQxMTIwMzRaMEAxCzAJBgNVBAYTAkNIMRMwEQYDVQQK EwpzdHJvbmdzd2FuMRwwGgYDVQQDExNtb29uLnN0cm9uZ3N3YW4ub3JnMCowBQYD K2VwAyEAaidKIJJYTIwxHCnBX8YplBgMm0CcAuaytEsRyvXgMqqjQzBBMB8GA1Ud IwQYMBaAFFz2qeq59kpsB+gaUo/qiJ2wRY8NMB4GA1UdEQQXMBWCE21vb24uc3Ry b25nc3dhbi5vcmcwBQYDK2VwA0EAYYzVbyuGOWHGCJ2DHcSl24+WzkaC/7D8kjg/ ymPYLF1of31Sdm/Z9zLT0gFUBBWZt5ckHGoaURgFYdOgEdgzCQ== -----END CERTIFICATE----- zrf@debian:/tmp$ pki --print --in moonCert.pem subject: "C=CH, O=strongswan, CN=moon.strongswan.org" issuer: "C=CH, O=strongSwan, CN=strongSwan Root CA" validity: not before Dec 05 19:20:34 2023, ok not after Dec 04 19:20:34 2028, ok (expires in 1825 days) serial: 01 altNames: moon.strongswan.org flags: authkeyId: 5c:f6:a9:ea:b9:f6:4a:6c:07:e8:1a:52:8f:ea:88:9d:b0:45:8f:0d subjkeyId: f3:02:c2:ba:0b:d7:97:53:b5:cc:ce:cb:8b:46:22:58:a4:2b:d6:c0 pubkey: ED25519 256 bits keyid: 5b:4a:c8:a6:d4:21:8d:6c:08:1b:c2:17:c4:ef:e2:04:c3:40:42:48 subjkey: f3:02:c2:ba:0b:d7:97:53:b5:cc:ce:cb:8b:46:22:58:a4:2b:d6:c0
5.5 验证实体证书
使用pki --verify
来验证一个证书是否被CA信任
1 2 3 4 5 zrf@debian:/tmp$ pki --verify --in moonCert.pem --cacert strongswanCert.pem using certificate "C=CH, O=strongswan, CN=moon.strongswan.org" using trusted ca certificate "C=CH, O=strongSwan, CN=strongSwan Root CA" reached self-signed root ca with a path length of 0 certificate trusted, lifetimes valid
至此,我们就完成了CA的创建、使用CA为最终实体创建、颁发、验证证书的所有流程。