如何使用OpenSSL:哈希值、數(shù)字簽名等
通過(guò) OpenSSL 深入了解密碼學(xué)的細(xì)節(jié):哈希值、數(shù)字簽名、數(shù)字證書(shū)等。
本系列的第一篇文章通過(guò) OpenSSL 庫(kù)和命令行實(shí)用程序介紹了哈希、加密/解密、數(shù)字簽名和數(shù)字證書(shū)。這第二篇文章將對(duì)細(xì)節(jié)進(jìn)行深入探討。讓我們從計(jì)算中無(wú)處不在的哈希開(kāi)始,并考慮是什么使哈希函數(shù)具備密碼學(xué)意義。
密碼學(xué)哈希
OpenSSL 源代碼的下載頁(yè)面包含了一個(gè)帶有最新版本的表格。每個(gè)版本都有兩個(gè)哈希值:160 位 SHA1 和 256 位 SHA256。這些值可以用來(lái)驗(yàn)證下載的文件是否與存儲(chǔ)庫(kù)中的原始文件相匹配:下載者在本地重新計(jì)算下載文件的哈希值,然后將結(jié)果與原始文件進(jìn)行比較?,F(xiàn)代系統(tǒng)有計(jì)算這種哈希值的實(shí)用程序。例如,Linux 有 md5sum 和 sha256sum。OpenSSL 本身也提供了類(lèi)似的命令行實(shí)用程序。
哈希值被用于計(jì)算的許多領(lǐng)域。例如,比特幣區(qū)塊鏈?zhǔn)褂?SHA256 哈希值作為區(qū)塊標(biāo)識(shí)符。挖比特幣就是生成一個(gè)低于指定閾值的 SHA256 哈希值,也就是至少有 N 個(gè)前導(dǎo)零的哈希值。(N 的值可以上升或下降,這取決于特定時(shí)間的挖礦生產(chǎn)力)。作為一個(gè)興趣點(diǎn),如今的礦機(jī)是為并行生成 SHA256 哈希值而設(shè)計(jì)的硬件集群。在 2018 年的一個(gè)高峰期,全球的比特幣礦工每秒產(chǎn)生約 7500 萬(wàn)個(gè)太哈希值 —— 這真是一個(gè)不可思議的數(shù)字。
網(wǎng)絡(luò)協(xié)議也使用哈希值(在這里通常叫做“校驗(yàn)和”)來(lái)支持消息的完整性;也就是說(shuō),保證收到的消息與發(fā)送的消息是一樣的。消息發(fā)送者計(jì)算消息的校驗(yàn)和,并將結(jié)果與消息一起發(fā)送。當(dāng)消息到達(dá)時(shí),接收方重新計(jì)算校驗(yàn)和。如果發(fā)送的校驗(yàn)和與重新計(jì)算的校驗(yàn)和不一致,那么消息在傳輸過(guò)程中可能出現(xiàn)了一些問(wèn)題,或者發(fā)送的校驗(yàn)和出現(xiàn)了問(wèn)題,或者兩者都出現(xiàn)了問(wèn)題。在這種情況下,應(yīng)該重新發(fā)送消息和它的校驗(yàn)和,或者至少應(yīng)該觸發(fā)一個(gè)錯(cuò)誤情況。(如 UDP 這樣的低級(jí)網(wǎng)絡(luò)協(xié)議不會(huì)理會(huì)校驗(yàn)和。)
哈希的其他例子大家都很熟悉。比如一個(gè)網(wǎng)站,要求用戶用密碼進(jìn)行驗(yàn)證,用戶在瀏覽器中輸入密碼,然后,他們通過(guò) HTTPS 連接到服務(wù)器,密碼從瀏覽器加密發(fā)送到服務(wù)器。一旦密碼到達(dá)服務(wù)器,就會(huì)被解密,然后進(jìn)行數(shù)據(jù)庫(kù)表的查詢。
在這個(gè)查詢表中應(yīng)該存儲(chǔ)什么?存儲(chǔ)密碼本身是有風(fēng)險(xiǎn)的。風(fēng)險(xiǎn)要小得多的方式是存儲(chǔ)一個(gè)由密碼生成的哈希值,也許在計(jì)算哈希值之前“加一些鹽(額外的位)改善口味”。你的密碼可能會(huì)被發(fā)送到 Web 服務(wù)器上,但網(wǎng)站可以向你保證,密碼不會(huì)存儲(chǔ)在那里。
哈希值還出現(xiàn)在安全的各個(gè)領(lǐng)域。例如,基于哈希值的消息認(rèn)證碼(HMAC)使用一個(gè)哈希值和一個(gè)秘密的加密密鑰來(lái)認(rèn)證通過(guò)網(wǎng)絡(luò)發(fā)送的消息。HMAC 碼輕量級(jí)且易于在程序中使用,在 Web 服務(wù)中很受歡迎。一個(gè) X509 數(shù)字證書(shū)包括一個(gè)稱為指紋的哈希值,它可以方便證書(shū)驗(yàn)證。一個(gè)存放于內(nèi)存中的可信存儲(chǔ)可以實(shí)現(xiàn)為一個(gè)以這種指紋為鍵的查找表 —— 作為一個(gè)支持恒定查找時(shí)間的哈希映射。來(lái)自傳入的證書(shū)的指紋可以與可信存儲(chǔ)中的密鑰進(jìn)行比較,以確定是否匹配。
密碼學(xué)哈希函數(shù)應(yīng)該具有什么特殊屬性?它應(yīng)該是單向的,這意味著很難被逆轉(zhuǎn)。一個(gè)加密哈希函數(shù)應(yīng)該是比較容易計(jì)算的,但是計(jì)算它的反函數(shù)(將哈希值映射回輸入位串的函數(shù))在計(jì)算上應(yīng)該是困難的。下面是一個(gè)描述,用 chf 作為加密哈希函數(shù),我的密碼 foobar 作為樣本輸入。
+---+foobar—>|chf|—>hash value ## 簡(jiǎn)單直接+--–+
相比之下,逆向操作是不可行的:
+-----------+hash value—>|chf inverse|—>foobar ## 棘手困難+-----------+
例如,回憶一下 SHA256 哈希函數(shù)。對(duì)于一個(gè)任意長(zhǎng)度為 N > 0 的輸入位串,這個(gè)函數(shù)會(huì)生成一個(gè) 256 位的固定長(zhǎng)度的哈希值;因此,這個(gè)哈希值甚至不會(huì)反映出輸入位串的長(zhǎng)度 N,更不用說(shuō)字符串中每個(gè)位的值了。順便說(shuō)一下,SHA256 不容易受到長(zhǎng)度擴(kuò)展攻擊。唯一有效的逆向工程方法是通過(guò)蠻力搜索將計(jì)算出的 SHA256 哈希值逆向返回到輸入位串,這意味著需要嘗試所有可能的輸入位串,直到找到與目標(biāo)哈希值匹配的位串。這樣的搜索在 SHA256 這樣一個(gè)完善的加密哈希函數(shù)上是不可行的。
現(xiàn)在,最后一個(gè)回顧的知識(shí)點(diǎn)是有序。加密哈希值是統(tǒng)計(jì)學(xué)上的唯一,而不是無(wú)條件的唯一,這意味著兩個(gè)不同的輸入位串產(chǎn)生相同的哈希值是不太可能的,但也不是不可能的 —— 這稱之為碰撞。生日問(wèn)題提供了一個(gè)很好的反直覺(jué)的碰撞例子。對(duì)各種哈希算法的抗碰撞性有著廣泛的研究。例如,MD5(128 位哈希值)在大約 221 次哈希之后,抗碰撞能力就會(huì)崩潰。對(duì)于 SHA1(160 位哈希值),大約在 261 次哈希后開(kāi)始崩潰。
對(duì)于 SHA256 的抗碰撞能力的剖析,目前還沒(méi)有一個(gè)很好的估計(jì)。這個(gè)事實(shí)并不奇怪。SHA256 有 2256 個(gè)不同的哈希值范圍,這個(gè)數(shù)字的十進(jìn)制表示法有 78 位之多!那么,SHA256 哈希會(huì)不會(huì)發(fā)生碰撞呢?當(dāng)然可能,但可能性極小。
在下面的命令行示例中,有兩個(gè)輸入文件被用作位串源:hashIn1.txt 和 hashIn2.txt。第一個(gè)文件包含 abc,第二個(gè)文件包含 1a2b3c。
為了便于閱讀,這些文件包含的是文本,但也可以使用二進(jìn)制文件代替。
在命令行(百分號(hào) % 是提示符)使用 Linux sha256sum 實(shí)用程序?qū)@兩個(gè)文件進(jìn)行處理產(chǎn)生以下哈希值(十六進(jìn)制):
% sha256sum hashIn1.txt9e83e05bbf9b5db17ac0deec3b7ce6cba983f6dc50531c7a919f28d5fb3696c3 hashIn1.txt% sha256sum hashIn2.txt3eaac518777682bf4e8840dd012c0b104c2e16009083877675f00e995906ed13 hashIn2.txt
OpenSSL 哈希對(duì)應(yīng)的結(jié)果與預(yù)期相同:
% openssl dgst -sha256 hashIn1.txtSHA256(hashIn1.txt)= 9e83e05bbf9b5db17ac0deec3b7ce6cba983f6dc50531c7a919f28d5fb3696c3% openssl dgst -sha256 hashIn2.txtSHA256(hashIn2.txt)= 3eaac518777682bf4e8840dd012c0b104c2e16009083877675f00e995906ed13
這種對(duì)密碼學(xué)哈希函數(shù)的研究,為我們仔細(xì)研究數(shù)字簽名及其與密鑰對(duì)的關(guān)系奠定了基礎(chǔ)。
數(shù)字簽名
顧名思義,數(shù)字簽字可以附在文件或其他一些電子工件(如程序)上,以證明其真實(shí)性。因此,這種簽名類(lèi)似于紙質(zhì)文件上的手寫(xiě)簽名。驗(yàn)證數(shù)字簽名就是要確認(rèn)兩件事:第一,被擔(dān)保的工件在簽名被附上后沒(méi)有改變,因?yàn)樗糠质腔谖募募用軐W(xué)哈希值。第二,簽名屬于一個(gè)人(例如 Alice),只有她才能獲得一對(duì)密鑰中的私鑰。順便說(shuō)一下,對(duì)代碼(源碼或編譯后的代碼)進(jìn)行數(shù)字簽名已經(jīng)成為程序員的普遍做法。
讓我們來(lái)了解一下數(shù)字簽名是如何創(chuàng)建的。如前所述,沒(méi)有公鑰和私鑰對(duì)就沒(méi)有數(shù)字簽名。當(dāng)使用 OpenSSL 創(chuàng)建這些密鑰時(shí),有兩個(gè)獨(dú)立的命令:一個(gè)是創(chuàng)建私鑰,另一個(gè)是從私鑰中提取匹配的公鑰。這些密鑰對(duì)用 base64 編碼,在這個(gè)過(guò)程中可以指定它們的大小。
私鑰由數(shù)值組成,其中兩個(gè)數(shù)值(一個(gè)模數(shù)和一個(gè)指數(shù))組成了公鑰。雖然私鑰文件包含了公鑰,但提取出來(lái)的公鑰并不會(huì)透露相應(yīng)私鑰的值。
因此,生成的帶有私鑰的文件包含了完整的密鑰對(duì)。將公鑰提取到自己的文件中是很實(shí)用的,因?yàn)檫@兩把鑰匙有不同的用途,而這種提取方式也將私鑰可能被意外公開(kāi)的危險(xiǎn)降到最低。
接下來(lái),這對(duì)密鑰的私鑰被用來(lái)生成目標(biāo)工件(如電子郵件)的哈希值,從而創(chuàng)建簽名。在另一端,接收者的系統(tǒng)使用這對(duì)密鑰的公鑰來(lái)驗(yàn)證附在工件上的簽名。
現(xiàn)在舉個(gè)例子。首先,用 OpenSSL 生成一個(gè) 2048 位的 RSA 密鑰對(duì):
openssl genpkey -out privkey.pem -algorithm rsa 2048
在這個(gè)例子中,我們可以舍去 -algorithm rsa 標(biāo)志,因?yàn)?nbsp;genpkey 默認(rèn)為 RSA 類(lèi)型。文件的名稱(privkey.pem)是任意的,但是隱私增強(qiáng)郵件(PEM)擴(kuò)展名 .pem 是默認(rèn) PEM 格式的慣用擴(kuò)展名。(如果需要的話,OpenSSL 有命令可以在各種格式之間進(jìn)行轉(zhuǎn)換。)如果需要更大的密鑰大?。ɡ?4096),那么最后一個(gè)參數(shù) 2048 可以改成 4096。這些大小總是二的冪。
下面是產(chǎn)生的 privkey.pem 文件的一個(gè)片斷,它是 base64 編碼的:
-----BEGIN PRIVATE KEY-----MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANnlAh4jSKgcNj/ZJF4J4WdhkljP2R+TXVGuKVRtPkGAiLWE4BDbgsyKVLfs2EdjKL1U+/qtfhYsqhkK...-----END PRIVATE KEY-----
接下來(lái)的命令就會(huì)從私鑰中提取出這對(duì)密鑰的公鑰:
openssl rsa -in privkey.pem -outform PEM -pubout -out pubkey.pem
由此產(chǎn)生的 pubkey.pem 文件很小,可以在這里完整地顯示出來(lái):
-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZ5QIeI0ioHDY/2SReCeFnYZJYz9kfk11RrilUbT5BgIi1hOAQ24LMilS37NhHYyi9VPv6rX4WLKoZCmkeYaWk/TR54nbH1E/AkniwRoXpeh5VncwWMuMsL5qPWGY8fuuTE27GhwqBiKQGBOmU+MYlZonOO0xnAKpAvysMy7G7qQIDAQAB-----END PUBLIC KEY-----
現(xiàn)在,有了密鑰對(duì),數(shù)字簽名就很容易了 —— 在本例中,源文件 client.c 是要簽名的工件:
openssl dgst -sha256 -sign privkey.pem -out sign.sha256 client.c
client.c 源文件的摘要是 SHA256,私鑰在前面創(chuàng)建的 privkey.pem 文件中。由此產(chǎn)生的二進(jìn)制簽名文件是 sign.sha256,這是一個(gè)任意的名字。要得到這個(gè)文件的可讀版本(比如 base64),后續(xù)命令是:
openssl enc -base64 -in sign.sha256 -out sign.sha256.base64
文件 sign.sha256.base64 現(xiàn)在包含如下內(nèi)容:
h+e+3UPx++KKSlWKIk34fQ1g91XKHOGFRmjc0ZHPEyyjP6/lJ05SfjpAJxAPm075VNfFwysvqRGmL0jkp/TTdwnDTwt756Ej4X3OwAVeYM7i5DCcjVsQf5+h7JycHKlMo/Jd3kUIWUkZ8+Lk0ZwzNzhKJu6LM5KWtL+MhJ2DpVc=
或者,可執(zhí)行文件 client 也可以被簽名,由此產(chǎn)生的 base64 編碼簽名將如預(yù)期的不同:
VMVImPgVLKHxVBapJ8DgLNJUKb98GbXgehRPD8o0ImADhLqlEKVy0HKRm/51m9IXxRAN7DoL4Q3uuVmWWi749Vampong/uT5qjgVNTnRt9jON112fzchgEoMb8CHNsCTXIMdyaPtnJZdLALw6rwMM55MoLamSc6M/MV1OrJnk/g=
這一過(guò)程的最后一步是用公鑰驗(yàn)證數(shù)字簽名。作為驗(yàn)證的一個(gè)重要步驟,應(yīng)重新計(jì)算用于簽署工件(在本例中,是可執(zhí)行的 client 程序)的哈希值,因?yàn)轵?yàn)證過(guò)程應(yīng)表明工件在簽署后是否發(fā)生了變化。
有兩個(gè) OpenSSL 命令用于這個(gè)目的。第一條命令是對(duì) base64 簽名進(jìn)行解碼。
openssl enc -base64 -d -in sign.sha256.base64 -out sign.sha256
第二條是核實(shí)簽名:
openssl dgst -sha256 -verify pubkey.pem -signature sign.sha256 client
第二條命令的輸出,應(yīng)該是這樣的:
Verified OK
為了了解驗(yàn)證失敗時(shí)的情況,一個(gè)簡(jiǎn)短但有用的練習(xí)是將最后一個(gè) OpenSSL 命令中的可執(zhí)行的 client 文件替換為源文件 client.c,然后嘗試驗(yàn)證。另一個(gè)練習(xí)是改變 client 程序,無(wú)論多么輕微,然后再試一次。
數(shù)字證書(shū)
數(shù)字證書(shū)匯集了到目前為止所分析的各個(gè)部分:哈希值、密鑰對(duì)、數(shù)字簽名和加密/解密。生產(chǎn)級(jí)證書(shū)的第一步是創(chuàng)建一個(gè)證書(shū)簽名請(qǐng)求(CSR),然后將其發(fā)送給證書(shū)頒發(fā)機(jī)構(gòu)(CA)。在 OpenSSL 的例子中,要做到這一點(diǎn),請(qǐng)運(yùn)行:
openssl req -out myserver.csr -new -newkey rsa:4096 -nodes -keyout myserverkey.pem
這個(gè)例子生成了一個(gè) CSR 文檔,并將該文檔存儲(chǔ)在文件 myserver.csr(base64 文本)中。這里的目的是:CSR 文檔要求 CA 保證與指定域名相關(guān)聯(lián)的身份,域名也就是 CA 所說(shuō)的通用名(CN)。
盡管可以使用現(xiàn)有的密鑰對(duì),但這個(gè)命令也會(huì)生成一個(gè)新的密鑰對(duì)。請(qǐng)注意,在諸如 myserver.csr 和 myserverkey.pem 等名稱中使用 server 暗示了數(shù)字證書(shū)的典型用途:作為與 www.google.com 等域名相關(guān)的 Web 服務(wù)器的身份擔(dān)保。
然而,無(wú)論數(shù)字證書(shū)如何使用,同樣使用這個(gè)命令都會(huì)創(chuàng)建一個(gè) CSR。它還會(huì)啟動(dòng)一個(gè)問(wèn)題/回答的交互式會(huì)話,提示有關(guān)域名的相關(guān)信息,以便與請(qǐng)求者的數(shù)字證書(shū)相連接。這個(gè)交互式會(huì)話可以通過(guò)在命令中提供基本的信息,用反斜杠來(lái)續(xù)行一步完成。-subj 標(biāo)志提供了所需的信息。
% openssl req -new \-newkey rsa:2048 -nodes -keyout privkeyDC.pem \-out myserver.csr \-subj "/C=US/ST=Illinois/L=Chicago/O=Faulty Consulting/OU=IT/CN=myserver.com"
產(chǎn)生的 CSR 文件在發(fā)送給 CA 之前可以進(jìn)行檢查和驗(yàn)證。這個(gè)過(guò)程可以創(chuàng)建具有所需格式(如 X509)、簽名、有效期等的數(shù)字證書(shū)。
openssl req -text -in myserver.csr -noout -verify
這是輸出的一個(gè)片斷:
verify OKCertificate Request:Data:Version: 0 (0x0)Subject: C=US, ST=Illinois, L=Chicago, O=Faulty Consulting, OU=IT, CN=myserver.comSubject Public Key Info:Public Key Algorithm: rsaEncryptionPublic-Key: (2048 bit)Modulus:00:ba:36:fb:57:17:65:bc:40:30:96:1b:6e:de:73:…Exponent: 65537 (0x10001)Attributes:a0:00Signature Algorithm: sha256WithRSAEncryption…
自簽證書(shū)
在開(kāi)發(fā) HTTPS 網(wǎng)站的過(guò)程中,手頭有一個(gè)不用經(jīng)過(guò) CA 流程的數(shù)字證書(shū)是很方便的。在 HTTPS 握手的認(rèn)證階段,自簽證書(shū)就能滿足要求,盡管任何現(xiàn)代瀏覽器都會(huì)警告說(shuō)這樣的證書(shū)毫無(wú)價(jià)值。繼續(xù)這個(gè)例子,自簽證書(shū)的 OpenSSL 命令(有效期為一年,使用 RSA 公鑰)如下:
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:4096 -keyout myserver.pem -out myserver.crt
下面的 OpenSSL 命令呈現(xiàn)了生成的證書(shū)的可讀版本:
openssl x509 -in myserver.crt -text -noout
這是自簽證書(shū)的部分輸出:
Certificate:Data:Version: 3 (0x2)Serial Number: 13951598013130016090 (0xc19e087965a9055a)Signature Algorithm: sha256WithRSAEncryptionIssuer: C=US, ST=Illinois, L=Chicago, O=Faulty Consulting, OU=IT, CN=myserver.comValidityNot Before: Apr 11 17:22:18 2019 GMTNot After : Apr 10 17:22:18 2020 GMTSubject: C=US, ST=Illinois, L=Chicago, O=Faulty Consulting, OU=IT, CN=myserver.comSubject Public Key Info:Public Key Algorithm: rsaEncryptionPublic-Key: (4096 bit)Modulus:00:ba:36:fb:57:17:65:bc:40:30:96:1b:6e:de:73:...Exponent: 65537 (0x10001)X509v3 extensions:X509v3 Subject Key Identifier:3A:32:EF:3D:EB:DF:65:E5:A8:96:D7:D7:16:2C:1B:29:AF:46:C4:91X509v3 Authority Key Identifier:keyid:3A:32:EF:3D:EB:DF:65:E5:A8:96:D7:D7:16:2C:1B:29:AF:46:C4:91X509v3 Basic Constraints:CA:TRUESignature Algorithm: sha256WithRSAEncryption3a:eb:8d:09:53:3b:5c:2e:48:ed:14:ce:f9:20:01:4e:90:c9:...
如前所述,RSA 私鑰包含的值是用來(lái)生成公鑰的。但是,給定的公鑰不會(huì)泄露匹配的私鑰。關(guān)于底層數(shù)學(xué)理論的介紹,見(jiàn) https://simple.wikipedia.org/wiki/RSA_algorithm。
數(shù)字證書(shū)與用于生成該證書(shū)的密鑰對(duì)之間存在著重要的對(duì)應(yīng)關(guān)系,即使證書(shū)只是自簽的:
- 數(shù)字證書(shū)包含構(gòu)成公鑰的指數(shù)和模數(shù)值。這些值是最初生成的 PEM 文件中密鑰對(duì)的一部分,在本例中,是文件 
myserver.pem。 - 指數(shù)幾乎總是 65,537(如本例中),所以可以忽略。
 - 密鑰對(duì)的模數(shù)應(yīng)該與數(shù)字證書(shū)的模數(shù)相匹配。
 
