密码学很有趣。这里是解密带有盐的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(''));
更新:有关CBC模式以及OpenSSL如何工作的更多细节。
如果您查看密码块链接模式中的流密码的工作方式,您会注意到加密数据需要两个初始值:初始化向量(IV)和密钥。重要的是,初始化向量的大小应该等于块大小,而密钥大小取决于算法,对于AES-256,它的长度为256位。
但是用户不希望设置256位的随机密码来访问其数据。这引发了一个问题,即如何从用户输入构造密钥和IV。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
这里的“key”和“iv”参数是密码的输入参数,“salt”用于随机化密文,以便对于相同的数据不会生成相同的密文。
OpenSSL将数据保存在文件中,如下所示:
Saltet__
因此,要解密它,应执行以下步骤:
- 跳过“Salted”前缀
- 读取输入的8个字节并保存为盐
- 从密码和盐构造密钥和向量
- 使用计算出的密钥和向量应用AES-256-CBC解密器来解密文件的其余部分
上面的代码执行这些步骤并解密文件。
openssl
的-nosalt
选项可以解决这个问题。不过我不知道Node是否已经支持盐了。 - robertklep