javascript - AES encryption in Node JS and C# gives different results - Stack Overflow

I have a use case where the text has to be encoded and sent using the AES 256 algorithm. The client-sid

I have a use case where the text has to be encoded and sent using the AES 256 algorithm. The client-side code is in C# which would be decrypting the code.

Encryption code in JS:

const crypto = require('crypto');
  algorithm = 'aes-256-cbc',
  secret = '1234567890123456',
  keystring = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 16);
  iv = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 16);
  inputEncoding = 'utf8',
  outputEncoding = 'base64';


function encrypt(text) {
  let cipher = crypto.createCipheriv('aes-256-cbc', keystring, iv);
  let encrypted = cipher.update(text, inputEncoding, outputEncoding)
  encrypted += cipher.final(outputEncoding);
  return encrypted;
}

Updated code used in the client side:

var keybytes = Encoding.UTF8.GetBytes(passwordKey);
var iv = Encoding.UTF8.GetBytes(passwordKey);

private byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv)
        {
            try
            {
                // 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;
            }
            catch (Exception ex)
            {
                throw ex;
                //LoggerCS.logError("Utility", "EncryptStringToBytes", JsonConvert.SerializeObject(null), ex.ToString(), ex.StackTrace);
            }
            return null;
        }

The keyString and IV value used are same in C# and is encrypted using Utf8. Looking for the equivalent operation in Node JS.

I have a use case where the text has to be encoded and sent using the AES 256 algorithm. The client-side code is in C# which would be decrypting the code.

Encryption code in JS:

const crypto = require('crypto');
  algorithm = 'aes-256-cbc',
  secret = '1234567890123456',
  keystring = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 16);
  iv = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 16);
  inputEncoding = 'utf8',
  outputEncoding = 'base64';


function encrypt(text) {
  let cipher = crypto.createCipheriv('aes-256-cbc', keystring, iv);
  let encrypted = cipher.update(text, inputEncoding, outputEncoding)
  encrypted += cipher.final(outputEncoding);
  return encrypted;
}

Updated code used in the client side:

var keybytes = Encoding.UTF8.GetBytes(passwordKey);
var iv = Encoding.UTF8.GetBytes(passwordKey);

private byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv)
        {
            try
            {
                // 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;
            }
            catch (Exception ex)
            {
                throw ex;
                //LoggerCS.logError("Utility", "EncryptStringToBytes", JsonConvert.SerializeObject(null), ex.ToString(), ex.StackTrace);
            }
            return null;
        }

The keyString and IV value used are same in C# and is encrypted using Utf8. Looking for the equivalent operation in Node JS.

Share edited Jun 23, 2020 at 18:10 Avinash 2,2152 gold badges20 silver badges16 bronze badges asked Jun 18, 2020 at 9:45 Suchetha BSuchetha B 952 silver badges8 bronze badges 8
  • Upvote for the fiddle, nice work, good luck – TheGeneral Commented Jun 18, 2020 at 9:53
  • 1 Is there a reason why you're ignoring algorithm and have hard-coded it to aes-128-cbc? – ProgrammingLlama Commented Jun 18, 2020 at 10:00
  • @John - There is no reason, I was trying to look at the other suggestions over the past questions of the users regarding the same and tried aes-128 as well. – Suchetha B Commented Jun 18, 2020 at 10:35
  • 1 I was just wondering if that was your problem since your C# code uses AES-256. – ProgrammingLlama Commented Jun 18, 2020 at 10:44
  • @Topaco - I'm a little confused here. C# uses block size of 256. And if this has to be changed to 128 to make it aes-256 algorithm, that is not feasible in my case. C# code is already in production from a long time and cannot be modified. Only the Node JS implementation has be done in such a way that it is in sync with the C#. – Suchetha B Commented Jun 19, 2020 at 5:40
 |  Show 3 more ments

4 Answers 4

Reset to default 3

TLDR;

You're using a different IV and algorithm (AES-128 vs AES-256) so you will get different results...

You will need to use the same IV as well as the same key and algorithm if you want to get identical results. This would be an anti-pattern (i.e. don't do this)! Check John's ment about how you're ignoring the algorithm variable in your code, as at a quick glance this and the different IV are responsible for why you're getting different results.

Longer Answer;

1) You actually want it so that the same message (plain text) encrypted with the same key does not always produce the same encrypted result (cipher text). Otherwise any party that is eavesdropping will always know when a duplicate message has been sent again.

2) The initialization vector (IV) is used to provide randomness so that the same plain text does not always result in the same cipher text when a given key is used.

3) This means that to decrypt a message you need to know not only the key but also the IV.

4) The IV should be random and not deterministically derived from the key, otherwise every use of the same key will have the same IV and thus each time the same plain text is encrypted the same cipher text would result. (Leaving you vulnerable to eavesdroppers observing the results of a given message being received and beginning to determine the meaning of the message).

Have a look at the answers to this question AES Encryption - Key versus IV and also this Wikipedia entry http://en.wikipedia/wiki/Initialization_vector for more info.

Try this:

var crypto = require('text');

var mykey = crypto.createCipher('aes-256-cbc',  keystring, iv);
var mystr = mykey.update('abc', 'utf8', 'hex')
mystr += mykey.final('hex');

console.log(mystr);

The whole issue is likely with the encoding. .Net crypto class by default uses Unicode or utf16-le. While you have specified base64 as output encoding. Change it to utf16le ie

outputEncoding = 'utf16le';

look at Node Js documentation here

The resolution was pretty simple than expected. The RijndaelManaged code with keylen 128 referred to AES-128 algorithm and using aes-128-cbc in nodeJS.

Also, since the C# code used getBytes for key and iv value. Buffer.from(secret) had to be used for both key and iv value in nodeJS. Final solution looks like:

   const crypto = require('crypto');
      algorithm = "aes-128-cbc",
      secret = '1234567890123456',
      keystring = new Buffer(secret),
      iv = new Buffer(secret),
      inputEncoding = 'utf8',
      outputEncoding = 'base64';
    function encrypt(text) {
      let cipher = crypto.createCipheriv(algorithm,keystring, iv);
      let encrypted = cipher.update(text, inputEncoding, outputEncoding)
      encrypted += cipher.final(outputEncoding);
      return encrypted;
    }
    
    function decrypt(encrypted) {
      let decipher = crypto.createDecipheriv(algorithm,keystring, iv)
      let dec = decipher.update(encrypted, outputEncoding, inputEncoding)
      dec += decipher.final(inputEncoding);
      return dec;
    }

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745058888a4608840.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信