Создайте 16-байтовый ключ для шифрования AES из соли и пароля в Node JS Crypto - PullRequest
0 голосов
/ 04 декабря 2018

Я пытаюсь сопоставить шифрование AES 256 CBC, реализованное в C #, с использованием криптомодуля узла JS.

Это мой код C #

using System;
using System.Security.Cryptography; 
using System.Text;
public class Program
{
    public static void Main()
    {
        Console.WriteLine(EncryptExt("Hello World"));
        Console.WriteLine(DecryptExt(EncryptExt("Hello World")));
    }

    public static string EncryptExt(string raw)

        {

            using (var csp = new AesCryptoServiceProvider())

            {

                ICryptoTransform e = GetCryptoTransformExt(csp, true);

                byte[] inputBuffer = Encoding.UTF8.GetBytes(raw);

                byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);



                string encrypted = Convert.ToBase64String(output);



                return encrypted;

            }

        }



        public static string DecryptExt(string encrypted)

        {

            using (var csp = new AesCryptoServiceProvider())

            {

                var d = GetCryptoTransformExt(csp, false);

                byte[] output = Convert.FromBase64String(encrypted);

                byte[] decryptedOutput = d.TransformFinalBlock(output, 0, output.Length);



                string decypted = Encoding.UTF8.GetString(decryptedOutput);

                return decypted;

            }

        }



        private static ICryptoTransform GetCryptoTransformExt(AesCryptoServiceProvider csp, bool encrypting)

        {

            csp.Mode = CipherMode.CBC;

           csp.Padding = PaddingMode.PKCS7;

            var passWord = Convert.ToString("AvbSkj3BVbf4o6mdlAofDp0/SD0susEWo0pKdmqas");

            var salt = Convert.ToString("ABj4PQgf3j5gblQ0iDp0/Gb07ukQWo0a");



            String iv = Convert.ToString("aAB1jhPQ89o=f619");



            var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(passWord), Encoding.UTF8.GetBytes(salt), 65536);

            byte[] key = spec.GetBytes(16);





            csp.IV = Encoding.UTF8.GetBytes(iv);

            csp.Key = key;

            if (encrypting)

            {

                return csp.CreateEncryptor();

            }

            return csp.CreateDecryptor();

        }

}

И это мой узел JSреализация

const crypto = require('crypto'),
  algorithm = 'aes-128-cbc',
  password = 'AvbSkj3BVbf4o6mdlAofDp0/SD0susEWo0pKdmqas',
  salt = 'ABj4PQgf3j5gblQ0iDp0/Gb07ukQWo0a',
  iv = 'aAB1jhPQ89o=f619',
  inputEncoding = 'utf8',
  outputEncoding = 'base64';


 function encrypt(text) {
  let cipher = crypto.createCipheriv(algorithm,createHashPassword(), iv);
  let encrypted = cipher.update(text, inputEncoding, outputEncoding)
  encrypted += cipher.final(outputEncoding);
  return encrypted;
}

function createHashPassword(){
    let nodeCrypto = crypto.pbkdf2Sync(Buffer.from(password), Buffer.from(salt), 65536, 16, 'sha1');

    return nodeCrypto || nodeCrypto.toString('hex');
};

function decrypt(encrypted) {
  let decipher = crypto.createDecipheriv(algorithm, Buffer.from(createHashPassword(),"hex"), iv)
  let dec = decipher.update(encrypted, outputEncoding, inputEncoding)
  dec += decipher.final(inputEncoding);
  return dec;
}

console.log(encrypt('Hello World'));
console.log(decrypt(encrypt('Hello World')));

Зашифрованные данные из этих двух опций отличаются друг от друга, следовательно, не в состоянии решить эту проблему.

Пока что я видел,

  • метод crypto createCipheriv узла принимает только 32-байтовый буфер, и если я передам ему 16-байтовый буфер, он говорит, недопустимая длина.
  • Если я преобразую 16-байтовый ключ в шестнадцатеричную строку, зашифрованное значение изменяется и не совпадает с реализацией C #.
  • Я не могу изменить реализацию C #, так как она уже находится в производствеи использовался несколькими приложениями.
  • Так что, похоже, существует проблема с генерацией ключа из соли и пароля в узле js, сопоставляя то, что сделано в C #, и я не могу это выяснить.

Код можно протестировать по следующей ссылке: C # Реализация: https://dotnetfiddle.net/bClrpW Узел JS Реализация: https://runkit.com/a-vi-nash/5c062544509d8200156f6111

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Если вы работаете с паролями длиной 41 символ, почему бы вместо этого не использовать реальный ключ? 256-битный ключ с кодировкой base64 будет иметь длину 44 символа.

Цель соли и итерации для отклонения состоит в том, чтобы противостоять общей проблеме слишком коротких паролей.Но зачем проходить через все трудности реализации этого в обоих концах без дополнительных преимуществ, а с несколькими недостатками - например, больше кода и более медленное решение.

0 голосов
/ 04 декабря 2018

Похоже, что вы создаете экземпляр AES-128 в своем коде C#, потому что вы используете 16 байтов keylen.

AES-256 keylen составляет 32 байта, а не 16 байтов.

Ошибки в коде:

  1. Поскольку для ключа C# установлено 16 байтов, он использует AES-128, а не AES-256.Поэтому вам нужно изменить node.js на AES-128 или изменить сгенерированный ключ на 32 байта с обеих сторон.
  2. Так как вы используете текстовую строку соль и пароль (не base64 в кодировке), ваш node.jsсторона использует неверные параметры pbkdf2Sync.
  3. IV len для алгоритма AES в 16 байтах, и вы не можете использовать более короткие.

Так как вы хотели AES-256 здесьВы изменили в обе стороны:

C# сторона:

String iv = Convert.ToString("SOME_IV_SOME_IV_"); // 16 bytes IV
....
byte[] key = spec.GetBytes(32); // 32 bytes key

node.js сторона:

iv = 'SOME_IV_SOME_IV_' // 16 bytes IV similar to C#
...
// Bugs in this function
function createHashPassword(){
    // Change parameters to `base64` only if salt and password are base64. it may be true for salt, but it is can rarely be correct for password.
    let nodeCrypto = crypto.pbkdf2Sync(Buffer.from(password), Buffer.from(salt), 65536, 32, 'sha1');

    return nodeCrypto;
};

ВАЖНЫЕ ЗАМЕЧАНИЯ:

  1. Помните, что IV должен быть выбран в качестве случайного буфера (ни фиксированного, ни текстового), и, поскольку кажется, что вы отправляете его по сети,Вам также нужно отправить IV с ним.
  2. SALT должен быть случайным буфером (не текстовым) и фиксированным с обеих сторон.
  3. Я предлагаю использовать более 100000 итераций для PBKDF2 как минимум.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...