为什么使用相同的AES算法和CryptoJS与节点内置加密模块之间的相同密钥加密结果是不同的

时间:2016-08-11 10:37:10

标签: node.js encryption cryptojs

我正在使用Node.js开发服务器,使用Ionic框架开发客户端

我为来自客户端的登录请求制作了API

当客户端请求登录时,发送加密的id和密码字符串

和服务器解密收到的id和密码字符串并检查验证

我使用crypto-js(https://code.google.com/archive/p/crypto-js/)库进行客户端加密

下面的客户端加密代码

var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "someId";
var encrypted = CryptoJS.AES.encrypt(id, password);
console.log(encrypted.toString());  // U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU=

对于服务器端解密,我使用了node built-in crypto module

const crypto = require('crypto');
var method = 'aes256';
var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU=" // suppose we received with no loss
var decipher = crypto.createDecipher(method, secret);
decipher.update(id,'base64','utf8');
var deciphered = decipher.final('utf8');
console.log(deciphered);

服务器端解密代码崩溃,错误消息在

下面
crypto.js:153
  var ret = this._handle.final();
                         ^

Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
    at Error (native)
    at Decipher.Cipher.final (crypto.js:153:26)
    at Object.<anonymous> (...\routes\index.js:33:27)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (...\app.js:18:14)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)

由于错误消息是“解密错误”,因此我尝试使用每个库加密相同的文本

[加密JS]

var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "someId";
var encrypted = CryptoJS.AES.encrypt(id, password);
console.log(encrypted.toString());  // U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU=

[加密模块]

const crypto = require('crypto');
var method = 'aes256';
var secret = 'abcdefghijklmnopqrstuvwxyz123456';
var id = "someId" 
var cipher= crypto.createCipher(method, secret);
cipher.update(id,'base64','utf8');
var ciphered = decipher.final('utf8');
console.log(ciphered.toString()); // WAsd61C2bfG7UbO5STo13A==

我发现图书馆的结果不同

plain text : 'someId'
crpyto-js  : 'U2FsdGVkX19EfjjBwydSZL509wKl5TEX+4f3vakEejU='
crpyto module : 'WAsd61C2bfG7UbO5STo13A=='

我试图理解每个库的源代码

但它太复杂了,我无法理解

我想知道每个库的加密是如何工作的以及导致不同结果的原因

2 个答案:

答案 0 :(得分:0)

您正在使用两个可能具有不同默认值的不同系统。不要依赖默认值,而是明确指定双方的所有内容相同。即使最小的东西不匹配,加密也会失败。您需要指定使用的字符到字节映射,加密模式,IV(如果需要),密钥和填充方法。

你的不同输出是不同的长度,所以最初我怀疑填充是第一个要看的东西。将两侧设置为PKCS#7填充,看看是否有帮助。

为了进一步诊断,检查每侧的密钥和IV 逐字节是否相同。

答案 1 :(得分:0)

必须指定所有参数并且正确无误。不依赖于默认值,它们是依赖于实现的,并且将在实现之间进行。

一般来说,你应该使用:

  1. CBC模式随机iv,加密时创建随机iv,将其添加到加密数据中以供解密使用。对于AES,iv应为16字节,即块大小。不要使用ECB模式,这是不安全的,请参阅ECB mode,向下滚动到企鹅。

  2. PKCS#7填充(有时称为PKCS#5)。这是必需的,因为AES是块密码,输入和输出必须是块大小的精确倍数。此填充将在加密期间自动添加,并在解密期间删除。

  3. 确保iv和键完全正确的大小。

  4. 用于调试以十六进制显示所有输入和输出。在调试期间,在加密和解密之前和之后转储所有输入和输出会很有帮助。十六进制允许人们看到每个字节,Base64将3个字节组合成4个字节,使其更难理解。

  5. 当所有这些完全相同时,输出也将完全相同。