3

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

gparedes09
  • 33
  • 1
  • 7

1 Answers1

0

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.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • i reduced the number of leading zeros from 16 to 8 and also used the `\0`, but I am still receiving the line of question marks when attempting to decrypt the encrypted string from C#. – gparedes09 Feb 02 '15 at 16:55
  • I don't use C#, so I cannot test it, but I would suggest that you check that the key and IV match between the two languages by printing to the console as hex or some other encoding. – Artjom B. Feb 02 '15 at 17:02
  • 1
    So long story short I used the C# encrypt function to print out the original Key and IV values being used and hardcoded them into my node.js decryption file. The final piece of the puzzle was using the Utf16LE encoding rather than Utf16. @artjom-b thanks for your help. The reducing of the zeros sent me down the right track. – gparedes09 Feb 02 '15 at 21:55