Rails-шифрование с использованием AES, слишком сложное - PullRequest
0 голосов
/ 21 декабря 2018

У меня проблемы с шифрованием значения от стороннего поставщика, которого я использую.

Их инструкции следующие:

1) Convert the encryption password to a byte array.
2) Convert the value to be encrypted to a byte array.
3) The entire length of the array is inserted as the first four bytes onto the front 
   of the first block of the resultant byte array before encryption.
4) Encrypt the value using AES with:
        1. 256-bit key size,
        2. 256-bit block size, 
        3. Encryption Mode ECB, and
        4. an EMPTY initialization vector.
5) After encryption, you should now have a byte array that holds the encrypted value. 
6) Convert each byte to a HEX format and string all the HEX values together.
7) The final result is a string of HEX values. This is the final encrypted value to be passed. 
   The length of the final value will always be an even number.

EXAMPLE:
Given the following input values:
plainText: 2017/02/07 22:46
secretKey: ABCD1234FGHI5678
The following string will be produced:
D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04

То, что я пробовал до сих пор ...

plain_text = "2017/02/07 22:46"
secret_key = "ABCD1234FGHI5678"

plain_text_byte_array = plain_text.bytes
plain_text_byte_array.unshift(0).unshift(0).unshift(0).unshift(16) # I found a Java example in their documentation and this is what they do. They prepend their byte array with 16, 0, 0, 0
secret_byte_array = secret_key.bytes
secret_byte_array = secret_byte_array.concat([0, 0, 0,...]) # also from their java example, they append the secret_byte array with 16 0's in order to get its length to 32

cipher = OpenSSL::Cipher::AES256.new(:ECB)
cipher.key = secret_byte_array.pack("C*")
encrypted = cipher.update(plain_text_byte_array.pack("C*")) + cipher.final

p encrypted.unpack("H*").first.to_s.upcase

# Result is: 
#    "84A0E5DCA7D704C41332F86E707DDAC244A1A87C38A906145DE4060D2BC5C8F4"

Как вы видите, мой результат отличается от фактического результата, который должен быть "D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04"

Кто-нибудь знает, что я что-то упускаю или что-то делаю.Мне было сложно разобрать их инструкции, поэтому, может быть, я что-то упустил.Спасибо за любую помощь, которую может оказать любой!(Я пробовал кучу разных вариантов того, что вы видите выше).Мне просто нужно какое-то руководство или, по крайней мере, кто-то, кто скажет мне, что я не сумасшедший, что не понимаю их инструкции.

Ответы [ 2 ]

0 голосов
/ 11 января 2019

На основании Отличный ответ Люка вот версия для Ruby.Мне пришлось использовать гем ruby-mcrypt и установить библиотеку mcrypt локально, используя brew install libmcrypt.

Ответ Люка указывает, что секретный ключ должен быть дополнен нулями справа.Вот мой код:

   plain_text = "2017/02/07 22:46"
   secret_text = "ABCD1234FGHI5678"
   answer = "D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04"

   def format_byte_arrays(plain, secret)
     zero_byte_array = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
     length_array = [16, 0, 0, 0]

     plain_bytes = length_array.concat(plain.bytes)
     secret_bytes = secret.bytes.concat(zero_byte_array)

     [plain_bytes, secret_bytes]
   end

   plain_bytes, secret_bytes = format_byte_arrays(plain_text, secret_text)
   final_plain, final_secret = [plain_bytes.pack("C*"), secret_bytes.pack("C*")]

   cipher = Mcrypt.new("rijndael-256", :ecb, final_secret, nil, :zeros)
   encrypted = cipher.encrypt(final_plain)
   result = encrypted.unpack("H*").first.to_s.upcase

Результат будет правильным ответом.

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

Мне удалось воспроизвести их результат - процесс, который они использовали, чрезвычайно запутан и настолько далек от элегантности, насколько это возможно.Я приложил гораздо более подробное описание шагов, необходимых для достижения их результата, и исходного кода C #, который я использовал для этого.

  1. Преобразование пароля в байтмассив. Массив байтов должен иметь длину 32 байта и, если пароль недостаточно длинный, должен дополняться 0 байтами справа.Таким образом, их пароль, закодированный в шестнадцатеричном формате, становится 4142434431323334464748493536373800000000000000000000000000000000.

  2. Преобразовать значение, которое должно быть зашифровано, в байтовый массив. Это достаточно просто, просто закодируйтес UTF-8.

  3. Вся длина массива вставляется как первые четыре байта в начало первого блока результирующего байтового массива перед шифрованием. Это глупо и не имеет смысла, но принимает длину байтового массива из шага 2 как беззнаковое 32-разрядное целое число и преобразует в байтовый массив байтов.Добавьте к массиву префикс из шага 2.

  4. Зашифруйте значение, используя AES .Эмм.Нет, не делай этого.Зашифруйте значение с помощью Rijndael , используя 256-битный размер блока, 256-битный размер ключа, режим ECB и нули для заполнения.

  5. Остальное легко,просто преобразуйте результат шифрования в шестнадцатеричный код.

Код, который я использовал для достижения этого результата, приведен ниже, в C #.Я не очень хорошо знаю Руби, извини.

    // 1. Convert the encryption password to a byte array.
    byte[] passwordBytesOriginal = Encoding.UTF8.GetBytes("ABCD1234FGHI5678");
    byte[] passwordBytes = new byte[32];
    Array.Copy(passwordBytesOriginal, 0, passwordBytes, 0, passwordBytesOriginal.Length);


    // 2. Convert the value to be encrypted to a byte array.
    byte[] valueBytes = Encoding.UTF8.GetBytes("2017/02/07 22:46");

    // 3. The entire length of the array is inserted as the first four bytes onto the front 
    // of the first block of the resultant byte array before encryption.
    byte[] valueLengthAsBytes = BitConverter.GetBytes((uint)valueBytes.Length);
    byte[] finalPlaintext = new byte[valueBytes.Length + valueLengthAsBytes.Length];
    Array.Copy(valueLengthAsBytes, 0, finalPlaintext, 0, valueLengthAsBytes.Length);
    Array.Copy(valueBytes, 0, finalPlaintext, valueLengthAsBytes.Length, valueBytes.Length);

    // 4. Encrypt the value using AES...
    byte[] ciphertext;
    using (RijndaelManaged rijn = new RijndaelManaged())
    {
        rijn.BlockSize = 256;
        rijn.KeySize = 256;
        rijn.Key = passwordBytes;
        rijn.Mode = CipherMode.ECB;
        rijn.Padding = PaddingMode.Zeros;

        var encryptor = rijn.CreateEncryptor();
        ciphertext = encryptor.TransformFinalBlock(finalPlaintext, 0, finalPlaintext.Length);
    }

    // 5., 6., 7...
    string result = BitConverter.ToString(ciphertext).Replace("-", "").ToUpper();
    Console.WriteLine(result); // D6281D5BE6CD6E79BB41C039F4DD020FBEC9D290AD631B2598A6DFF55C68AD04
...