4

I am having the code to encrypt data on Angular, But I don't know how to decrypt on server side

  var panno = CryptoJS.AES.encrypt("FEAPS8905Q", "myPassword").toString();

Encrypted as U2FsdGVkX19mi5mXlJ14Lj0XcJBbqMPDzi/UeNXK4Cw=in angular, after sending the encrypted using Http.post method, I am not getting the exact data, instead, getting 楀뢖᷈鍩ԏ건뫨샞일䜍钚䁞

I used this reference also Decrypting on C#, but I am getting some data like 壓섢⻫捼笺ﵑ戛ꔉ됒퍿誁累♟꘶콒ꚦ

public string Decrypt(string cipherText)
    {
        string EncryptionKey = "myPassword";
        cipherText = cipherText.Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] {  
            0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76  });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.Padding = PaddingMode.None;
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }
12
  • So where's your C# code? Expected output in javascript and what you actually get instead in C# for provided inputs? Commented Apr 24, 2018 at 11:53
  • Do you store encrypted data in database? Commented Apr 24, 2018 at 11:55
  • No, I am not storing, I am just sending to the API. there I need decrypt it for encrypted communication Commented Apr 24, 2018 at 12:02
  • @Evk Updated the code now Commented Apr 24, 2018 at 12:03
  • 1
    Is it a requirement to use just CryptoJS.AES.encrypt(text, password)? Because that derives key from password in a way which is not quite easy to replicate in C#. If that's not a requirement, it's better to derive key manually (for example with CryptoJS.PBKDF2). Commented Apr 24, 2018 at 12:36

5 Answers 5

8

CryptoJS.AES.encrypt(text, password) implicitly derives encryption key and iv from your password using derivation algorithm which is kind of not-native for C#. Instead of relying on that implicit derivation - it's better to explicitly do that yourself, using well known algorithm such as PBKDF2.

Key derivation is needed because your password can have arbitrary size, but given algorithm (AES) needs key of specific size, for example 256 bits. So we need to go from arbitrary length password to fixed size key (in irreversible way).

Sample javascript code:

function encrypt (msg, pass) {
  // random salt for derivation
  var keySize = 256;
  var salt = CryptoJS.lib.WordArray.random(16);
  // well known algorithm to generate key
  var key = CryptoJS.PBKDF2(pass, salt, {
      keySize: keySize/32,
      iterations: 100
    });
  // random IV
  var iv = CryptoJS.lib.WordArray.random(128/8);      
  // specify everything explicitly
  var encrypted = CryptoJS.AES.encrypt(msg, key, { 
    iv: iv, 
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC        
  });
  // combine everything together in base64 string
  var result = CryptoJS.enc.Base64.stringify(salt.concat(iv).concat(encrypted.ciphertext));
  return result;
}

Decrypting that in C# is now easy:

public static string Decrypt(string cipherText, string password) {
    byte[] cipherBytes = Convert.FromBase64String(cipherText);
    using (Aes encryptor = Aes.Create()) {
        // extract salt (first 16 bytes)
        var salt = cipherBytes.Take(16).ToArray();
        // extract iv (next 16 bytes)
        var iv = cipherBytes.Skip(16).Take(16).ToArray();
        // the rest is encrypted data
        var encrypted = cipherBytes.Skip(32).ToArray();
        Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 100);
        encryptor.Key = pdb.GetBytes(32);
        encryptor.Padding = PaddingMode.PKCS7;
        encryptor.Mode = CipherMode.CBC;
        encryptor.IV = iv;
        // you need to decrypt this way, not the way in your question
        using (MemoryStream ms = new MemoryStream(encrypted)) {
            using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read)) {
                using (var reader = new StreamReader(cs, Encoding.UTF8)) {
                    return reader.ReadToEnd();
                }
            }
        }
    }
}    

If you understand the consequences, you can use fixed salt (or for example fixed salt per user in your application), and reduce number of iterations in PBKDF2. Don't use fixed IV though, and don't use part of key as IV either.

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

6 Comments

` var encrypted = CryptoJS.AES.encrypt(this.panno, key, { iv: iv, padding: CryptoJS.pad.Pkcs7, mode: CryptoJS.mode.CBC });` Here I am getting exception Cannot read property '0' of undefined All the params are having their values
What's the type of this.panno? It should be string, and it should not be undefined. Try with encrypt function provided in answer first, don't modify it.
I made some replacement in this line CryptoJS.lib.WordArray.random(16); with ((CryptoJS.lib.WordArray as any).random(16) as CryptoJS.WordArray).toString(); as it shows error like random function doesn't exist in TS editor and this.panno is string only
Well that toString() breaks stuff, you need to remove it. As you see in CryptoJS.lib.WordArray.random(16); there is no toString anywhere.
when removing the toString() I am getting error Argument of type '{ iv: WordArray; padding: Padding; mode: Mode; }' is not assignable to parameter of type 'CipherOption'. Types of property 'iv' are incompatible. Type 'WordArray' is not assignable to type 'string'. and also, salt : wordArray doesnot contain concat()
|
2

