javascriptc#node.jscryptojstripledes

triple des encrypt c# and decrypt in javascript


I have a C# encrypted string that needs to be decrypted in node.js. I am currently using cryptoJS as the decipher.

Below is the code to initially encrypt the string in C#:

The CryptoAgent constructor builds the algorithm key and initialization vector using a Guid. For example, "A925B4D6-A8D0-11E4-BA34-AC7BA1ACF56B".

public CryptoAgent(Guid keyGuid)
    {
        _UseSymmetricEncryption = true;
        byte[] guidArr = keyGuid.ToByteArray();
        Array.Resize<byte>(ref guidArr, 24);
        _Key = (byte[])guidArr.Clone();
        Array.Reverse(guidArr);
        _IV = guidArr;
    }

The encrypt method is pretty straight forward. It takes the plainText and encrypts the data using the key and iv created above, then returns it in a URL friendly string. For example, "Email=testuser@gmail.com&ProductUserId=C4B80D7F-A8D0-11E4-BA34-AC7BA1ACF56B"

private string EncryptSymmetric(string plainText)
    {
        if (string.IsNullOrEmpty(plainText))
        {
            throw new ArgumentNullException("The string to be encrypted cannot be null.");
        }
        ICryptoTransform transform;
        TripleDESCryptoServiceProvider csp = new TripleDESCryptoServiceProvider();
        transform = csp.CreateEncryptor(_Key, _IV);
        MemoryStream memoryStream = new MemoryStream();
        CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write);
        byte[] plaintextBytes = Encoding.Unicode.GetBytes(plainText);
        cryptoStream.Write(plaintextBytes, 0, plaintextBytes.Length);
        cryptoStream.FlushFinalBlock();
        byte[] encryptedData = memoryStream.GetBuffer();
        Console.WriteLine(csp.Mode);
        Console.WriteLine(csp.Padding);
        return UrlNormalize(Convert.ToBase64String(encryptedData, 0, (int)memoryStream.Length));
    }

The resulting encrypted string would be the following:

ZuD6CIEY6b-sh9Q6DRh9SWE0YyC92Jmw1oplTqy7kjETXoNio42hoJxDmMr7V-Sp14aX9lwTxYBM_KjA bEevElE_7nUzC_C4nM13LHHbpg6aR8xO39RseQjpLCLYj5ZKKWiXZREqpvDBlvtF-F1VuqyAMa0ECYOD N8ZCcmmyIHuCpalcUkLZ0zZajwutIrtmmqg3VXQNT3E~

I am tasked with receiving this encrypted string and decrypting the string in node.js and parsing out the two parameters for further use. Below is my initial file for decryption:

var CryptoJS = require("crypto-js");

var text = "Email=testuser@gmail.com&ProductUserId=C4B80D7F-A8D0-11E4-BA34-AC7BA1ACF56B";
var key = "A925B4D6-A8D0-11E4-BA34-AC7BA1ACF56B";
var useHashing = true;

if (useHashing){
   key = CryptoJS.MD5(key).toString();
   key = key + '0000000000000000';
}

var textWordArray = CryptoJS.enc.Utf16.parse(text);
var keyHex = CryptoJS.enc.Hex.parse(key);

var iv = reverseHexString(keyHex.toString());
var ivHex = CryptoJS.enc.Hex.parse(iv);

console.log('hexadecimal key: ' + keyHex + '\n');

console.log('hexadecimal iv: ' + ivHex + '\n');

var options = {
    mode: CryptoJS.mode.CBC, 
    padding: CryptoJS.pad.Pkcs7,
    iv: ivHex
};

var encrypted = CryptoJS.TripleDES.encrypt(textWordArray, keyHex, options);

var base64String = encrypted.toString();

console.log('base64: ' + base64String + '\n');

var decrypted = CryptoJS.TripleDES.decrypt( {
    ciphertext: CryptoJS.enc.Base64.parse(base64String)
}, keyHex, options);

console.log('decrypted: ' + decrypted.toString(CryptoJS.enc.Utf16));

function reverseHexString(hexStr) {
    var first32 = hexStr.substring(0, 32);
    var reverseFirst32 = first32.split("").reverse().join("").split("");

    var reverseHex = '0000000000000000';

    for (var i = 0; i < reverseFirst32.length; i+=2) {
        reverseHex += reverseFirst32[i+1];
        reverseHex += reverseFirst32[i];
    };

    return reverseHex;
}

My initial run at a solution has resulted in the decryption failing and producing a line of question marks.

Using the C# code I was able to print out the key and iv values. I attempted to replace the keyHex and ivHex Javascript values with the key and iv values printed from the C#, but the decryption still fails.

Any help that can be provided is greatly appreciated.

Thank you


Solution

  • The reason this doesn't work is probably the key generation: You use ASCII zeros instead of \0 and you have 16 of them and not 8 (MD5 gives 16 bytes and you want a 24 byte TDES key). This isn't bad for the key as CryptoJS will just disregard the additional bytes, but since you reverse the key to get the IV, you get a wrong IV instead.