密码学很有趣。下面是用 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(''));
Update:有关什么是 cbc 模式以及 openssl 如何工作的更多详细信息
如果您查看流加密方式密码块链接模式 http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29在工作中,您会注意到密码需要两个初始值来开始加密数据:初始化向量 (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”是密码的输入参数,并且需要盐来随机化密文,因此对于相同的数据,它不会相同。
openssl将数据保存在文件中,如下:
Saltet__;[salt][cipher-text]
因此,要解密它,应执行以下步骤:
- 应跳过“Salted”前缀
- 应读取输入的 8 个字节并将其保存为 salt
- 应该根据密码和盐构造密钥和 iv
- 文件的其余部分应通过应用带有计算密钥和 iv 的 AES-256-CBC 解密器来解密
上面的代码执行这些步骤并解密文件。