AES-GCM是一种经过身份验证的加密算法.它在加密期间自动生成身份验证标记,用于解密期间的身份验证.当前Ruby代码中考虑了not个标记.默认为16字节,可使用cipher.auth_tag
检索,必须添加,例如:
ciphertext = cipher.update(plaintext) + cipher.final + cipher.auth_tag
关于nonce/IV,请注意,Base64编码实际上应该进行after次串联(然而,对于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.