對稱式金鑰在安全與便利間取得不錯的平衡,卻有個重大問題:網路參與者必須實際交換祕密金鑰,當網路橫跨多個地理區域時尤其困難。非對稱式金鑰密碼學(asymmetric key cryptography,常稱公開金鑰加密 public key encryption)能緩解這個問題。
非對稱演算法需要兩種金鑰:
- 公鑰(public key):用來加密訊息。因為公鑰無法解密訊息,可以公開給任何人,即使在公開網路上傳送也不怕被攻擊者攔截拿去解密流量。
- 私鑰(private key):用來解密訊息,必須嚴格保密。

圖表 7-10:非對稱式金鑰的加密與解密
公鑰與私鑰在數學上相關,但演算法刻意讓「從公鑰反推私鑰」極為耗時。它們建立在稱為單向暗門函式(trapdoor function)的數學原語上——就像穿過一道暗門很容易,門在身後關上後卻很難走回去。這些演算法仰賴一個假設:底層數學的耗時特性沒有捷徑可繞過。但未來數學或運算能力的突破,可能推翻這類假設。
RSA 演算法#
RSA 是目前用於保護網路流量最廣泛的非對稱演算法,在可預見的未來仍將如此。較新的演算法基於橢圓曲線(elliptic curve)構造,但與 RSA 共享許多通用原理。
RSA 於 1977 年首度發表,命名取自三位開發者 Ron Rivest、Adi Shamir、Leonard Adleman。其安全性仰賴一個假設:分解兩個質數乘積而成的大整數非常困難。
金鑰產生流程的要點:
- 產生兩個大的隨機質數 p 與 q。
- 選一個公開指數 e(常用 65537,因其數學性質有助於演算法安全)。
- 計算模數 n(modulus,即 p 與 q 的乘積)與私密指數 d(private exponent,用於解密)。
- 公開指數 + 模數 = 公鑰;私密指數 + 模數 = 私鑰。
私密指數是由原始質數 p 與 q 產生的,因此除了私密指數本身,這兩個質數也必須保密。
RSA 加解密的運算流程
- 先把訊息轉為整數,通常把訊息的位元組視為一個可變長度的整數 m。
- 將 m 提升到公開指數的次方,得到
m^e。 - 對結果套用以模數 n 為模的模運算,得到密文——一個介於 0 與 n 之間的值。
- 解密時套用相同流程,只是把公開指數換成私密指數。

圖表 7-11:RSA 加解密的簡單範例
因為密文值介於 0 與 n 之間,若你有一把 1024 位元金鑰,一則訊息最多只能加密 1024 位元的內容。
RSA 運算非常昂貴,尤其相對於 AES 這類對稱式密碼。因此極少有應用直接用 RSA 加密訊息,而是產生一把隨機工作階段金鑰(session key),用對稱式密碼加密訊息本體,只用 RSA 加密那把工作階段金鑰一起傳送。接收方先解出金鑰,再用它解密訊息。這種組合兼得兩者之長:加密快速,又有公開金鑰的安全性。
RSA 填充(RSA Padding)#
基本 RSA 有個弱點:它是決定性的——用同一把公鑰加密同一則訊息,永遠得到相同的密文。
決定性讓攻擊者能發動選擇明文攻擊(chosen plaintext attack)。攻擊者持有公鑰,因此能加密任意訊息;他們持續加密自己的猜測,只要某個加密結果與原始密文相符,就等於在沒有私鑰的情況下解出了訊息。
為對抗選擇明文攻擊,RSA 在加密過程使用一種填充(padding),確保加密輸出是非決定性的。
此處的「填充」與前面區塊加密的填充不同:區塊填充是把明文補到區塊邊界,RSA 填充則是為了讓輸出不可預測。RSA 常用兩種填充方案:一是 PKCS#1.5,二是較新的 OAEP(Optimal Asymmetric Encryption Padding)。新應用推薦使用 OAEP。RSA 不使用填充是嚴重的安全漏洞。
Diffie–Hellman 金鑰交換#
RSA 不是唯一能在網路參與者之間交換金鑰的技術。有數種演算法專門用於此目的,其中最重要的是 Diffie–Hellman 金鑰交換(DH)。
DH 由 Whitfield Diffie 與 Martin Hellman 於 1976 年提出,和 RSA 一樣建立在指數運算與模算術之上。它讓兩個參與者交換金鑰,同時防止任何監聽網路的人得知該金鑰。流程概要:
- 發起者決定一個參數(一個大質數)並傳給對方;此值不是祕密,可明文傳送。
- 每個參與者各自產生自己的私鑰值(通常用密碼學安全的亂數產生器),再用私鑰與選定的群組參數計算出公鑰。
- 公鑰可安全地在雙方之間傳送而不洩露私鑰。
- 最後,各自把「對方的公鑰」與「自己的私鑰」結合,算出共享金鑰(shared key)。雙方從未直接交換金鑰,卻都得到了它。

圖表 7-12:Diffie–Hellman 金鑰交換演算法
基本版 DH 無法抵禦中間人攻擊(man-in-the-middle attack)。攻擊者可在網路上冒充伺服器:與用戶端交換一把金鑰,再與伺服器交換另一把金鑰,於是握有連線的兩把獨立金鑰。接著他就能解密來自用戶端的資料、轉發給伺服器,反之亦然。