首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用'crypto‘编码,用’crypto‘解码(节点)

用'crypto‘编码,用’crypto‘解码(节点)
EN

Stack Overflow用户
提问于 2020-11-23 05:29:41
回答 1查看 1.7K关注 0票数 1

我使用高级加密标准(AES)在浏览器中使用“cypto-js”加密字符串,并需要在服务器上使用节点“crypto”解密。

我可以单独使用'crypto‘加密/解密,但是当我试图使用'crypto.createDecipher’解密‘密码’(Node)时,我会得到错误消息,结果是‘坏解密’或‘错误块大小’取决于我尝试的内容。

例句:只使用‘密码-js’-很好。

代码语言:javascript
复制
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‘解码密码-结果是错误的

代码语言:javascript
复制
[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

我试过:

  • 将解密中的加密算法更改为192或其他(但“crypto-js”文档(例如默认值为'256‘)是密码。
  • 客户端上的base64编码。也尝试过十六进制编码

例:

代码语言:javascript
复制
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)
  • 我使用的是'crypto.createDecipher‘而不是'crypto.createDecipheriv’,因为在这个项目中我被困在使用NodeV8.12.0

我想就这样.我很感谢你的帮助和建议!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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):

代码语言:javascript
复制
// 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'));
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

服务器端解密的示例实现(NodeJS):

代码语言:javascript
复制
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 dog
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64962999

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档