Шифрование сложно: шифрование AES в Hex - PullRequest
2 голосов
/ 02 апреля 2010

Итак, у меня на работе есть приложение, которое шифрует строку с помощью ColdFusion. Встроенные помощники шифрования ColdFusion делают это довольно просто:

encrypt('string_to_encrypt','key','AES','HEX')

Я пытаюсь использовать Ruby для создания той же зашифрованной строки, что и этот скрипт ColdFusion. К сожалению, шифрование является наиболее запутанным предметом информатики, известным человеку.

Я нашел пару вспомогательных методов, которые используют библиотеку openssl и дают вам действительно простой метод шифрования / дешифрования. Вот результирующая строка:

"\370\354D\020\357A\227\377\261G\333\314\204\361\277\250"

Что выглядит для меня в юникоде. Я пробовал несколько библиотек, чтобы преобразовать это в hex, но все они говорят, что он содержит недопустимые символы. Попытка распаковать это приводит к этому:

string = "\370\354D\020\357A\227\377\261G\333\314\204\361\277\250"
string.unpack('U')
ArgumentError: malformed UTF-8 character
  from (irb):19:in `unpack'
  from (irb):19

В конце дня это должно выглядеть примерно так (вывод метода шифрования ColdFusion):

F8E91A689565ED24541D2A0109F201EF

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

Вот простой скрипт, который я использую для шифрования / дешифрования:

def aes(m,k,t)
  (aes = OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key = Digest::SHA256.digest(k)
  aes.update(t) << aes.final
end

def encrypt(key, text)
  aes(:encrypt, key, text)
end

def decrypt(key, text)
  aes(:decrypt, key, text)
end

Любая помощь? Может быть, простой вариант, который я могу передать OpenSSL :: Cipher :: Cipher, который скажет ему закодировать шестнадцатеричную финальную строку?

Ответы [ 2 ]

2 голосов
/ 23 октября 2011

Я столкнулся с подобной проблемой сегодня. Мой был немного сложнее, потому что у меня не было доступа к коду CF - только текст для шифрования, ключ и SHA256 зашифрованного результата.

Официальная документация для Шифрование Функция говорит:

ключ : строка. Ключ или семя, использованное для шифрования строки.

  • Для алгоритма CFMX_COMPAT - любая комбинация любого количества символов; используется в качестве начального числа для генерации 32-битного ключа шифрования.

  • Для всех других алгоритмов введите ключ в формате, используемом алгоритмом. Для этих алгоритмов используйте функцию GenerateSecretKey для генерации ключа.

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

Поскольку мы не можем напрямую использовать собственный ключ для шифрования AES - мне пришлось преобразовать его в тот же формат GenerateSecretKey has.

После некоторого копания оказалось, что GenerateSecretKey создает случайную двоичную строку длиной 16 байтов и кодирует ее в Base64. Но - это важно - внутренне декодирует его во время процесса шифрования.

Итак, это рабочее решение:

Код CF:

plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"; // this can be MD5 of some secret string
encoded_key = ToBase64(BinaryDecode(plain_key, "Hex"));
base64EncodedResult = Encrypt("PLAIN TEXT", key, "AES", "Base64");

Рубиновый код:

plain_key = "REPLACE_ME_WITH_32_HEX_UPPERCASED_CHARS"
encoded_key = plain_key.unpack('a2' * 16).map(&:hex).pack('c' * 16) # same as in CF except encoding to Base64
aes_encrypted = Aes.encrypt('PLAIN TEXT', encoded_key)
base64_encoded_result = ActiveSupport::Base64.encode64s(aes_encrypted)

Код модуля Aes:

# Two changes comparing to author's code:
# 1) AES-128-ECB instead of AES-256-CBC
# 2) No key conversion to SHA256

module Aes
  def self.aes(m,k,t)
    (aes = OpenSSL::Cipher::Cipher.new('aes-128-ecb').send(m)).key = k
    aes.update(t) << aes.final
  end

  def self.encrypt(text, key)
    aes(:encrypt, key, text)
  end

  def self.decrypt(text, key)
    aes(:decrypt, key, text)
  end
end 
1 голос
/ 07 июля 2010

Чтобы преобразовать полученную строку в формат, аналогичный тому, который выводит ColdFusion, просто используйте:

raw = "\370\354D\020\357A\227\377\261G\333\314\204\361\277\250" 
raw.unpack('H*').to_s.upcase
=> "F8EC4410EF4197FFB147DBCC84F1BFA8"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...