Encrypt in javascript and decrypt in C# with AES algorithm

12,787

Solution 1

Using Dot net core and Type Script.

npm instal crypto-js

//Inside imports of your TS file include 
import * as CryptoJS from 'crypto-js';

// Declare this key and iv values in declaration
private key = CryptoJS.enc.Utf8.parse('4512631236589784');
private iv = CryptoJS.enc.Utf8.parse('4512631236589784');

// Methods for the encrypt and decrypt Using AES
encryptUsingAES256() {
    var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(JSON.stringify("Your Json Object data or string")), this.key, {
        keySize: 128 / 8,
        iv: this.iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    console.log('Encrypted :' + encrypted);
    this.decryptUsingAES256(encrypted);
    return encrypted;
}

decryptUsingAES256(decString) {
    var decrypted = CryptoJS.AES.decrypt(decString, this.key, {
        keySize: 128 / 8,
        iv: this.iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    console.log('Decrypted : ' + decrypted);
    console.log('utf8 = ' + decrypted.toString(CryptoJS.enc.Utf8));

}

The C# code to encode or decode is here.

public class encr {
    public static string DecryptStringAES(string cipherText) {
        var keybytes = Encoding.UTF8.GetBytes("4512631236589784");
        var iv = Encoding.UTF8.GetBytes("4512631236589784");

        var encrypted = Convert.FromBase64String(cipherText);
        var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
        return decriptedFromJavascript;
    }
    private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv) {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0) {
            throw new ArgumentNullException("cipherText");
        }
        if (key == null || key.Length <= 0) {
            throw new ArgumentNullException("key");
        }
        if (iv == null || iv.Length <= 0) {
            throw new ArgumentNullException("key");
        }

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        // Create an RijndaelManaged object
        // with the specified key and IV.
        using(var rijAlg = new RijndaelManaged()) {
            //Settings
            rijAlg.Mode = CipherMode.CBC;
            rijAlg.Padding = PaddingMode.PKCS7;
            rijAlg.FeedbackSize = 128;

            rijAlg.Key = key;
            rijAlg.IV = iv;

            // Create a decrytor to perform the stream transform.
            var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

            try {
                // Create the streams used for decryption.
                using(var msDecrypt = new MemoryStream(cipherText)) {
                    using(var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {

                        using(var srDecrypt = new StreamReader(csDecrypt)) {
                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();

                        }

                    }
                }
            } catch {
                plaintext = "keyError";
            }
        }

        return plaintext;
    }

    public static string EncryptStringAES(string plainText) {
        var keybytes = Encoding.UTF8.GetBytes("4512631236589784");
        var iv = Encoding.UTF8.GetBytes("4512631236589784");

        var encryoFromJavascript = EncryptStringToBytes(plainText, keybytes, iv);
        return Convert.ToBase64String(encryoFromJavascript);
    }

    private static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv) {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0) {
            throw new ArgumentNullException("plainText");
        }
        if (key == null || key.Length <= 0) {
            throw new ArgumentNullException("key");
        }
        if (iv == null || iv.Length <= 0) {
            throw new ArgumentNullException("key");
        }
        byte[] encrypted;
        // Create a RijndaelManaged object
        // with the specified key and IV.
        using(var rijAlg = new RijndaelManaged()) {
            rijAlg.Mode = CipherMode.CBC;
            rijAlg.Padding = PaddingMode.PKCS7;
            rijAlg.FeedbackSize = 128;

            rijAlg.Key = key;
            rijAlg.IV = iv;

            // Create a decrytor to perform the stream transform.
            var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

            // Create the streams used for encryption.
            using(var msEncrypt = new MemoryStream()) {
                using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
                    using(var swEncrypt = new StreamWriter(csEncrypt)) {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        // Return the encrypted bytes from the memory stream.
        return encrypted;
    }
}

Solution 2

I too had the requirement to send encrypted JSON object to .Net CORE API 2.0 and searched on internet to find if there is any help. I know by now you would have solved this issue but to help anyone interested I am providing my solution to help them.

With the sample codes I found here on stackoverflow, I managed to implement the solution. The tricky bit is the key and IV has to be 16 in length for the code to work.

public static encrypt(model: any) {
        const key = CryptoJS.enc.Utf8.parse('TestMyOwnKeyForI');
        const iv = CryptoJS.enc.Utf8.parse('TestMyOwnIV1ForI');
        // padding and truncating
        const encryptedMessage = CryptoJS.AES.encrypt(JSON.stringify(model), key, {            
            keySize: 128 / 8,
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }).toString();

        return encryptedMessage;
}

In CORE I've implemented my customer model binding provider as follows:

public class DecryptModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context.Metadata.ModelType == typeof(MyModel))
                return new DecryptModelBinder();

            return null;
        }
    }

