Encryption
實現 PBKDF2 + AES CBC + HMAC 的正確方法是什麼?
我一直在閱讀大量有關使用 HMAC 身份驗證實現 AES CBC 模式的正確方法。我已經看到了很多解釋,但是,我很難在包括密鑰推導、加密和解密在內的所有步驟上找到一個實際的真實範例(帶有程式碼)。我的應用程序使用 PBKDF2 進行密鑰派生。這是我到目前為止所擁有的:
派生密鑰
- 使用 KDF 生成 256 位“密鑰材料”
key_material = pbkdf2(user_password, salt, iterations, size:256, alg:sha256)
- 將密鑰材料分成兩半,生成用於加密和簽名的 x2 128 位密鑰
enc_key = key_material.split(0, 127) mac_key = key_material.split(128, 255)
加密
- 生成 128 位初始化向量
iv = secureRandomBits(128)
- 做AES加密
cipher = aesEncrypt(plaintext, iv, mode:cbc, key:enc_key)
- 使用級聯 IV 和密碼位計算 MAC
mac = hmac(iv + cipher, alg:sha256, key:mac_key)
- 將結果值儲存到伺服器(被認為是不安全的儲存)
storeValuesToServer(cipher, iv, mac)
解密
- 從儲存中獲取數據
cipher, iv, mac = getValuesFromServer()
- 重新計算mac
new_mac = hmac(iv + cipher, alg:sha256, key:mac_key)
- 比較 Mac
if(mac != new_mac) throw 'Failed MAC check!'
- 做AES解密
plaintext = aesDecrypt(cipher, iv, mode:cbc, key:enc_key)
問題
這看起來正確嗎?這裡主要擔心的是:
- 我是否正確導出了密鑰,根據 KDF 的輸出將它們分成兩半?
- 我是否通過組合正確計算 HMAC
iv + cipher
。如果我這樣做了,這有關係cipher + iv
嗎?
你會發現關於這個主題有很多分歧,尤其是密鑰推導。但是,是的,您的虛擬碼很好,儘管您可能想要修改 (0, 128) => (0, 127) 和 (129, 256) => (128, 255) …(如果我錯了,請糾正我?)。此外,您可能希望實現一個恆定時間比較函式來驗證 mac。
我是否正確導出了密鑰,根據 KDF 的輸出將它們分成兩半?
這可以。有些人會不同意。有關更深入的討論,請參見此處 和此處。
我是否通過組合 iv + cipher 正確計算 HMAC。如果我做了 cipher + iv 有關係嗎?
是的,您正在正確計算 HMAC。不,cipher + iv 的順序根本不重要。如果您可以使用它,您可能需要考慮像GCM這樣的模式,它使用單個密鑰為您處理加密和身份驗證。