首页 > 解决方案 > Nodejs createCipheriv 像 openssl

问题描述

MariaDB 的静态加密依赖于 openssl 对 keys.txt 文件 ( https://mariadb.com/kb/en/library/encryption-key-management/#encrypting-the-key-file ) 的 sha1 加密。我需要使用 Node.js 启动一个 MariaDB 实例。所以,我需要使用 Node.js 以类似的方式加密这个文件。到目前为止,使用https://github.com/beeven/gulp-openssl-encrypt作为指南,我已经能够复制 openssl 的-md md5. 但这不是 MariaDB 所需的 sha1 摘要。

function md5(data) {
  let hash = crypto.createHash('md5');
  hash.update(data);
  return hash.digest();
}
const buffer = Buffer.from(stringToEncrypt);
const salt = crypto.randomBytes(8);
const password = Buffer.from(encryptionKey);
const hash1 = md5(Buffer.concat([password, salt]));
const hash2 = md5(Buffer.concat([hash1, password, salt]));
const key = Buffer.concat([hash1, hash2]);
const iv = md5(Buffer.concat([hash2, password, salt]));
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
const chunks = [Buffer.from('Salted__'),salt];
chunks.push(cipher.update(buffer));
chunks.push(cipher.final());
let encryptedStuff = Buffer.concat(chunks);

(编辑:澄清)我想要的是这样的:

function sha1(data) {
  let hash = crypto.createHash('sha1');
  hash.update(data);
  return hash.digest();
}
const buffer = Buffer.from(stringToEncrypt);
const salt = crypto.randomBytes(8);
const password = Buffer.from(encryptionKey);
const hash1 = sha1(Buffer.concat([password, salt]));
const hash2 = sha1(Buffer.concat([hash1, password, salt]));
const key = Buffer.concat([hash1, hash2]);
const iv = sha1(Buffer.concat([hash2, password, salt]));
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
const chunks = [Buffer.from('Salted__'),salt];
chunks.push(cipher.update(buffer));
chunks.push(cipher.final());
let encryptedStuff = Buffer.concat(chunks);

但是当我尝试这样做时,密钥和 iv 变得太长,并且出现“无效密钥长度”错误。因此,当我尝试按照https://github.com/nodejs/node/issues/6696的建议对其进行切片时,它确实对其进行了加密,但 openssl 无法对其进行解密。

标签: node.jsencryptionopensslcryptographymariadb

解决方案


For details on the OpenSSL password-based encryption scheme used for enc namely EVP_BytesToKey, see https://crypto.stackexchange.com/questions/3298/is-there-a-standard-for-openssl-interoperable-aes-encryption

AES-256 in CBC mode requires 48 octets for key+IV and SHA1 output is 20 octets, so you must:

// do three hashes, much as you already have
hash1 = sha1(Buffer.concat([password, salt]));
hash2 = sha1(Buffer.concat([hash1, password, salt]));
hash3 = sha1(Buffer.concat([hash2, password, salt]));

// then concatenate them and split _that_ to key and IV 
total = Buffer.concat([hash1,hash2,hash3]);
key = total.slice(0,32);
iv = total.slice(32,48);

For md5 treating them separately worked because it happens MD5 output of 16 octets is exactly half the key size and exactly the IV size.


推荐阅读