Crypto-Js different output from mcrypt - javascript

I have a js script which encrypts data which is 'Blader'. If I encrypt it it returns an output of
JS-SCRIPT RESULT
uqnOrevjCc2YCvY3uKNjzA==
Now, being this answer as a base for comparison, I wrote or rather say searched for a equivalent script in PHP similar to my JS script. What confuses me is that the logic is fine and correct but the answer is different. On my php script which is by the uses mcrypt, I have this result in
mcrypt RESULT
HzfWFNKcAmkO6zJEYjbG4Q==
If you notice, the length are the same which means that the logic/modification on the code I did was correct. Now As i have said before I copied the script over some posts here.
Here's the JS Script which i think uses the crypto-JS
function crypto_encrypt(text) { //This is for JS
var keyBase64 = CryptoJS.enc.Base64.parse("ITU2NjNhI0tOc2FmZExOTQ==");
var iv = CryptoJS.enc.Base64.parse('AAAAAAAAAAAAAAAAAAAAAA==');
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(text), keyBase64,
{
keySize: 128 / 8,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
//padding: CryptoJS.pad.ZeroPadding
});
// Returns a Base64 encoded string.
return encrypted;
}
And here's the code I found in mcrypt/mycrypt
<?php
$encrypted = "Blader";
$iv = "0000000000000000"; // iv_base64 from JS
$key = hexdec("213536363361234b4e736166644c4e4d"); // key_base64 from JS
$plaintext = mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv );
echo base64_encode($plaintext);
?>
Now the question is, I tried from UTF8_encode upto everything base64_encode and decode but still can't find what's wrong and I'm curios that is this attainable or not since I notice that the IV from JS-Script is different from the IV in mcryp(PHP) everything I tried to echo it. Any advice, comments and suggestion will be highly be thanked.
Peace out.

First, you have to use exactly the same key and IV in PHP as you do in CryptoJS, or it's just not going to work. Did you compare values of the key and IV? They don't match.
Second, you have to use the same padding on each side. Did you check how MCrypt pads? It uses zero-padding. Your two plaintexts are different, because padding is part of the plaintext.
Finally, don't you want to use mcrypt_encrypt instead of mcrypt_decrypt here?
If you match the key and IV, and the padding, and encrypt in PHP, you'll get the same result (I've manually padded with \x0a -- 10 -- to match your PKCS#7 padding):
$encrypted = "Blader\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a";
$iv = base64_decode('AAAAAAAAAAAAAAAAAAAAAA==');
$key = base64_decode('ITU2NjNhI0tOc2FmZExOTQ==');
$plaintext = mcrypt_encrypt( MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv );
echo base64_encode($plaintext);
uqnOrevjCc2YCvY3uKNjzA==

Related

Crypto js decrypt from base64

