Search code examples
javascriptencryptioncryptographycryptojs

Encrypting with CryptoJS using Triple DES in ECB mode and PKCS#5 padding


I'm encrypting strings before sending to a 3rd party API that requires Triple DES encryption in ECB mode with PKCS#5 padding. They have given me a sample string to encrypt of

www.society.com|1084470043000|memberaccess

and a sample key of

92f2f81930b5afb056630afb02f2f8b1

The resulting encrypted string should match

uQlYYov+XlVEHL0JBpvt15FeJxt+fXgjs9KLJHH5XsUd80emx5Nn5kSaCXxhQId/

But the string I'm receiving is

U2FsdGVkX19/IR4A9cm+duXf3vhnmnuyJtXFVWJi/Ptqib7g5gOANppYXh+mTQ8tcenO58a5FxnFVxRq1PUETA==

I'm using these libraries

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/crypto-js.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/tripledes.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/mode-ecb.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9/pad-pkcs7.js"></script>

And this is my code

var encrypted = CryptoJS.TripleDES.encrypt("www.society.com|1084470043000|memberaccess" , "92f2f81930b5afb056630afb02f2f8b1", {
        mode: CryptoJS.mode.ECB,
        padding: CryptoJS.pad.Pkcs7
    });

I realize that I'm specifying PKCS#7 instead of PKCS#5 but I haven't found a library for PKCS#5.

My question is whether it is possible to meet their requirements using CryptoJS and if not, are there any other javascript solutions available?

My fiddle

https://jsfiddle.net/dwc6zb89/2/

I don't spend enough time in cryptography to give you a good answer on whether it's base64 or not. I believe so because I have a block of c# code that I've written that produces nearly the correct result. It's a few characters off. I'm continuing to compare the two to see what my c# code is doing that the javascript is not.

public static string Encrypt(string toEncrypt, bool useHashing)
{
    var key = "92f2f81930b5afb056630afb02f2f8b1";

    var iso8859_1 = System.Text.Encoding.GetEncoding("iso-8859-1");

    var keyArray = Convert.FromBase64String(iso8859_1.GetString(iso8859_1.GetBytes(key)));


    byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);




    if (useHashing)
    {
        MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();

        //Always release the resources and flush data
        // of the Cryptographic service provide. Best Practice

        hashmd5.Clear();
    }
    else
        keyArray = UTF8Encoding.UTF8.GetBytes(key);

    TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
    //set the secret key for the tripleDES algorithm
    tdes.Key = keyArray;
    //mode of operation. there are other 4 modes.
    //We choose ECB(Electronic code Book)
    tdes.Mode = CipherMode.ECB;
    //padding mode(if any extra byte added)

    tdes.Padding = PaddingMode.PKCS7;

    ICryptoTransform cTransform = tdes.CreateEncryptor();
    //transform the specified region of bytes array to resultArray
    byte[] resultArray =
      cTransform.TransformFinalBlock(toEncryptArray, 0,
      toEncryptArray.Length);
    //Release resources held by TripleDes Encryptor
    tdes.Clear();
    //Return the encrypted data into unreadable string format
    return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

Update:

I feel like I'm maddeningly close. By converting my key using the following

var encryptedKey = CryptoJS.enc.Base64.parse(key);

I am able to generate an encrypted value that is only a few characters off from the sample the vendor has given me. This is my current fiddle.

https://jsfiddle.net/uv8z2mrc/1/

Update:

I had two issues.

  1. I needed to base 64 encrypt my key before using it like so.

    var encryptedKey = CryptoJS.enc.Base64.parse(key);

  2. The vendors documentation was wrong and the value to encrypt was supposed to be use an address of .org instead of .com. GRRR!


Solution

  • From the CryptoJS docs:

    For the key, when you pass a string, it's treated as a passphrase and used to derive an actual key and IV. Or you can pass a WordArray that represents the actual key. If you pass the actual key, you must also pass the actual IV.

    You should hex decode the key to a word array and also give a 16 byte IV set to all zero bytes. The IV is not used by ECB, but please specify it none-the-less. Otherwise the key will be derived from the string, which will obviously lead to incorrect results.