首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用CTR模式对加密js加密和节点密码解密

使用CTR模式对加密js加密和节点密码解密
EN

Stack Overflow用户
提问于 2019-09-13 19:14:20
回答 2查看 1.7K关注 0票数 0

我试图使用crypto javascript库加密数据,并试图使用节点密码库在nodejs端解密相同的加密文本。我使用AES 256加密algo与CTR模式,没有填充。我能够正确地加密,但是nodejs密码模块上的描述并不能产生相同的纯文本。

如果我试图使用相同的密码-js和节点密码库加密或解密,它可以正常工作,但加密对加密js和对密码的描述并不像预期的那样工作。我试着确认我是否在同一个库中加密和解密,而不是它是否工作,而且它运行得非常好。有人能检查一下我在这里犯了什么错误吗?

请找到下面的代码样本。

加密:

代码语言:javascript
复制
var key =  CryptoJS.enc.Hex.parse('F29BA22B55F9B229CC9C250E11FD4384');
var iv  =  CryptoJS.enc.Hex.parse('C160C947CD9FC273');


function encrypt(plainText) {

  return CryptoJS.AES.encrypt(                                               
                                plainText,                                           
                                key,
                                { 
                                    iv: iv,
                                    padding: CryptoJS.pad.NoPadding,
                                    mode:  CryptoJS.mode.CTR
                                }
                              );                             
}

使用NodeJS加密模块的解密码:

代码语言:javascript
复制
var algorithm = 'aes-256-ctr';
var key = 'F29BA22B55F9B229CC9C250E11FD4384';
var iv = 'C160C947CD9FC273';

var outputEncoding = 'hex';
var inputEncoding = 'hex';

const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update('8df5e11f521cf492437a95', inputEncoding, 'utf8');
decrypted += decipher.final('utf8');

console.log(decrypted);

正如我前面提到的,如果我使用相同的lib加密和解密,JavaScript密码-js和NodeJS密码模块会话就可以正常工作,但否则就不能工作。请检查工作代码如下。

JavaScript:R/2 qwt8jsh/2/

NodeJS:https://repl.it/repls/AchingRegalPhp

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-13 20:19:52

与NodeJS (Crypto)不同,JavaScript (CryptoJS)将键和IV解释为十六进制字符串。因此,在JavaScript-128和NodeJS 256中使用.为了解决这个问题,这两个代码必须使用相同的加密。

选项1:将JavaScript代码更改为AES-256:在JavaScript代码中替换

代码语言:javascript
复制
var key = CryptoJS.enc.Hex.parse('F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Hex.parse('D959B836CD9FB162');

通过

代码语言:javascript
复制
var key = CryptoJS.enc.Utf8.parse('F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Utf8.parse('D959B836CD9FB162');

选项2:将NodeJS-代码更改为AES-128:在NodeJS-代码中替换

代码语言:javascript
复制
var algorithm = 'aes-256-ctr';    
var key = 'F18AB33A57F9B229CC9C250D00FC3273';
var iv = 'D959B836CD9FB162';

通过

代码语言:javascript
复制
var algorithm = 'aes-128-ctr';
var key = Buffer.from('F18AB33A57F9B229CC9C250D00FC3273', 'hex');
var iv = Buffer.from('D959B836CD9FB1620000000000000000', 'hex');

通过两个变化中的每一个,两个链接的代码产生相同的结果。

如果应该使用AES-256,并将key和IV指定为十六进制字符串,则必须使用相应的大键和大键,例如在JavaScript端:

代码语言:javascript
复制
var key = CryptoJS.enc.Hex.parse('F18AB33A57F9B229CC9C250D00FC3273F18AB33A57F9B229CC9C250D00FC3273');
var iv = CryptoJS.enc.Hex.parse('D959B836CD9FB16200000000000000'); 

在NodeJS方面:

代码语言:javascript
复制
var algorithm = 'aes-256-ctr';
var key = Buffer.from('F18AB33A57F9B229CC9C250D00FC3273F18AB33A57F9B229CC9C250D00FC3273', 'hex');
var iv = Buffer.from('D959B836CD9FB1620000000000000000', 'hex');
票数 0
EN

Stack Overflow用户

发布于 2019-09-13 21:26:44

我认为您的CryptoJS代码没有使用AES-256,因为键和IV太短,因此它隐含地使用AES-128。如果您从blockSize对象获得CryptoJS.AES,它为我指定了4。这就是说,我对CryptoJS不太了解,这可能并不意味着“四个字”。

为了避免这种实现的不确定性,最好有一个“金本位”来复制。NIST提供了大量的测试向量,其中一些应用于您的CTR模式AES-256。首先,我从该文档中提取一组(十六进制编码的)测试向量:

代码语言:javascript
复制
const key = (
  '603deb1015ca71be2b73aef0857d7781' +
  '1f352c073b6108d72d9810a30914dff4'
)
const ctr = 'f0f1f2f3f4f5f6f7f8f9fafbfcfdff00'

const output = '5a6e699d536119065433863c8f657b94'
const cipher = 'f443e3ca4d62b59aca84e990cacaf5c5'
const plain = 'ae2d8a571e03ac9c9eb76fac45af8e51'

接下来,我尝试从模块中恢复这些

代码语言:javascript
复制
const crypto = require('crypto')

function node_crypto(text) {
  const dec = crypto.createDecipheriv(
    'aes-256-ctr',
    Buffer.from(key, 'hex'),
    Buffer.from(ctr, 'hex')
  );
  const out = dec.update(Buffer.from(text, 'hex'))
  return out.toString('hex')
}

现在,我可以编写一个简单的测试工具来测试上面的内容,并将它与该函数一起使用:

代码语言:javascript
复制
const zero = '00'.repeat(16);
function test_crypto(fn) {
  return {
    'zero => output': fn(zero) == output,
    'cipher => plain': fn(cipher) == plain,
    'plain => cipher': fn(plain) == cipher,
  }
}

console.log(test_crypto(node_crypto))

这给了我所有测试的true

最后,CryptoJS的等效代码是:

代码语言:javascript
复制
const CryptoJS = require("crypto-js");

function cryptojs(text) {
  const out = CryptoJS.AES.encrypt(
    CryptoJS.enc.Latin1.parse(Buffer.from(text, 'hex').toString('binary')),
    CryptoJS.enc.Hex.parse(key),
    {
      iv: CryptoJS.enc.Hex.parse(ctr),
      mode:  CryptoJS.mode.CTR,
      padding: CryptoJS.pad.NoPadding,
    }
  );

  return out.ciphertext.toString();
}

console.log(test_crypto(cryptojs))

这对我也有用。

需要注意的是,CryptoJS只是默默地接受任意大小的键,文档中这样说:

CryptoJS支持AES-128、AES-192和AES-256.它将根据您传入的键的大小来选择变体。如果您使用密码,那么它将生成一个256位的密钥.

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57929210

复制
相关文章

相似问题

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