I dealing with cryptojs and want to try a simple example with aes
var encrypted = CryptoJS.AES.encrypt("TEST_TEXT", '9021D105A446', {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
var decrypt = CryptoJS.AES.decrypt(encrypted, '9021D105A446', {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
console.log(decrypt.toString(CryptoJS.enc.Utf8));//Yeah! TEST_TEXT output as expected
Now I give a try with encrypted in base64, but not output as expected
var encryptedText = encrypted.ciphertext.toString(CryptoJS.enc.Base64)
var encrypted2 = CryptoJS.enc.Base64.parse(encryptedText);
var decrypt2 = CryptoJS.AES.decrypt(encrypted2, '9021D105A446', {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
console.log(decrypt2.toString(CryptoJS.enc.Utf8));// Ops! empty output
Do you know something went wrong with decryption in 2nd example?
Another question, every I run example 1, the encryptedText was difference from previous running. Is this normal behavior?
Fiddle update : https://jsfiddle.net/n6wL9a40/
You don't need to convert encrypted value to base64, encrypted.toString() returns base64 value.
var base64Value = encrypted.toString();
// base64Value is U2FsdGVkX19s42BDpx8A9I265vm+zGKSk8nEbQwNjfw=
var encryptedText = CryptoJS.enc.Base64.parse(base64Value)
var encrypted2 = encryptedText.toString(CryptoJS.enc.Base64);
var decrypt2 = CryptoJS.AES.decrypt(encrypted2, '9021D105A446', {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
console.log(decrypt2.toString(CryptoJS.enc.Utf8));// TEST_TEXT
First, actually CryptoJS.enc.Base64.parse(encryptedText) doesn't give you back a Base64 string, but an object, you should use it with toString like this: CryptoJS.enc.Base64.parse(encryptedText).toString() to get back your original string that was encoded in Base64
But the real problem is that you use the wrong part of the encrypted object (see linked fiddle, trying to decrypt .ciphertext won't work, because ciphertext is just the last part of the encrypted result needed for decryption, first part is missing). And additionally, there is no need to convert your output to Base64 at all, because it's already in Base64!
console.log(encrypted.toString()); //will already be Base64
See all this in an updated fiddle: https://jsfiddle.net/gqkcvjxo/
EDIT:
For your other question I quote the docs:
CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key
You can generate a key for AES-128 by using a pass of length 16 (128/8), you'll see in the fiddle that it works, the encrypted text length is halved.
var pass = 'abcdefghijklmnop'; //must be length 16 (because 128/8)
var key = CryptoJS.enc.Utf8.parse(pass);
Updated fiddle: https://jsfiddle.net/o3975jtd/3/
To answer your other question, the encrypted text is not the same each time in first version because of the generated iv (see explanation here). By using a key with AES-128 in ECB mode, the iv is not automatically generated and comes undefined (apparently, when trying to specify one, nothing changes, probably because it's not used as told in the explanation link)

Different Outputs for AES Encryption using CryptoJS and AES Encryption in JavaScript

Here is my solution to PHP, Ruby & Swift.
I faced issues when using CryptoJS on my test.
my code is like this
var data = "Hello World";
var key = "57119C07F45756AF6E81E662BE2CCE62";
var iv = "GsCJsm/uyxG7rBTgBMrSiA==";
var encryptedData = CryptoJS.AES.encrypt(data,
CryptoJS.enc.Hex.parse(key), {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Base64.parse(iv)
}
);
console.log("encryptedData: " + encryptedData);
// var crypttext = encryptedData.toString();
var crypttext = "k4wX2Q9GHU4eU8Tf9pDu+w==";
var decryptedData = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(crypttext)
}, CryptoJS.enc.Hex.parse(key), {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: CryptoJS.enc.Base64.parse(iv)
});
console.log("decryptedData: " + decryptedData);
console.log result
encryptedData: 97SwKfGtNARERiSYyZxdAQ==
decryptedData:
I've looked at your PHP code. You're using a 32 character key which is obviously Hex-encoded, but instead of decoding it to bytes, you're using the characters directly. Therefore the aes-256-cbc cipher is also wrong.
If you don't want to change your misleading PHP code, you can simply make the same mistake in CryptoJS: CryptoJS.enc.Utf8.parse(key) instead of CryptoJS.enc.Hex.parse(key).
Security considerations:
The IV must be unpredictable (read: random). Don't use a static IV, because that makes the cipher deterministic and therefore not semantically secure. An attacker who observes ciphertexts can determine when the same message prefix was sent before. The IV is not secret, so you can send it along with the ciphertext. Usually, it is simply prepended to the ciphertext and sliced off before decryption.
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.

AES encode in Delphi XE4 decode in Javascript

I would like to AES encode in Delphi XE4 and decode in JavaScript.
My Delphi code:
(I use DCPcrypt Cryptographic Component Library v2 Beta 3)
procedure TForm1.Button5Click(Sender: TObject);
var
Cipher : TDCP_rijndael;
key: Ansistring;
data: Ansistring;
iv: Ansistring;
begin
Key := SHA256('password');
IV := 'cd6f6eea9a2a59f2';
Data := '12345678901234567890';
Cipher := TDCP_rijndael.Create(Self);
if Length(Key) <= 16 then
Cipher.Init(Key[1], 128, #IV[1])
else
if Length(Key) <= 24 then
Cipher.Init(Key[1], 192, #IV[1])
else
Cipher.Init(Key[1], 256, #IV[1]);
Cipher.EncryptCBC(Data[1],Data[1],Length(Data));
memo1.Lines.Add('DATA_ENC:'+DATA);
memo1.Lines.Add('DATA_BASE64_ENC: '+Base64encode(DATA));
end;
My JavaScript code (I use CryptoJS):
encypted = 'Pz8/yw0/ck+4tTY/Pn8zPz/f9D8='; //input base64 text from Delphi routine
var key = CryptoJS.SHA256(CryptoJS.enc.Base64.parse("password"));
var iv = CryptoJS.enc.Base64.parse('cd6f6eea9a2a59f2');
var decrypted = CryptoJS.AES.decrypt(encrypted,key,
keySize: 256,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
console.log('DECRYPTED: '+decrypted.toString(CryptoJS.enc.Utf8));
I do not get back the original text, please help me. What is the matter?
I have no idea about Delphi, so I can't help you there, but I can say, that your Delphi code is wrong, because if you parse the Base64 ciphertext and encode it as Hex, you will see this:
3f3f3fcb0d3f724fb8b5363f3e7f333f3fdff43f
A ciphertext of a modern cipher is supposed to be indistinguishable from random noise, but this ciphertext looks rather regular (there are a lot of 0x3f bytes).
Your JavaScript code is rather all over the place. Almost every string that you use, has a wrong encoding.
run.onclick = function(){
var encrypted = CryptoJS.enc.Base64.parse(inVal.value);
var key = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse("password"));
var iv = CryptoJS.enc.Utf8.parse('cd6f6eea9a2a59f2');
var decrypted = CryptoJS.AES.decrypt({
ciphertext: encrypted
}, key, {
iv: iv,
padding: CryptoJS.pad.ZeroPadding
});
outHex.innerHTML = decrypted.toString();
outUtf8.innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
};
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/sha256.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/components/pad-zeropadding-min.js"></script>
<div>Base64 input: <input id="inVal" value="Pz8/yw0/ck+4tTY/Pn8zPz/f9D8="></div>
<div>Decrypted Hex: <span id="outHex">-</span></div>
<div>Decrypted Utf8: <span id="outUtf8">-</span></div>
<div><button id="run">Decrypt</button></div>
When you have fixed your Delphi code, you can include the Base64 in the above runnable snippet and see that decrypts correctly.
Security considerations:
You need to use a random IV, if you're sending multiple ciphertexts with the same key. If you send the same message again, an attacker can see that only by observing ciphertexts. The IV doesn't have to be secret, so you can send it along with the ciphertext. A common way is to prepend it to the ciphertext and remove it before decryption.
SHA-256 is not sufficient for key derivation from a low-entropy password. You should use an iterated key derivation function (KDF) such as PBKDF2, bcrypt, scrypt or Argon2. See more: How to securely hash passwords?
It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.

Encrypting with PHP; decrypting with CryptoJS

I am having some trouble decrypting data using CryptoJS that was encrypted in PHP. Maybe somebody can advise me on where I am going wrong?
I am encrypting as follows:
Get hashed password
Take substring of (0,16) as the key
Encrypt (MCRYPT_RIJNDAEL_128)
Encode ciphertext as base64
When decrypting I do the same:
Get hashed password
Take substring of (0,16) as the key
Base64 decode the ciphertext
Decrypt
PHP:
public function encrypt($input, $key) {
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$input = $this->_pkcs5_pad($input, $size);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = base64_encode($data);
return $data;
}
JavaScript:
function decrypt(ciphertext, hashedPsw) {
var key = hashedPsw.substring(0, 16);
var key = CryptoJS.enc.Hex.parse(key);
var options = { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, keySize:128 / 32 };
ciphertext = CryptoJS.enc.Base64.parse(ciphertext);
var decrypted = CryptoJS.AES.decrypt(ciphertext, key);
return decrypted;
}
The CryptoJS decrypt function expects an object that contains a WordArray and not the WordArray itself, so you need to use:
var decrypted = CryptoJS.AES.decrypt({ ciphertext: ciphertext }, key, options);
You also need to pass the options to the decrypt function. Otherwise, CryptoJS won't know that you wanted to use ECB mode.
Security
Don't use ECB mode! It's not semantically secure. You should at the very least use CBC mode with a random IV. The IV doesn't need to be secret, so you can simply prepend it to the ciphertext.
Then you should authenticate your ciphertexts. This can be done with authenticated modes like GCM or EAX, but they are not provided by mcrypt or CryptoJS. The next best thing is to use an encrypt-then-MAC scheme where you use a strong keyed hash function like HMAC-SHA256 over the ciphertext to make it infeasible for an attacker to change ciphertexts without you knowing it.
I just discovered the answer in a previous thread: Turns out that the problem was the key encoding.

Decrypting AES with Javascript CryptoJS after encrypting with PHP mcrypt

Encrypting in PHP with mcrypt
<?php
$string = 'Secret Message';
$key = 'd4b494e4502a62edd695a903a94c2701';
$iv = '02f30dffbb0d084755f438f7d8be4a7d';
$encrypted = base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_256,
$key,
$string,
MCRYPT_MODE_CBC,
$iv
)
);
//$encrypted results in 'nYoFAiyDARVSI09lH/IPdim5TvE51izVjk6sc2AK9Rg='
?>
Decrypting in Javascript with CryptoJS
<script>
var encrypted = 'nYoFAiyDARVSI09lH/IPdim5TvE51izVjk6sc2AK9Rg=';
var key = CryptoJS.enc.Hex.parse('d4b494e4502a62edd695a903a94c2701');
var iv = CryptoJS.enc.Hex.parse('02f30dffbb0d084755f438f7d8be4a7d');
var decrypted = CryptoJS.AES.decrypt(encrypted,key,{iv:iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});
console.log(decrypted.toString(CryptoJS.enc.Utf8)); //prints an empty string
</script>
I can't figure out how to get the Javascript side to spit out the original text.
SOLVED
Note: I found out that "MCRYPT_RIJNDAEL_256" in PHP's mcrypt is NOT included in AES. It uses the Rijndael method, BUT with a 256-bit block size (not included in AES). So, CryptoJS does not handle 256-bit block sizes for Rijndael. Thanks, GregS
Nonetheless, I found an implementation that successfully decrypted the ciphertext I get from running my PHP mcrypt function above, using MCRYPT_RIJNDAEL_256 (Rijndael, 256-bit block size, with 256-bit key/32-byte key).
Here it is:
https://code.google.com/p/js-mcrypt/
<script>
var encrypted = 'nYoFAiyDARVSI09lH/IPdim5TvE51izVjk6sc2AK9Rg=';
var key = 'd4b494e4502a62edd695a903a94c2701';
var iv = '02f30dffbb0d084755f438f7d8be4a7d';
var decrypted = mcrypt.Decrypt(atob(encrypted), iv, key, 'rijndael-256', 'cbc');
</script>
I hope this helps someone as I spent a week of my spare time trying to figure this out and almost giving up.

Categories