Шифрование AES в Node JS и C# дает разные результаты - PullRequest
6 голосов
/ 18 июня 2020

У меня есть вариант использования, когда текст нужно закодировать и отправить с использованием алгоритма AES 256. Код на стороне клиента находится в C#, который будет расшифровывать код.

Код шифрования в 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;
}

Обновленный код, используемый на стороне клиента:

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;
        }

Используемые значения keyString и IV такие же, как в C#, и зашифрованы с использованием Utf8. Ищем эквивалентную операцию в Node JS.

Ответы [ 4 ]

3 голосов
/ 18 июня 2020

TLDR;

Вы используете другой IV и другой алгоритм (AES-128 против AES-256), поэтому вы получите разные результаты ...

Вам нужно будет использовать тот же IV, а также тот же ключ и алгоритм, если вы хотите получить идентичные результаты. Это будет антишаблон (т.е. не делайте этого)! Проверьте комментарий Джона о том, как вы игнорируете переменную алгоритма в своем коде, так как на первый взгляд это и разные IV отвечают за то, почему вы получаете разные результаты.

Длинный ответ;

1) Вы действительно хотите, чтобы одно и то же сообщение (простой текст ), зашифрованный одним и тем же ключом, не всегда дает одинаковый зашифрованный результат (зашифрованный текст). В противном случае любая сторона, которая подслушивает, всегда будет знать, когда повторяющееся сообщение было отправлено снова.

2) Вектор инициализации (IV) используется для обеспечения случайности, чтобы один и тот же простой текст не всегда приводил к одному и тому же зашифрованный текст при использовании данного ключа.

3) Это означает, что для дешифрования сообщения вам необходимо знать не только ключ, но и IV.

4) IV должен быть случайным и не получен детерминированно из ключа, в противном случае каждое использование одного и того же ключа будет иметь один и тот же IV, и, таким образом, каждый раз, когда один и тот же простой текст будет зашифрован, будет получаться один и тот же зашифрованный текст. (Оставляя вас уязвимыми для подслушивающих, наблюдающих за результатами получения данного сообщения и начинающих определять значение сообщения).

Посмотрите ответы на этот вопрос Шифрование AES - ключ против IV , а также эту запись в Википедии http://en.wikipedia.org/wiki/Initialization_vector для получения дополнительной информации.

0 голосов
/ 03 июля 2020

Разрешение оказалось довольно простым, чем ожидалось. Код RijndaelManaged с keylen 128 ссылается на алгоритм AES-128 и использует aes-128-cb c в nodeJS.

Кроме того, поскольку код C# использует getBytes для ключа и значения iv. Buffer.from (secret) должен использоваться как для ключа, так и для значения iv в nodeJS. Окончательное решение выглядит так:

   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;
    }
0 голосов
/ 02 июля 2020

Вся проблема скорее всего в кодировке. . Net криптографический класс по умолчанию использует Unicode или utf16-le. Пока вы указали base64 в качестве выходной кодировки. Измените его на utf16le ie

outputEncoding = 'utf16le';

посмотрите Node Js документацию здесь

0 голосов
/ 28 июня 2020

Попробуйте следующее:

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);
...