AES Java-кодирование, Ruby-декодирование - PullRequest
7 голосов
/ 24 марта 2010

Я пытаюсь AES кодировать данные в java, отправлять их по сети и декодировать в ruby.

Работает нормально с базовыми строками, но как только длина строки составляет 16 байт или более, у меня появляется мусор при кодировании декодированной строки ruby. Я предполагаю, что это связано с отступом (хотя не уверен, поскольку он влияет даже на строки с точным размером 16)

Я пытался использовать PKCS или просто добавить пробел в конце моей строки, чтобы соответствовать точной длине без удачи

Также кто-нибудь может объяснить, почему я должен сделать "aes-256-cbc" в ruby, зная, что мой код Java использует aes 128? попытка aes-128-cbc в ruby ​​не работает для любой строки

Любая помощь очень ценится

Вот мой основной код

Java

byte[] raw = key.getBytes();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(str.getBytes());
return new BASE64Encoder().encode(encrypted);

рубин

def aes_decrypt(key, encrypted)
decipher =OpenSSL::Cipher::Cipher.new("aes-256-cbc")
decipher.decrypt
decipher.padding = 0
decipher.key = key
d = decipher.update(encrypted)
d << decipher.final
logger.debug "email  #{d.to_s}"
return d.to_s
end

Ответы [ 2 ]

11 голосов
/ 24 марта 2010

Есть отступ и цепочка . Сначала вы должны получить правильную цепочку.

AES шифрует блоки по 16 байт, не больше и не меньше. Если вы хотите зашифровать сообщение, которое может быть длиннее 16 байт, вам нужно решить, как данные будут разбиты на блоки и затем собраны заново. Основной алгоритм разделения называется ECB : это «просто разделение» на блоки, зашифрованные индивидуально. Известно, что ECB является слабым с данными реального мира, потому что он пропускает информацию о том, какие блоки открытого текста равны друг другу (они будут одинаково зашифрованы), и такая избыточность часто возникает в «нормальных» данных.

Таким образом, необходимо каким-то образом «рандомизировать» блоки данных, чтобы избыточность данных была скрыта. Режим CBC выполняет это посредством «цепочки»: обработка блока зависит от результата шифрования предыдущего блока. А именно, блок открытого текста для шифрования объединяется (с побитовым XOR) с выводом предыдущего блока шифрования.

Важным моментом здесь является то, что первый блок для шифрования (первые 16 байтов данных) не имеет «предыдущего блока», поэтому XOR не имеет ничего общего с. Это решается путем выбора «случайного IV», то есть последовательности из 16 случайных байтов, которая будет использоваться в качестве «блока -1» для этапа XORing. IV должен быть известен расшифровывающей стороне (иначе он не будет знать, с чем XOR расшифрованный блок, и первые 16 байтов данных не будут понятны). Яркая сторона в том, что IV не должен быть секретным; он ДОЛЖЕН быть выбран равномерно (это не может быть счетчик, увеличенный для каждого сообщения), но он может быть передан «в открытом виде», обычно вдоль самого зашифрованного сообщения.

Так что вам нужно немного побеспокоиться о IV, и я ничего не вижу в коде Java или Ruby. Обычно в Java по умолчанию используется ECB (следовательно, IV вообще нет). Если в CBC по умолчанию используется значение «все ноль» в CBC (что концептуально небезопасно), то вполне нормально, что вы можете расшифровать первый блок (записать его, он «просто работает»), но в равной степени нормально что он не работает для последующих блоков.

Поэтому я предлагаю вам явно использовать CBC (в Java используйте "AES/CBC/PKCS5Padding" в качестве имени алгоритма, а не "AES") и управлять IV (который затем должен быть передан; вы можете принять соглашение для объединения IV непосредственно перед зашифрованное сообщение).

Несколько других заметок:

  • Заполнение - это добавление некоторых данных в открытый текст, чтобы у вас была подходящая длина ввода. CBC требует, чтобы длина ввода была кратна размеру блока (16 байт). PKCS # 5 - это популярный метод, при котором вы добавляете не менее 1 байта, не более 16 байтов, так что все они имеют значение n , где n - это число добавлены байты. Затем получатель может узнать (однозначно), сколько байтов было добавлено, и удалить их. Java может добавить заполнение для вас, и я полагаю, что Ruby также может автоматически обработать заполнение, если вас попросят.

  • В коде Java вы используете key.getBytes(). Я полагаю, что key является String. Помните, что getBytes() кодирует строку в соответствии с набором символов платформы по умолчанию, который не всегда одинаков во всем мире Вы сэкономите немного беспокойства, указав явную кодировку. Кроме того, поскольку вы хотите использовать 128-битный ключ, но вы получаете что-то на стороне Ruby только с "AES-256", то я предполагаю, что вы на самом деле используете 256-битный ключ на стороне Java. Я предполагаю, что ваша строка key представляет собой шестнадцатеричное представление вашего ключа в виде 32 символов. key.getBytes() не интерпретирует шестнадцатеричные цифры; он кодирует сами символы, получая 32-байтовый массив - и 32 байта, то есть 256 бит, а не 128.

1 голос
/ 24 марта 2010

Я согласен с вашим подозрением по поводу заполнения. Обивка PKCS # 5 «округлит» ваш открытый текст до границы следующего целого блока; если вы дадите ему целое количество блоков, он добавит один целый блок заполнения.

Если бы я был вами, я бы посмотрел, что именно вы получаете, когда вы спрашиваете JCE о AES - я подозреваю, что вы получаете AES / CBC / PKCS5Padding, но, возможно, более разумно явно запросить то, что вы хочу. Точно так же вам нужно посмотреть, что именно вы получаете в конце Ruby - может ли «мусор» в конце расшифровки быть байтами заполнения? Прочтите спецификацию PKCS # 5 и сравните ее с тем, что вы получаете.

Я немного обеспокоен тем, что вы используете AES-128 на стороне Java, но (по-видимому) AES-256 на стороне Ruby / OpenSSL. Такое несоответствие гарантированно не сработает, но вы говорите, что шифрование работает, по крайней мере, для коротких сообщений. Вполне возможно, что вы на самом деле получаете AES-256 из java (опять же, если вы спросите его «AES», что вы на самом деле получаете?) Или что-то странное происходит на стороне рубина, которая обнаружение, что вы используете 128-битный ключ, и выполнение того, что он считает правильным.

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

...