我使用高级加密标准(AES)在浏览器中使用“cypto-js”加密字符串,并需要在服务器上使用节点“crypto”解密。
我可以单独使用'crypto‘加密/解密,但是当我试图使用'crypto.createDecipher’解密‘密码’(Node)时,我会得到错误消息,结果是‘坏解密’或‘错误块大小’取决于我尝试的内容。
例句:只使用‘密码-js’-很好。
crypto-js
const cypherParams = CryptoJS.AES.encrypt('my message', 'passphrase')
const decrypted = CryptoJS.AES.decrypt(cypherParams, 'passphrase')
console.log(decrypted.toString(CryptoJS.enc.Utf8)) // 'my message' - works!例:用'crypto-js‘解码密码-结果是错误的
[client]
const cypherParams = CryptoJS.AES.encrypt('my message', 'passphrase')
[server]
const decipher = crypto.createDecipher('aes-256-cbc', 'passphrase');
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
// results in 'bad decrypt' or 'block size' error in console
console.log(decrypted); // this never executes我试过:
例:
const cypherParams = CryptoJS.AES.encrypt('my message', 'passphrase')
const base64Encoded = cipherParams.toString(CryptoJS.enc.Base64)
and
const cypherParams = CryptoJS.AES.encrypt('my message', 'passphrase')
const cypherParams.ciphertext = cipherParams.toString(CryptoJS.enc.Base64)我想就这样.我很感谢你的帮助和建议!
发布于 2020-11-23 08:29:11
如果密钥作为字符串传递,CryptoJS.AES.encrypt()将使用OpenSSL密钥派生函数(KDF) EVP_BytesToKey()派生出32字节密钥(和16字节IV),即确实将AES-256应用于加密(这里和这里)。在此过程中,将生成一个随机的8字节盐,这将确保每次都会产生不同的密钥/IV对。
NodeJS方法crypto.createCipher()使用相同的KDF,但不应用salt,因此始终生成相同的密钥/IV对。因此,crypto.createDecipher()也不考虑盐。
总之,这意味着用CryptoJS.AES.encrypt()加密时生成的密钥对与用crypto.createDecipher()解密时生成的密钥对不同,并且解密失败。
据我所知,这两种方法都没有提供控制是否使用盐的可能性,因此不能消除不相容。
因此,一种解决方案是省略内置的KDF (它无论如何都被认为是弱的,这也是为什么不推荐crypto.createCipher()/crypto.createDecipher() ),而使用可靠的KDF,例如PBKDF2,并使用由此派生的密钥/IV对。
在CryptoJS端,您必须将键和IV作为WordArray传递,在NodeJS端,您必须使用create.createDecipheriv()。
加密和解密之间的连接是密钥推导过程中随机生成的盐。盐不是秘密的,通常与密文连在一起,并以这种方式传递给接收者。
您提到使用的版本是Nodev8.12.0,因此不能应用crypto.createDecipheriv()。但是从0.1.94版本开始就可以使用crypto.createDecipheriv()了,所以它应该可以在您的环境中使用。
客户端加密的示例实现(CryptoJS):
// Generate random salt
var salt16 = CryptoJS.lib.WordArray.random(16); // Random 16 bytes salt
// Derive key and IV via PBKDF2
var keyIV = CryptoJS.PBKDF2("My Passphrase", salt16, {
keySize: (32 + 16) / 4, // 12 words a 4 bytes = 48 bytes
iterations: 1000, // Choose a sufficiently high iteration count
hasher: CryptoJS.algo.SHA256 // Default digest is SHA-1
});
var key32 = CryptoJS.lib.WordArray.create(keyIV.words.slice(0, 32 / 4)); // 8 words a 4 bytes = 32 bytes
var iv16 = CryptoJS.lib.WordArray.create(keyIV.words.slice(32 / 4, (32 + 16) / 4)); // 4 words a 4 bytes = 16 bytes
// Encrypt
var message = 'The quick brown fox jumps over the lazy dog';
var cipherParams = CryptoJS.AES.encrypt(message, key32, {iv:iv16});
var ciphertext = cipherParams.ciphertext;
// Concatenate salt and ciphertext
var saltCiphertext = salt16.clone().concat(ciphertext);
var saltCiphertextB64 = saltCiphertext.toString(CryptoJS.enc.Base64); // This is passed to the recipient
// Outputs
console.log("Salt:\n", salt16.toString(CryptoJS.enc.Base64).replace(/(.{56})/g,'$1\n'));
console.log("Ciphertext:\n", ciphertext.toString(CryptoJS.enc.Base64).replace(/(.{56})/g,'$1\n'));
console.log("Salt | Ciphertext:\n", saltCiphertextB64.replace(/(.{56})/g,'$1\n'));<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
服务器端解密的示例实现(NodeJS):
var crypto = require('crypto');
// Separate salt and ciphertext
var saltCiphertextB64 = 'lhBp/LKhv8TxeJYnLDy/F2oaQYScOVFVLLZxd00HiRy9fYy97lX2ZjGJt+S4x+GF9X0AEjAS9k8tUDHKCz4srQ=='; // Received from client
var saltCiphertextBuf = Buffer.from(saltCiphertextB64, 'base64');
var saltBuf = saltCiphertextBuf.slice(0,16);
var ciphertextBuf = saltCiphertextBuf.slice(16);
// Derive key and IV via PBKDF2
var keyIVBuf = crypto.pbkdf2Sync("My Passphrase", saltBuf, 1000, 32 + 16, 'sha256');
var keyBuf = keyIVBuf.slice(0, 32);
var ivBuf = keyIVBuf.slice(32, 32 + 16);
// Decrypt
var decipher = crypto.createDecipheriv("aes-256-cbc", keyBuf, ivBuf);
var plaintextBuf = Buffer.concat([decipher.update(ciphertextBuf), decipher.final()]);
// Outputs
console.log("Plaintext: ", plaintextBuf.toString('utf8')); // Plaintext: The quick brown fox jumps over the lazy doghttps://stackoverflow.com/questions/64962999
复制相似问题