Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to decrypt AES ECB using crypto-js

Tags:

javascript

ecb

I am trying to send encrypted data from flash (client side) to javascript (running as jscript in asp) on the server side.

There are several javascript Aes libraries, but they are virtually undocumented. I'm trying with crypto-js, but cant get the code to work. The below example generates an empty output, it should generate "6bc1bee22e409f96e93d7e117393172a".

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/rollups/aes.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/mode-ecb.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/pad-nopadding.js"></script>
<script>
    var key = CryptoJS.enc.Hex.parse('2b7e151628aed2a6abf7158809cf4f3c');
    var data = CryptoJS.enc.Hex.parse('3ad77bb40d7a3660a89ecaf32466ef97');
    var decrypted3 = CryptoJS.AES.decrypt(data, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });
    document.write("<br /> dec3: " + decrypted3.toString());
</script>
</body>
</html>

I took a documented working key and encrypted data from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors

I am using ECB because its the only version which doesn't require an IV or salt, as the server wont know the IV or salt used on the client, so would not be able to decrypt the data.

Does anyone have any clue why the above fails to decrypt the data, or know where any documentation is?

Update: After some hours of trial and error, I came up with a combination which produces the output: 7c121d95a84573b6120ada2ffff1ce3118561eba40555c0b However, this is still incorrect. The change made to produce this was:

 var decrypted3 = CryptoJS.AES.decrypt('3ad77bb40d7a3660a89ecaf32466ef97', key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });

I.e. I passed the data in as a string of hex, which cant be right, but does produce output at least.

The next problem will be padding issues. On the client I am using AS3 hurlant libraries, which only offer two padding strategies: NONE and PKCS#5. In crypto-js, the available strategies are:

Pkcs7 (the default)
Iso97971
AnsiX923
Iso10126
ZeroPadding
NoPadding 

Does this mean there will be no chance to every decrypt data between the two libraries? Before I have had to write my own padding hacks (between AS3 and java), to add or remove trailing data, but this took days of trial and error with binary data - there must be an easier way to send a single encrypted string from client to server.

SSL is not an option as the client user can simply use Charles proxy or similar to see and tamper with the unencrypted data.

like image 213
wingnut Avatar asked Jan 14 '13 21:01

wingnut


2 Answers

The example below returns the desired output using AES and ECB.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/rollups/aes.js"></script>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/mode-ecb.js"></script>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/pad-nopadding.js"></script>


    <script>
        var encrypted = '3ad77bb40d7a3660a89ecaf32466ef97',
            key = CryptoJS.enc.Hex.parse('2b7e151628aed2a6abf7158809cf4f3c'),
            cipherParams = CryptoJS.lib.CipherParams.create({
                ciphertext: CryptoJS.enc.Hex.parse(encrypted)         
            });

        var decrypted3 = CryptoJS.AES.decrypt(cipherParams, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.NoPadding });
        document.write("<br /> dec3: " + CryptoJS.enc.Hex.stringify(decrypted3));
    </script>
</body>
</html>

The only real differences is creating a cypherParams object using CryptoJS.lib.CipherParams.create(). According to the official docs a cypherParams object "gives you access to all the parameters used during encryption" including key, iv, salt and the original cypherText. Basically all the info needed to decrypt it. In our case we needed to convert the encrypted data to cypherParam with only the cypherText property. Incidentally the cypherParam can be stringified using standard formats, which is how it is communicated to other systems.

Regarding the padding, as I understand it Pkcs7 is an extension of Pkcs5 and should work for any cypher created using Pkcs5. When I tried the code sample above without the NoPadding option (defaulting to Pkcs7) it didn't work, but I can't tell what was used in creating that encrypted data. At least that AES Test Vectors page you linked to doesn't tell us.

like image 200
frederickf Avatar answered Oct 23 '22 19:10

frederickf


Gave up with ECB, tried various permutations with CBC, and got one to work. It also seems that it is OK to send the IV in plain text from client to server.

Here is the version which correctly outputs "6bc1bee22e409f96e93d7e117393172a". Shock.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/rollups/aes.js"></script>
<!--script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/mode-cbc.js"></script-->
<script src="http://crypto-js.googlecode.com/svn/tags/3.1/build/components/pad-nopadding.js"></script>
<script>
    var key = CryptoJS.enc.Hex.parse('2b7e151628aed2a6abf7158809cf4f3c');
    var iv = CryptoJS.enc.Hex.parse('000102030405060708090A0B0C0D0E0F');
    var data = CryptoJS.enc.Hex.parse('7649abac8119b246cee98e9b12e9197d');      

    var encrypted = {};
    encrypted.key=key;
    encrypted.iv=iv;
    encrypted.ciphertext = data;

    var decrypted = CryptoJS.AES.decrypt(encrypted, key, { iv: iv, padding: CryptoJS.pad.NoPadding });

    document.write("<br /> dec3: " + CryptoJS.enc.Hex.stringify(decrypted));
</script>
</body>
</html>
like image 24
wingnut Avatar answered Oct 23 '22 19:10

wingnut