为什么我不能使用openssl加密的NodeJS解密文件?

flo*_*low 4 encryption node.js

我使用命令行加密文件

openssl aes-256-cbc -in /tmp/text.txt -out /tmp/text.crypt
Run Code Online (Sandbox Code Playgroud)

我然后尝试使用以下JavaScript代码解密它:

crypto        = require( 'crypto' );
cipher_name   = 'aes-256-cbc';
password      = '*';
decoder       = crypto.createDecipher( cipher_name, password );
text_crypt    = njs_fs.readFileSync( '/tmp/text.crypt' );
chunks        = [];
chunks.push decoder.update( text_crypt, 'binary' );
chunks.push decoder.final( 'binary' );
text          = chunks.join( '' ).toString( 'utf-8' );
Run Code Online (Sandbox Code Playgroud)

这失败了

TypeError: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Ale*_*hov 11

密码学很有趣.下面是使用salt解密用openssl加密的文件的代码.

var crypto = require('crypto');

function md5(data) {
    var hash = crypto.createHash('md5');
    hash.update(data);
    return new Buffer(hash.digest('hex'), 'hex');
}

var text = require('fs').readFileSync('text.crypt');
var salt = text.slice(8, 16);
var cryptotext = text.slice(16);
var password = new Buffer('*');

var hash0 = new Buffer('');
var hash1 = md5(Buffer.concat([ hash0, password, salt ]));
var hash2 = md5(Buffer.concat([ hash1, password, salt ]));
var hash3 = md5(Buffer.concat([ hash2, password, salt ]));
var key = Buffer.concat([ hash1, hash2 ]);
var iv = hash3;

var decoder = crypto.createDecipheriv('aes-256-cbc', key, iv);

var chunks = [];
chunks.push(decoder.update(cryptotext, "binary", "utf8"));
chunks.push(decoder.final("utf8"));
console.log(chunks.join(''));
Run Code Online (Sandbox Code Playgroud)

更新:有关什么是cbc模式以及openssl如何工作的更多详细信息

如果您查看密码块链接模式中的流密码如何工作,您会注意到密码需要两个初始值才能开始加密数据:初始化向量(iv)和密钥.重要的是初始化矢量的大小应该等于块大小,密钥大小取决于算法,对于AES-256,它是256位长.

但用户不希望设置256位随机密码来访问其数据.这打开了一个关于如何构造密钥的问题,并且从用户的输入开始,并且openssl通过将EVP_BytesToKey函数应用于用户输入来解决它,实际上MD5应用于密码和盐多次.

您可以通过执行来查看派生值

C:\Tools\wget>openssl enc -aes-256-cbc -P
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
salt=A94B7976B2534923
key=C8B806C86E60ED664B9C369628D1A78260753580D78D09EAEC04EAC1535077C3
iv =7B6FB26EB62C34F04F254A0C4F4F502A
Run Code Online (Sandbox Code Playgroud)

参数"key和"iv"这里是密码的输入参数,盐需要随机化密码文本,因此对于相同的数据它将不相同.

openssl将数据保存在文件中,如下所示:

Saltet__;[salt][cipher-text]
Run Code Online (Sandbox Code Playgroud)

因此,为了解密它,应该执行以下步骤:

  1. 应跳过"Salted"前缀
  2. 应读取8个字节的输入并保存为salt
  3. 从密码和盐密钥和iv应该构建
  4. 应该通过AES-256-CBC解密器和计算密钥和iv来解密文件的其余部分

上面的代码执行这些步骤并解密文件.