【问题标题】:why encrypt result is different using same AES algorithm and same key between CryptoJS and node built-in crypto module为什么在 CryptoJS 和节点内置加密模块之间使用相同的 AES 算法和相同的密钥加密结果不同
【发布时间】:2016-12-18 01:15:31
【问题描述】:

我用 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=

对于服务器端解密,我使用了节点内置的加密模块

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)

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

[crypto-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=='

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

但是太复杂了,看不懂

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

【问题讨论】:

  • 我的这两个答案处理两个方向:CryptoJS to node.jsnode.js to CryptoJS
  • 您没有使用有效的 AES 密钥,因此两个系统都试图使其长度正确,显然采用不同的策略。
  • @dandavis 这正是不同之处。两者都没有使用任何密钥,但他们假设传递的“密钥”是密码,然后从密码中派生出实际的密钥。唯一的区别是 CryptoJS 使用随机盐,而 node.js 没有。这就是我在第一个链接背后的答案所说的。遗憾的是,我不能提出重复的建议。

标签: node.js encryption cryptojs


【解决方案1】:

所有参数必须指定且正确。不要依赖默认值,它们依赖于实现,并且在实现之间非常重要。

一般你应该使用:

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

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

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

  4. 用于调试以十六进制显示所有输入和输出。在调试过程中,在加密和解密之前和之后转储所有输入和输出会很有帮助。 16进制可以看到每个字节,Base64将3个字节组合成4个字节,比较难理解。

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

【讨论】:

    【解决方案2】:

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

    您的不同输出具有不同的长度,因此最初我怀疑填充是首先要查看的内容。将两边都设置为 PKCS#7 填充,看看是否有帮助。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-28
      • 2017-08-25
      • 2012-08-02
      • 1970-01-01
      • 2015-04-24
      • 2016-12-17
      • 2017-09-08
      相关资源
      最近更新 更多