Encrypt in node.js:

    var crypto = require('crypto');
var key = '00000000000000000000000000000000'; //replace with your key
var iv = '0000000000000000'; //replace with your IV
var cipher = crypto.createCipheriv('aes256', key, iv)
var crypted = cipher.update(authorizationKey, 'utf8', 'base64')
crypted += cipher.final('base64');
console.log(crypted);

decrypt c#

    string keyString = "00000000000000000000000000000000"; //replace with your key
string ivString = "0000000000000000"; //replace with your iv

byte[] key = Encoding.ASCII.GetBytes(keyString);
byte[] iv = Encoding.ASCII.GetBytes(ivString);

using (var rijndaelManaged =
        new RijndaelManaged { Key = key, IV = iv, Mode = CipherMode.CBC })
        {
            rijndaelManaged.BlockSize = 128;
            rijndaelManaged.KeySize = 256;
            using (var memoryStream =
                   new MemoryStream(Convert.FromBase64String(AuthorizationCode)))
            using (var cryptoStream =
                   new CryptoStream(memoryStream,
                       rijndaelManaged.CreateDecryptor(key, iv),
                       CryptoStreamMode.Read))
            {
                return new StreamReader(cryptoStream).ReadToEnd();
            }
        }

source: https://gsferreira.com/archive/2015/02/how-to-encrypt-in-nodejs-and-decrypt-in-c-sharp/

work for me !

Comments

1

Encrypt data in c#

Refer https://www.c-sharpcorner.com/article/encryption-and-decryption-using-a-symmetric-key-in-c-sharp/ to encrypt data

Decrypt data in angular

Install crypto-js from https://www.npmjs.com/package/crypto-js

//install crypto-js from https://www.npmjs.com/package/crypto-js and import it   

import * as CryptoJS from 'crypto-js';

encrypedcode="Awt%2FgsVGXoQc3sasAkDqbVoXbXlmc2xZzu14cpHxmu1J0pvGYjGCm1uGz0qcpF07"

decryptData(encryptedText:any) {

    try {
      let cipherPhrase = 'decryptkey';

var key = CryptoJS.enc.Utf8.parse(cipherPhrase);
var iv = CryptoJS.enc.Utf8.parse('');

      var decrypted = CryptoJS.AES.decrypt(encryptedText.trim(), key,
        {
          keySize: 128/8,
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7
        });

      return decrypted.toString(CryptoJS.enc.Utf8);


    } catch (e) {
      console.log(e);
    }
  }

 let data=this.decryptData(this.encrypedcode);
console.log(data);

Comments

0

For Encryption the basic idea is to

  • Use PBKDF2 for key generation.
  • Use AES cipher for encryption.

You can read more about this encryption at : CrytoJs officialdocs