模數(shù)是一個(gè)很大的值,為了便于閱讀,可以進(jìn)行哈希處理。下面是兩個(gè) OpenSSL 命令,它們檢查相同的模數(shù),從而確認(rèn)數(shù)字證書(shū)是基于 PEM 文件中的密鑰對(duì)。
% openssl x509 -noout -modulus -in myserver.crt | openssl sha1 ## 證書(shū)中的模數(shù)(stdin)= 364d21d5e53a59d482395b1885aa2c3a5d2e3769% openssl rsa -noout -modulus -in myserver.pem | openssl sha1 ## 密鑰中的模數(shù)(stdin)= 364d21d5e53a59d482395b1885aa2c3a5d2e3769
所產(chǎn)生的哈希值匹配,從而確認(rèn)數(shù)字證書(shū)是基于指定的密鑰對(duì)。
回到密鑰分發(fā)問(wèn)題上
讓我們回到第一部分末尾提出的一個(gè)問(wèn)題:client 程序和 Google Web 服務(wù)器之間的 TLS 握手。握手協(xié)議有很多種,即使是用在 client 例子中的 Diffie-Hellman 版本也有不同的方式。盡管如此,client 例子遵循了一個(gè)共同的模式。
首先,在 TLS 握手過(guò)程中,client 程序和 Web 服務(wù)器就加密套件達(dá)成一致,其中包括要使用的算法。在本例中,該套件是 ECDHE-RSA-AES128-GCM-SHA256。
現(xiàn)在值得關(guān)注的兩個(gè)要素是 RSA 密鑰對(duì)算法和 AES128 塊密碼,用于在握手成功的情況下對(duì)消息進(jìn)行加密和解密。關(guān)于加密/解密,這個(gè)過(guò)程有兩種流派:對(duì)稱和非對(duì)稱。在對(duì)稱流派中,加密和解密使用的是相同的密鑰,這首先就引出了密鑰分發(fā)問(wèn)題。如何將密鑰安全地分發(fā)給雙方?在非對(duì)稱流派中,一個(gè)密鑰用于加密(在這種情況下,是 RSA 公鑰),但另一個(gè)密鑰用于解密(在這種情況下,是來(lái)自同一對(duì)密鑰的 RSA 私鑰)。
client 程序擁有來(lái)認(rèn)證證書(shū)的 Google Web 服務(wù)器的公鑰,而 Web 服務(wù)器擁有來(lái)自同一對(duì)密鑰的私鑰。因此,client 程序可以向 Web 服務(wù)器發(fā)送加密信息,而 Web 服務(wù)器可以單獨(dú)對(duì)該通信進(jìn)行解密。
在 TLS 的情況下,對(duì)稱方式有兩個(gè)顯著的優(yōu)勢(shì):
- 在 
client程序與 Google Web 服務(wù)器之間的互動(dòng)中,認(rèn)證是單向的。Google Web 服務(wù)器向client程序發(fā)送三張證書(shū),但client程序并沒(méi)有向 Web 服務(wù)器發(fā)送證書(shū),因此,Web 服務(wù)器沒(méi)有來(lái)自客戶端的公鑰,無(wú)法加密發(fā)給客戶端的消息。 - 使用 AES128 的對(duì)稱加密/解密比使用 RSA 密鑰的非對(duì)稱加密/解密快了近千倍。
 
