I'm trying to decrypt a file encrypted with openssl using CryptoJS 3.1.5.
Everything works fine if I encrypt and decrypt using CryptoJS, same goes for OpenSSL in shell, but when I try to mix CryptoJS with OpenSSL everything goes wrong.
The file is created using this command:
openssl enc -aes-256-cbc -in file.txt -out file.enc -k password
and I try to decrypt like this:
fs.readFile('file.enc', function(err, data) {
var decrypted = CryptoJS.AES.decrypt(
data.toString(),
"password",
{ mode : CryptoJS.mode.CBC }
);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
});
// Give me this err: Uncaught Error: Malformed UTF-8 data
And in the other way, I do :
fs.readFile('file.txt', function(err, data) {
var encrypted = CryptoJS.AES.encrypt(
data.toString(),
"password",
{ mode : CryptoJS.mode.CBC });
fs.writeFile('file.enc', encrypted);
});
And then in Shell:
openssl enc -d -aes-256-cbc -in file.enc -out file2.txt -k password
// Give me this err: bad magic number
Am I missing something obvious ?
Not definitely an answer yet but too much for comments:
Commandline openssl enc
by default uses password-based encryption (PBE) with salt, which means the actual encryption key, and IV when applicable which it is for CBC, are computed from the given password and a random salt value by a Password Based Key Derivation Function that makes it more difficult for an adversary to try password-guessing attacks. I don't know your JS module (or much JS at all) but the webpage you link lists a variety of low-level primitives suggesting it does not automatically do PBE. A text string like "password" is (possibly) suitable for PBE, but not direct AES encryption where the key must be exactly 128, 192 or 256 bits and should be random binary data.
If you want openssl's semi-standard PBE, match it on the JS side; the item evpkey
sounds possibly helpful, since EVP
is the openssl module involved and I know no other (PB)KDF scheme that would be called EVP. If not, the enc
default PBE is just MD5 of the password concatenated with the salt, iterated with feedback as many times as needed which in this case is three. See https://superuser.com/questions/455463/openssl-hash-function-for-generating-aes-key for an example in (mostly) perl. OpenSSL prefixes the 8 ASCII chars "Salted__" and the 8 bytes of salt to the file, so you need to remove those (and use the salt) before decrypt, or add them after encrypt.
If you want raw encryption, choose a more suitable key (on whichever side), and a unique and unpredictable IV unless you always use a new key in which case you can use a fixed IV, and on the openssl side use -K
(note uppercase) and -iv
to specify those values in hex. See the manpage on any Unix system with openssl installed or https://www.openssl.org/docs/manmaster/apps/enc.html .
Plus in either case enc
defaults to "PKCS#5" (really PKCS#7) padding. I don't know if your JS module does; if not you should specify it. Unless you can guarantee your plaintexts will always be an exact multiple of 16 bytes (after any encoding like UTF8); then you could specify (or maybe default) no padding on the JS side and specify -nopad
on the openssl side.