Then my own decryptmodelbinder as follows:

public class DecryptModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));
            using (var sr = new StreamReader(bindingContext.HttpContext.Request.Body))
            {
                string valueFromBody = sr.ReadToEnd();

                if (valueFromBody != null && valueFromBody.Length > 0)
                {
                    var decrypted = Encryption.DecryptString(valueFromBody, "TestMyOwnKeyForI");

                    var model = JsonConvert.DeserializeObject(decrypted, bindingContext.ModelType);

                    bindingContext.Result = ModelBindingResult.Success(model);
                    bindingContext.Model = model;        
                }

            }

            return Task.CompletedTask;
        }
    }

Solution 3

You would need to serialize the ciphertext yourself. There are many ways to do it.

If the key is not a string, but a WordArray (as in your case), then a simple encryptedlogin.toString() would produce a Base64 encoded string only containing the ciphertext. Remember that you need to include the enc-base64.js source file.

If the "key" (actually password) is a string, then an OpenSSL-compatible key derivation is applied. In that case encryptedlogin.toString() would be a Base64 encoded string which contains the "Salted__" string, 8 byte random salt and the ciphertext.

If you only want to get the ciphertext then encryptedlogin.ciphertext.toString() will give you a Hex-encoded string which contains only the ciphertext and encryptedlogin.iv.toString() will give you a Hex-encoded IV. You can produce a Base64-encoded string in this way encryptedlogin.ciphertext.toString(CryptoJS.enc.Base64).

Remember that the IV must be randomly chosen for every encryption in order to provide semantic security. It doesn't have to be secret, so you can send it along with the ciphertext.

On the server side, you would decode the values (Base64 or Hex depending on what you used during encryption) and use them with the AesCryptoServiceProvider class (or similar) to decrypt the ciphertext.


Remember that you additionally need to authenticate your ciphertext in order to detect (malicious) manipulation. This can be done with an encrypt-then-MAC scheme with a strong MAC like HMAC-SHA256.

Also, if the key is transmitted along with the ciphertext or over an insecure channel, then this is basically just data obfuscation and doesn't provide real security. See more: Javascript Cryptography Considered Harmful

Share:
12,787
Lea
Author by

Lea

Updated on June 04, 2022

Comments

  • Lea
    Lea almost 2 years

    I tried to encrypt in angular using AES library from AES.

    I encrypted the string using the CryptoJS.AES.encrypt() method from AES.

    Here is my code:

      var txtloginKod = 'Some String...';             
      var key = CryptoJS.enc.Utf8.parse('8080808080808080');
      var iv = CryptoJS.enc.Utf8.parse('8080808080808080');
      var  encryptedlogin = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(txtloginKod), key,
      {
          keySize: 128 / 8,
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
      });
    

    The method CryptoJS.AES.encrypt() return a Object to my encryptedlogin variable.

    I don't know how to send this object to my WCF Web server in C#

    When I tried to send the whole object (and define the Web service method to expect get C# Object), I got the error below:

    "Converting circular structure to JSON"

  • Mulli
    Mulli over 3 years
    Answer should provide more details