1

I have two system which are sharing a user database, so authentication needs to be the same.

The passwords are currently encrypted using C#'s Cryptography.Rijndael(N.B. not RijndaelManaged). Using a custom key and iv (initialisation vector). (CBC mode and Pkcs7 padding)

The C# encryption is as follows:

Rijndael alg = Rijndael.Create();
alg.Key = key;
alg.IV = IV;
CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(clearData, 0, clearData.Length);
cs.Close();
byte[] encryptedData = ms.ToArray();

key is 256 bits (32 bytes) and iv (initialisation vector) is 128 bits (16 bytes). The block size is 128 bits (16 bytes).

key and iv are a byte arrays from a base64 strings via:

byte[] key = Convert.FromBase64String(base64Key);
byte[] iv = Convert.FromBase64String(base64IV);

N.B. I have no control on the C# code (legacy system).

On the javascript based system I have to encrypt the passwords exactly the same way. I've tried using node crypto-js to no avail. my code looks something like this:

var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(password), keyCodeWords, {
    iv: ivCodeWords,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
});

keyCodeWords and ivCodeWords are CryptoJS code words from the same base64 key and iv as follows:

var keyCodeWords = CryptoJS.enc.Base64.parse(base64Key);
var ivCodeWords = CryptoJS.enc.Base64.parse(base64IV);

The encryption does work (in the sense that I can encrypt and then decrypt to get the same value). However, the issue is that the encrypted value (encrypted.ciphertext) is not the same as the C# one, so I'm unable to authenticate.

The comparison is done base comparing the base64 encrypted output strings.

How do I make crypto-js (or any other javascript encryption library) consistent with C# Rijndael?

7
  • There are a million options for Rijndael in C#. Which were yours? Can you show us the code? Have you checked that the encoding fits? Remember that AES is only a subset of Rijndael. If you're using a block size other than 128 bit in C#, then you can't use CryptoJS. Commented Mar 24, 2016 at 9:06
  • 1
    You should never encrypt your user's passwords. You need to use hashing instead with some strong ones being PBKDF2, bcrypt, scrypt and Argon2. Since hash functions are one-way function, you won't be able to "decrypt" the hashes. In order to authenticate your user, you can run the password through the hash function again in order to compare with the hash that is stored in the database. See more: How to securely hash passwords? Commented Mar 24, 2016 at 9:06
  • @ArtjomB. , C# encryption: Rijndael alg = Rijndael.Create(); alg.Key = key; alg.IV = IV; CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write); cs.Write(clearData, 0, clearData.Length); cs.Close(); byte[] encryptedData = ms.ToArray(); The key is 256 bits, the `iv' is 128 bits. Block size is 128. Unfortunately, I have no control on the C# implementation (legacy system) - I also would have just used hashing. Commented Mar 24, 2016 at 9:19
  • @ArtjomB., sorry about that I edited my question. Please check it. Thanks. Commented Mar 24, 2016 at 9:29
  • 1
    Ok, it looks fine. So it must be an encoding problem. How are you encoding the password string into bytes on both sides? How are you providing the key and IV from C# in CryptoJS? Can you provide the corresponding code? How are you comparing the results? Commented Mar 24, 2016 at 9:40

1 Answer 1

6

The code works correctly... Your problem is probably in the handling of the password/IV in C# or in Javascript... In C#: https://ideone.com/APC4MM and in Javascript: https://jsfiddle.net/jjwy5472/

I've used in both cases the same password:

byte[] key = new byte[] 
{ 
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
};

byte[] iv = new byte[] 
{ 
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
};

the plaintext is

"Hello world! This is a wonderful day! àèéìòù"

and in both cases the resulting encrypted text is

aa429aa5c1c928b86d81b43ff3fb6cc46f24cc73957bc7c00829357bf441eb3be9cf8aef2ff6f819f9b95c69886b169b6959c4f7ece0620c6a28f849516adee9

But note that the encrypted variable in Javascript is a complex object, containing various properties with various versions of your encrypted data. encrypted.toString() returns the base64 version of the encrypted data, encrypted.ciphertext is a WordArray (the equivalent of CryptoJS of byte[]), and encrypted.ciphertext.toString() is the hex version of it (equivalent to doing BitConverter.ToString(encryptedData).Replace("-", "").ToLowerInvariant() in C#).

Sign up to request clarification or add additional context in comments.

6 Comments

this helped me very much. I was able to see where the issue is. It's the encoding, indeed when using utf8 encoding as you did, the results are the same. However, I just noticed on my side the Unicode is used as the encoding standard on the C# version I have. Now I'm struggling to find a Unicode encoding on CryptoJS. Once I can find that and confirm that I have the same results I'll accept your answer.
@Kholofelo You must use CryptoJS.enc.Utf16LE. See examples: ideone.com/lRG126 and jsfiddle.net/am216ywd
@Kholofelo Note that CryptoJS.enc.Utf16LE could not be included in the "base" library you use of CryptoJS. It is in an additional package.
This absolutely helped, I didn't know that Utf16LE is the same as Unicode. Thanks so much @xanatos, I accepted this answer. After so long this is all I had to change!
@Kholofelo Note that "strangely" CryptoJS.enc.Utf16 == CryptoJS.enc.Utf16BE, so the default encoding with Utf16 is Big Endian. This is "strange" because nowadays 99% of the computers are little endian (and Windows is Little Endian). I use the double quotes around "strange" because technically the CryptoJS behavior is the more correct one (en.wikipedia.org/wiki/UTF-16#Byte_order_encoding_schemes), but sometimes "correctness" and "what persons assume" are different things :-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.