我正在嘗試使用 sjcl.js 庫解密由 Ruby 生成的 AES 密碼。
由于未知原因,我收到“損壞”錯誤……。我想解決這個問題。
作為參考,在CBC模式下嘗試加解密時,解密成功。
紅寶石代碼:
cipher = OpenSSL::Cipher.new('aes-256-gcm')
cipher.encrypt
iv = cipher.random_iv
cipher.key = Digest::SHA256.digest(password)
ciphertext = cipher.update(plaintext) cipher.final
return Base64.strict_encode64(iv) Base64.strict_encode64(ciphertext)
Javascript代碼:
var iv = sjcl.codec.base64.toBits(IV_BASE64);
var ciphertext = sjcl.codec.base64.toBits(CIPHERTEXT_BASE64);
var key = sjcl.hash.sha256.hash(KEY_UTF8);
var decrypted = sjcl.mode.gcm.decrypt(new sjcl.cipher.aes(key), ciphertext, iv);
uj5u.com熱心網友回復:
AES-GCM 是一種經過身份驗證的加密演算法。加密時自動生成認證標簽,用于解密時的認證。當前的 Ruby 代碼中不考慮此標記。默認為 16 位元組,可使用檢索cipher.auth_tag且必須添加,例如:
ciphertext = cipher.update(plaintext) cipher.final cipher.auth_tag
關于 nonce/IV,請注意 Base64 編碼實際上應該在連接之后進行(但是,這對于 GCM 常用的 12 位元組 nonce/IV 并不重要)。
在 JavaScript 方面,nonce/IV 的分離缺失。密文和標簽不需要分開,因為 sjcl 處理兩者的連接(密文|標簽):
const GCM_NONCE_LENGTH = 12 * 8
const GCM_TAG_LENGTH = 16 * 8
// Separate IV and ciptertext/tag combination
let ivCiphertextTagB64 = "2wLsVLuOJFX1pfwwjoLhQrW7f/86AefyZ7FwJEhJVIpU iG2EITzushCpDRxgqK2cwVYvfNt7KFZ39obMMmIqhrDCIeifzs="
let ivCiphertextTag = sjcl.codec.base64.toBits(ivCiphertextTagB64)
let iv = sjcl.bitArray.bitSlice(ivCiphertextTag, 0, GCM_NONCE_LENGTH)
let ciphertextTag = sjcl.bitArray.bitSlice(ivCiphertextTag, GCM_NONCE_LENGTH)
// Derive key via SHA256
let key = sjcl.hash.sha256.hash("my password")
// Decrypt
let cipher = new sjcl.cipher.aes(key)
let plaintext = sjcl.mode.gcm.decrypt(cipher, ciphertextTag, iv, null, GCM_TAG_LENGTH)
//let plaintext = sjcl.mode.gcm.decrypt(cipher, ciphertextTag, iv) // works also; here the defaults for the AAD ([]) and the tag size (16 bytes) are applied
console.log(sjcl.codec.utf8String.fromBits(plaintext))
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sjcl/1.0.8/sjcl.min.js "></script>
上面代碼中使用的密文是使用 Ruby 代碼生成的,考慮了身份驗證標簽,并成功解密。
請注意,使用摘要的密鑰派生是不安全的。相反,應該使用可靠的密鑰派生函式,如 PBKDF2。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/485801.html
