串流密碼(stream ciphers)比起完整的偽隨機數產生器(PRNG),其實更接近確定性隨機位元產生器(DRBG)——因為和 DRBG 一樣,串流密碼是確定性的。

正是這份確定性讓解密成為可能:你可以重新產生當初用來加密的那串偽隨機位元。

若改用 PRNG,你可以加密卻永遠無法解密——安全,但沒用。

與 DRBG 的差別:兩個輸入#

串流密碼與 DRBG 的分別在於:DRBG 只接收單一輸入值,串流密碼則接收兩個值:

  • 金鑰(key):應保密,通常 128 或 256 位元。
  • nonce:不必保密,但對每把金鑰都必須唯一,通常介於 64 到 128 位元。

nonce 這個名字其實是 number used only once(只用一次的數字)的縮寫。在串流密碼的脈絡下,它有時被稱為 IV(initial value,初始值)。

金鑰流#

串流密碼產生一串偽隨機的位元流,稱為金鑰流(keystream)。金鑰流與明文 XOR 就完成加密,再與密文 XOR 就完成解密:

KS = SC(K, N)      產生金鑰流
C  = P ⊕ KS        加密
P  = C ⊕ KS        解密

其中 SC 是串流密碼演算法、KS 是金鑰流、P 是明文、C 是密文。

圖 5-1:串流密碼如何加密:接收秘密金鑰 K 與公開 nonce N

加密與解密函式完全相同,因為兩者做的是同一件事——把位元與金鑰流 XOR。

這就是為什麼某些密碼學函式庫只提供單一個 encrypt 函式,加密與解密都用它。

絕不重複使用 (K, N)#

串流密碼允許你用金鑰 K₁ 與 nonce N₁ 加密一則訊息,然後:

  • K₁ 與另一個 nonce N₂(≠ N₁)加密另一則訊息,或
  • 用另一把金鑰 K₂(≠ K₁)與 nonce N₁ 加密。

但你絕不該再次K₁N₁ 加密,因為那會讓同一串金鑰流 KS 被用兩次。

屆時你會有 C₁ = P₁ ⊕ KSC₂ = P₂ ⊕ KS;若你知道 P₁,就能算出:

P₂ = C₁ ⊕ C₂ ⊕ P₁

兩種架構#

從高層次看,串流密碼分成兩類。

有狀態串流密碼#

有狀態串流密碼(stateful stream ciphers)擁有一個在金鑰流產生過程中不斷演化的秘密內部狀態

密碼先從金鑰與 nonce 初始化狀態,接著呼叫一個 update 函式來更新狀態值,並從狀態產生一個或多個金鑰流位元。

圖 5-2:有狀態串流密碼

著名的 RC4 就是有狀態密碼。

計數器式串流密碼#

計數器式串流密碼(counter-based stream ciphers)從金鑰、nonce 與一個計數器值產生金鑰流片段。

與有狀態串流密碼不同,金鑰流產生過程中不會記憶任何秘密狀態。Salsa20 屬於這一類。

圖 5-3:計數器式串流密碼

兩種內部實作取向#

上述兩種取徑定義的是串流密碼的高層次架構,與核心演算法如何運作無關。

串流密碼的內部結構也分成兩類,取決於密碼的目標平台:硬體導向軟體導向