Since Decryption is at server(C#) code we need to provide it with values such as- Salt,iv,encrypted text out of our cipher. To pass it we encode this all info in base64 string and pass it to server.

For Encryption in Angular- (my project is in TS) If anyone has errors such as

  • "wordArray doesn't contain concat()"
  • Type 'WordArray' is not assignable to type 'string'

I was able to go through few documentations and was able to find the solution to be able to combine salt, iv and cipher text.

The issue was with Types we need to have a WordArray format of all these 3 to encode.

My approach is far-fetched but it works

  • Convert all LIb.WordArray to ByteArray so its easy to combine all 3 strings to one.
  • Before encoding to Base64 convert the combined to WordArray.
  • Now Send this encoded string to Server for extracting the salt,iv,encryted text at server end to decrypt it.

Make sure you have @types/crypto-js and crypto-js in your project. My version("crypto-js": "^4.0.0", "@types/crypto-js": "^3.1.47").

Encrytion At Angular side TypeScript:

encrypt(msg: string) {
//will have this at C# as well.
var pass = "secret";
var keySize = 256;
//random salt
var salt = CryptoJS.lib.WordArray.random(16);
// to generate key
var key = CryptoJS.PBKDF2(pass, salt, {
  keySize: keySize / 32,
  iterations: 1000,
});
// random IV
var iv = CryptoJS.lib.WordArray.random(128 / 8);
//will attach link where you can find these
var encrypted = CryptoJS.AES.encrypt(msg, key, {
  iv: iv,
  padding: CryptoJS.pad.Pkcs7,
  mode: CryptoJS.mode.CBC,
});

//Convert Lib.WordArray to ByteArray so we can combine them like Concat
var saltwords = this.wordArrayToByteArray(salt);
var ivwords = this.wordArrayToByteArray(iv);
var cryptedText = this.wordArrayToByteArray(encrypted.ciphertext);
// combine everything together in ByteArray.
var header = saltwords.concat(ivwords).concat(cryptedText);
//Now convert to WordArray.
var headerWords = this.byteArrayToWordArray(header);
//Encode this to sent to server
var encodedString = CryptoJS.enc.Base64.stringify(headerWords);
return encodedString;  
}

Type Conversions:

wordArrayToByteArray(wordArray) {
if (
  wordArray.hasOwnProperty("sigBytes") &&
  wordArray.hasOwnProperty("words")
) {
  length = wordArray.sigBytes;
  wordArray = wordArray.words;
}

var result = [],
  bytes,
  i = 0;
while (length > 0) {
  bytes = this.wordToByteArray(wordArray[i], Math.min(4, length));
  length -= bytes.length;
  result.push(bytes);
  i++;
 }
 return [].concat.apply([], result);
 }
byteArrayToWordArray(ba) {
var wa = [],
  i;
for (i = 0; i < ba.length; i++) {
  wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
}

return CryptoJS.lib.WordArray.create(wa);
}
wordToByteArray(word, length) {
 var ba = [],
  xFF = 0xff;
 if (length > 0) ba.push(word >>> 24);
 if (length > 1) ba.push((word >>> 16) & xFF);
 if (length > 2) ba.push((word >>> 8) & xFF);
 if (length > 3) ba.push(word & xFF);

return ba;
}

Decryption at C# is same as mentioned in answer given by EVK.

 public static string Decrypt(string cipherText)
    {
        var password = "secret";
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            // extract salt (first 16 bytes)
            var salt = cipherBytes.Take(16).ToArray();
            // extract iv (next 16 bytes)
            var iv = cipherBytes.Skip(16).Take(16).ToArray();
            // the rest is encrypted data
            var encrypted = cipherBytes.Skip(32).ToArray();
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 1000);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.Padding = PaddingMode.PKCS7;
            encryptor.Mode = CipherMode.CBC;
            encryptor.IV = iv;

            using (MemoryStream ms = new MemoryStream(encrypted))
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    using (var reader = new StreamReader(cs, Encoding.UTF8))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
        }
    }

Comments

0

Found matching algorithms for both Angular and C# to encrypt & Decrypt text cipherPhrase text contain both key and IV separated by a demiliter pipe

Angular TypeScript Code

import * as CryptoJS from 'crypto-js';
 
 encrypt(plainText: string): string {    
let cipherPhrase = environment.angularCipherKeyIvPhrase;
// separate the key and Iv from the cipher phrase string

var key = CryptoJS.enc.Utf8.parse(cipherPhrase.split("|")[0]);
var iv = CryptoJS.enc.Utf8.parse(cipherPhrase.split("|")[1]);

var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(plainText), key,
  {
    keySize: 128 / 8,
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });
console.log(encrypted.toString());
return encrypted;
  }

Decrypt Typescript Function

decrypt(encryptedText: string): string {

let cipherPhrase = environment.angularCipherKeyIvPhrase;

// separate the key and Iv from the cipher phrase string
var key = CryptoJS.enc.Utf8.parse(cipherPhrase.split("|")[0]);
var iv = CryptoJS.enc.Utf8.parse(cipherPhrase.split("|")[1]);

var decrypted = CryptoJS.AES.decrypt(encryptedText, key,
  {
    keySize: 128 / 8,
    iv: iv,
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7
  });

return decrypted.toString(CryptoJS.enc.Utf8);
}

C# function to encrypt / decrypt

        // encryption function similar to Angular cryptoJs
    public static string NgEncrypt(string plainText, string ngCipherKeyIvPhrase)
    {
        var cipherTextArray = ngCipherKeyIvPhrase.Split("|");
        string cipherPhrase = cipherTextArray[0];
        string salt  = cipherTextArray[1];

        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 = Encoding.UTF8.GetBytes(cipherPhrase);
            rijAlg.IV = Encoding.UTF8.GetBytes(salt);

            // 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 Convert.ToBase64String(encrypted);
    }

    // decryption function similar to Angular cryptoJs
    public static string NgDecrypt(string encryptedText,string ngCipherKeyIvPhrase)
    {
        string plainText = string.Empty;
        var cipherTextArray = ngCipherKeyIvPhrase.Split("|");
        string cipherPhrase = cipherTextArray[0];
        string salt = cipherTextArray[1];

        byte[] cipherText = Convert.FromBase64String(encryptedText); 
        // 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 = Encoding.UTF8.GetBytes(cipherPhrase);
            rijAlg.IV = Encoding.UTF8.GetBytes(salt);

            // Create a decryptor to perform the stream transform.  
            var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
            
                // 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();

                        }

                    }
                }

                return plainText;
         
        }

    }

Comments

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.