当用node-forge的AES impl加密、解密、然后重新加密一个字符串时,为什么加密和重新加密的字符串是不同的?

j7dteeu8  于 2022-12-12  发布在  Node.js
关注(0)|答案(1)|浏览(258)

我尝试使用node-forge来解密由另一个应用程序加密的字符串。在解密后,我没有得到原来的字符串,所以我决定把下面的SSCCE放在一起,它加密一个字符串,解密它,然后重新加密它。我得到的结果没有意义。

  • 原始字符串:hi(十六进制等效值为6869)
  • 加密的十六进制字符串:7457
  • 解密的十六进制字符串:2b0a684b
  • 重新加密的十六进制字符串:2e5c6d1dc7cfa554
    问题

1.首先,我做错了什么?即,为什么解密的十六进制不同于原始的十六进制,为什么重新加密的十六进制不同于加密的十六进制?

  1. node-forge文档中的所有代码示例都得到了十六进制的解密输出。这是怎么回事?我想要返回纯文本,即'hi'。我如何请求库给予文本来代替(调用decypher.output.toString()会导致错误)。
    1.我的最终目标是能够解密的输出:echo -n "hi" | openssl enc -aes-256-ctr -K $(echo -n redacted12345678 | openssl sha256) -iv 1111111111111111 -a -A -nosalt使用一个javascript库。任何关于如何做到这一点的建议将非常感谢。

中学会考:

var forge = require('node-forge'); //npm install node-forge

//Inital data
var data = 'hi';
var iv = '1111111111111111';
var password = 'redacted12345678';

var md = forge.md.sha256.create();
md.update(password)
var keyHex = md.digest().toHex();
var key = Buffer.from(keyHex, 'hex').toString()

var cipher = forge.cipher.createCipher('AES-CTR', key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(data));
cipher.finish(); 
var encrypted = cipher.output.toHex()

console.log("encrypted: " + encrypted) //encrypted: 7457

var decipher = forge.cipher.createDecipher('AES-CTR', key)
decipher.start({iv: iv});
decipher.update(forge.util.createBuffer(encrypted));
decipher.finish(); 
var decrypted = decipher.output.toHex()

console.log("decrypted: " + decrypted) //decrypted: 2b0a684b

var recipher = forge.cipher.createCipher('AES-CTR', key);
recipher.start({iv: iv});
recipher.update(forge.util.createBuffer(decrypted));
recipher.finish(); 
var reencrypted = recipher.output.toHex()

console.log("reencrypted: " + reencrypted) //reencrypted: 2e5c6d1dc7cfa554
5n0oy7gb

5n0oy7gb1#

我重写了您尝试模仿的OpenSSL命令,如下所示:

echo -n "hi" | openssl enc -aes-256-ctr \
    -K $(echo -n redacted12345678 | openssl sha256 -binary | xxd -p -c 256) \
    -iv $(echo -n 1111111111111111 | xxd -p) -a -A -nosalt

我所做的更改是由于以下原因:

  • openssl sha256命令生成的十六进制输出以(stdin)=为前缀(至少在我的发行版上是这样),所以我只是通过xxd运行了密码的二进制散列,以获得一个干净的十六进制字符串形式的密钥。
  • openssl enc命令要求IV为十六进制格式,因此我也通过xxd运行了它。(由于AES IV需要16个字节,因此您的命令将导致IV值为111111111111111100000000000000,我认为这不是您的目标。)

执行此命令将为加密字符串生成以下base64输出:

JAA=

为了复制相同的代码,我修改了JavaScript代码,如下所示:

const forge = require('node-forge');

const data = 'hi', iv = '1111111111111111', password = 'redacted12345678';

const key = forge.md.sha256.create().update(password).digest().getBytes();

const cipher = forge.cipher.createCipher('AES-CTR', key);
cipher.start({ iv });
cipher.update(forge.util.createBuffer(data));
cipher.finish(); 
const encryptedBytes = cipher.output.getBytes();
const encryptedBase64 = forge.util.encode64(encryptedBytes);

console.log("encrypted: " + encryptedBase64);

const decipher = forge.cipher.createDecipher('AES-CTR', key)
decipher.start({ iv });
decipher.update(forge.util.createBuffer(encryptedBytes));
decipher.finish(); 
const decryptedBytes = decipher.output.getBytes();
const decryptedString = forge.util.encodeUtf8(decryptedBytes);

console.log("decrypted: " + decryptedString);

const recipher = forge.cipher.createCipher('AES-CTR', key);
recipher.start({ iv });
recipher.update(forge.util.createBuffer(decryptedBytes));
recipher.finish(); 
const reencryptedBytes = recipher.output.getBytes();
const reencryptedBase64 = forge.util.encode64(reencryptedBytes);

console.log("reencrypted: " + reencryptedBase64);

生成匹配输出:

encrypted: JAA=
decrypted: hi
reencrypted: JAA=

从本质上讲,当整个加密/解密操作使用原始字节完成,并且在处理输入或呈现输出时仅从/向十六进制、base64或UTF-8字符串转换时,一切都正常工作。

相关问题