TLS 握手將兩種加密/解密方式巧妙地結(jié)合在一起。在握手過(guò)程中,client 程序會(huì)生成隨機(jī)位,即所謂的預(yù)主密(PMS)。然后,client 程序用服務(wù)器的公鑰對(duì) PMS 進(jìn)行加密,并將加密后的 PMS 發(fā)送給服務(wù)器,服務(wù)器再用 RSA 密鑰對(duì)的私鑰對(duì) PMS 信息進(jìn)行解密:
+-------------------+ encrypted PMS +--------------------+client PMS--->|server’s public key|--------------->|server’s private key|--->server PMS+-------------------+ +--------------------+
在這個(gè)過(guò)程結(jié)束時(shí),client 程序和 Google Web 服務(wù)器現(xiàn)在擁有相同的 PMS 位。每一方都使用這些位生成一個(gè)主密碼,并立即生成一個(gè)稱為會(huì)話密鑰的對(duì)稱加密/解密密鑰?,F(xiàn)在有兩個(gè)不同但等價(jià)的會(huì)話密鑰,連接的每一方都有一個(gè)。在 client 的例子中,會(huì)話密鑰是 AES128 類(lèi)的。一旦在 client 程序和 Google Web 服務(wù)器兩邊生成了會(huì)話密鑰,每一邊的會(huì)話密鑰就會(huì)對(duì)雙方的對(duì)話進(jìn)行保密。如果任何一方(例如,client 程序)或另一方(在這種情況下,Google Web 服務(wù)器)要求重新開(kāi)始握手,握手協(xié)議(如 Diffie-Hellman)允許整個(gè) PMS 過(guò)程重復(fù)進(jìn)行。
總結(jié)
在命令行上說(shuō)明的 OpenSSL 操作也可以通過(guò)底層庫(kù)的 API 完成。這兩篇文章重點(diǎn)使用了這個(gè)實(shí)用程序,以保持例子的簡(jiǎn)短,并專(zhuān)注于加密主題。如果你對(duì)安全問(wèn)題感興趣,OpenSSL 是一個(gè)很好的開(kāi)始地方,并值得深入研究。















 
 
 



 
 
 
 