-
-
Save schakko/2628689 to your computer and use it in GitHub Desktop.
// Doing AES-256-CBC (salted) decryption with node.js. | |
// This code is based on http://php.net/manual/de/function.openssl-decrypt.php and works with PHP sqAES. | |
// | |
// Create your encrypted data with | |
// echo -n 'Hello world' | openssl aes-256-cbc -a -e | |
var crypto = require('crypto'); | |
var password = 'password'; | |
var edata = 'U2FsdGVkX18M7K+pELP06c4d5gz7kLM1CcqJBbubW/Q='; | |
var data = new Buffer(edata, "base64"); | |
console.log("Data (Base64): " + data ); | |
var salt = data.toString("binary", 8, 16); | |
console.log("Salt (Base64): " + new Buffer(salt, "binary").toString("base64")); | |
var ct = data.toString("binary", 16); | |
console.log("Content (Base64): " + new Buffer(ct, "binary").toString("base64")); | |
var rounds = 3; | |
var data00 = password + salt; | |
console.log("Data00 (Base64): " + new Buffer(data00, "binary").toString("base64")); | |
md5_hash = new Array(); | |
md5_hash[0] = crypto.createHash("md5").update(data00).digest("binary"); | |
var result = md5_hash[0]; | |
console.log("MD5-Hash[0] (Base64): " + new Buffer(result, "binary").toString("base64")); | |
for (i = 1; i < rounds; i++) { | |
md5_hash[i] = crypto.createHash("md5").update(md5_hash[i - 1] + data00).digest("binary"); | |
result += md5_hash[i]; | |
console.log("Result (Base64): " + new Buffer(result, "binary").toString("base64")); | |
} | |
key = result.substring(0, 32); | |
console.log("Key (Base64): " + new Buffer(key, "binary").toString("base64")); | |
var iv = result.substring(32, (32 + 16)); | |
console.log("IV (Base64): " + new Buffer(iv, "binary").toString("base64")); | |
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); | |
var content = decipher.update(ct, "binary", "utf8"); | |
content += decipher.final("utf8"); | |
console.log("Decrypted: " + content); |
<?php | |
// Doing AES-256-CBC (Salted) decryption with PHP | |
// This code is based on http://php.net/manual/de/function.openssl-decrypt.php and adds only some comments | |
// | |
// Create your encrypted data with | |
// echo -n 'Hello world' | openssl aes-256-cbc -a -e | |
$password = 'password'; | |
$edata = 'U2FsdGVkX18M7K+pELP06c4d5gz7kLM1CcqJBbubW/Q='; | |
$data = base64_decode($edata); | |
print "Data: " . $data . "\n"; | |
$salt = substr($data, 8, 8); | |
print "Salt (Base64): " . base64_encode($salt) . "\n"; | |
$ct = substr($data, 16); | |
print "Content (Base64): " . base64_encode($ct) . "\n"; | |
$rounds = 3; | |
$data00 = $password.$salt; | |
print "Data00 (Base64): " . base64_encode($data00) . "\n"; | |
$md5_hash = array(); | |
$md5_hash[0] = md5($data00, true); | |
$result = $md5_hash[0]; | |
print "MD5-Hash[0] (Base64): " . base64_encode($result) . "\n"; | |
for ($i = 1; $i < $rounds; $i++) { | |
$md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true); | |
$result .= $md5_hash[$i]; | |
print "Result (Base64): " . base64_encode($result) . "\n"; | |
} | |
$key = substr($result, 0, 32); | |
print "Key (Base64): " . base64_encode($key) . "\n"; | |
$iv = substr($result, 32, 16); | |
print "IV (Base64): " . base64_encode($iv) . "\n"; | |
print "Decrypted: " . openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv); |
You're a lifesaver, thanks dude.
The code need to update:
hash.update(data[, inputEncoding])
Version | Changes |
---|---|
v6.0.0 | The default inputEncoding changed from binary to utf8. |
v0.1.92 | Added in: v0.1.92 |
After nodejs v6.0.0, the default encoding of Hash#update changed from 'binary' to 'utf8'.
When calculate the hash, encoding must be explicit as 'binary'.
md5_hash[0] = crypto.createHash("md5").update(data00).digest("binary");
==>
md5_hash[0] = crypto.createHash("md5").update(data00, 'binary').digest("binary");
I also suggest the debug as hex not base64, so it's easier to debug with the openssl command line utils.
$ cat input.txt | openssl aes-256-cbc -a -salt -k hello -p -out input.txt.enc
salt=C97734D83EDAFD8D
key=67B99E14801776F828D1614328653BDD02A706EC74B772F362BB5517D2BE1B37
iv =07EAEDD9CC7E4577957FE314C589E361
Original implementation no longer works. I've rewrote everything using modern JS:
"use strict";
// This will decrypt output of: echo -n 'Hello world' | openssl aes-256-cbc -a -e -k julius -p -md md5
const crypto = require("crypto");
function aesDecrypt(message, secret) {
const TRANSFORM_ROUNDS = 3;
const cypher = Buffer.from(message, "base64");
const salt = cypher.slice(8, 16);
const password = Buffer.concat([Buffer.from(secret, "binary"), salt]);
const md5Hashes = [];
let digest = password;
for (let i = 0; i < TRANSFORM_ROUNDS; i++) {
md5Hashes[i] = crypto.createHash("md5")
.update(digest)
.digest();
digest = Buffer.concat([md5Hashes[i], password]);
}
const key = Buffer.concat([md5Hashes[0], md5Hashes[1]]);
const iv = md5Hashes[2];
const contents = cypher.slice(16);
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
return decipher.update(contents) + decipher.final();
}
console.log(aesDecrypt("U2FsdGVkX196b1K93xH6y0aSOTJmR5w9ofQDeDyIq3w=", "julius"));
Thank you for showing me clues!
When I try echo -n 'Hello world' | openssl aes-256-cbc -a -e -k julius -p -md md5
,
OpenSSL warned me:
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
The old manner has been deprecated since OpenSSL 1.1.1.
I looked into about pbkdf2.
And then RTFM (where is the fine manual?)
My references are as follow:
- Openssl CLI memo#Key derivation
- Decrypt openssl AES 256 CBC in browser/CryptoJS#Answer 1
- How to decrypt using openssl EVP?
- Node.js Document
The result is:
'use strict';
const crypto = require('crypto');
// echo -n 'message to encrypt' | openssl aes-256-cbc -a -e -k <PASSPHRASE> -pbkdf2 -p
function dec(message, secret)
{
const cypher = Buffer.from(message, "base64");
// eat up 'Salted__'
const salt = cypher.slice(8, 16);
// iteration: "10000", hash algorithm: "sha256" by default
// you can change the values with -iter and -md options
// rv: key(aes256 key length 32-Byte) + iv(aes256 iv length 16-Byte)
const key_iv = crypto.pbkdf2Sync(secret, salt, 10000, 32+16, 'sha256');
const key = key_iv.slice(0,32);
const iv = key_iv.slice(32);
const contents = cypher.slice(16);
const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
return decipher.update(contents) + decipher.final();
}
// echo -n '<CYPHERTEXT_IN_BASE64>' | node thiscode.js
if (require.main === module) {
const buf = [];
process.stdin.on('data', data => {
buf.push(data);
});
process.stdin.on('end', () => {
const cyphertext = buf.join('');
const plaintext = dec(cyphertext, '<PASSPHRASE>');
console.log(plaintext);
});
}
could you also provide the node.js encrypt function that the openssl can decrypt as well? Thanks!
i.e.
encrypt-from-nodejs.js | openssl aes-256-cbc -base64 -a -d -k password