Question:
Hello, I’m trying to decrypt my encoded base64 with the following command:
echo "base64key" | (openssl enc -AES-256-cbc -d -a -pass "pass:test" -pbkdf2 -iter 100000 -md sha256 -p; echo) | tee >(hexdump -C)
The base64 key originates from the following JavaScript code:
const crypto = require('crypto');
const passphrase = 'test';
const iterations = 100000;
const keyLength = 32;
const saltLength = 8;
const ivLength = 16;
let salt = crypto.randomBytes(saltLength);
let key = crypto.pbkdf2Sync(passphrase, salt, iterations, keyLength, 'sha256');
let iv = crypto.randomBytes(ivLength);
console.log("Salt size: ",salt.length + " bytes");
console.log("Key size: ",key.length + " bytes");
console.log("IV size: ",iv.length +" bytes");
const dataToEncrypt = 'its a secret!';
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encryptedData = cipher.update(dataToEncrypt, 'utf8', 'base64');
encryptedData += cipher.final('base64');
const saltedPrefix = Buffer.from('Salted__');
const prefixedData = Buffer.concat([saltedPrefix, salt, iv, Buffer.from(encryptedData, 'base64')]);
console.log("Result HEX: ", prefixedData.toString('hex'));
const encrypted = prefixedData.toString('base64');
/* FINAL SIZE */
console.log("Result size: ", encrypted.length +" bytes");
/* RESULT LOG */
console.log('Base64 encrypted: ' + encrypted);
output of the javascript:
Salt size: 8 bytes
Key size: 32 bytes
IV size: 16 bytes
Result HEX: 53616c7465645f5f2d920c9fc07a1131ff26f94a8e2b8110691e022c824f9251256f28e1533a4dfcb7eda2ae5f665809
Result size: 64 bytes
Base64 encrypted: U2FsdGVkX18tkgyfwHoRMf8m+UqOK4EQaR4CLIJPklElbyjhUzpN/Lftoq5fZlgJ
On my linux server now,
The output of the command is the following:
command:
echo "U2FsdGVkX18tkgyfwHoRMf8m+UqOK4EQaR4CLIJPklElbyjhUzpN/Lftoq5fZlgJ" | (openssl enc -AES-256-cbc -d -a -pass "pass:test" -pbkdf2 -iter 100000 -md sha256 -p; echo) | tee >(hexdump -C)
output:
salt=2D920C9FC07A1131
key=C4B6F8A9A1DA258846E066D8B3D4A7028922376D87DC898255C8DE64DD994E09
iv =F7369730119C2461AB0A6CA1B8D3015D
▒▒f/B>▒=O▒▒琰its a secret!
00000000 73 61 6c 74 3d 32 44 39 32 30 43 39 46 43 30 37 |salt=2D920C9FC07|
00000010 41 31 31 33 31 0a 6b 65 79 3d 43 34 42 36 46 38 |A1131.key=C4B6F8|
00000020 41 39 41 31 44 41 32 35 38 38 34 36 45 30 36 36 |A9A1DA258846E066|
00000030 44 38 42 33 44 34 41 37 30 32 38 39 32 32 33 37 |D8B3D4A702892237|
00000040 36 44 38 37 44 43 38 39 38 32 35 35 43 38 44 45 |6D87DC898255C8DE|
00000050 36 34 44 44 39 39 34 45 30 39 0a 69 76 20 3d 46 |64DD994E09.iv =F|
00000060 37 33 36 39 37 33 30 31 31 39 43 32 34 36 31 41 |7369730119C2461A|
00000070 42 30 41 36 43 41 31 42 38 44 33 30 31 35 44 0a |B0A6CA1B8D3015D.|
00000080 f6 db 66 2f 01 42 3e 80 3d 4f 9d c5 04 e7 90 b0 |..f/.B>.=O......|
00000090 69 74 73 20 61 20 73 65 63 72 65 74 21 0a |its a secret!.|
0000009e
As you can see, the secret is there, but there’s a jumbled words behind it, how can I make this work without those characters?
I’m using prefix "Salted__" because it seems its needed for the OpenSSL decryption in this case.
I’m really struggling on this, anyone got any ideas?
2
Answers
I have found the solution.
In In AES-256-CBC encryption, you need both a key and an IV, and by concatenating these two lengths
(keyLength + ivLength)
, you ensure that thecrypto.pbkdf2Sync
function generates a single buffer that contains both the key and the IV, with the key occupying the first keyLength bytes of the buffer and the IV occupying the next ivLength bytes.This can then be read by the openssl command without the need to specify the
-iv
In the JavaScript code, the IV is not determined from the key derivation function (PBKDF2), instead a random IV is generated.
The encrypted data consists of the concatenation of the ASCII encoding of
Salted__
, followed by the 8 bytes salt, followed by the 16 bytes IV and finally the actual ciphertext:In contrast, openssl enc -d requires the encrypted data in the following order: ASCII encoding of
Salted__
, followed by the 8 bytes salt and finally the actual ciphertext, i.e. the IV is not included:which corresponds Base64 encoded to:
In addition, the IV is derived together with the key using the key derivation function. Alternatively, the IV can be specified with the -iv option, which must be followed by the hex encoded IV. The latter is required here:
Overall the fixed OpenSSL statement is:
This then returns the original plaintext
its a secret!
.