Шифрование AES в Oracle и MySQL дает разные результаты - PullRequest
7 голосов
/ 01 сентября 2011

Мне нужно сравнить данные между базой данных Oracle и базой данных MySQL.

В Oracle данные сначала шифруются с помощью алгоритма AES-128, а затем хешируются.Это означает, что невозможно восстановить данные и расшифровать их.

Те же данные доступны в MySQL и в виде обычного текста.Чтобы сравнить данные, я попытался зашифровать и затем хэшировать данные MySQL, выполнив те же действия, что и в Oracle.

После многих попыток я наконец-то обнаружил, что aes_encrypt в MySQL возвращает результаты, отличные отодин в Oracle.

-- ORACLE:
-- First the key is hashed with md5 to make it a 128bit key:
raw_key := DBMS_CRYPTO.Hash (UTL_I18N.STRING_TO_RAW ('test_key', 'AL32UTF8'), DBMS_CRYPTO.HASH_MD5);

-- Initialize the encrypted result
encryption_type:= DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5;

-- Then the data is being encrypted with AES:
encrypted_result := DBMS_CRYPTO.ENCRYPT(UTL_I18N.STRING_TO_RAW('test-data', 'AL32UTF8'), encryption_type, raw_key);

Результат для кода оракула будет: 8FCA326C25C8908446D28884394F2E22

-- MySQL
-- While doing the same with MySQL, I have tried the following:
SELECT hex(aes_encrypt('test-data', MD5('test_key'));

Результат для кода MySQL будет: DC7ACAC07F04BBE0ECEC6B6934CF79FE

Я что-то упустил?Или методы шифрования между разными языками не одинаковы?

ОБНОВЛЕНИЕ: Согласно комментариям ниже, я считаю, что я должен упомянуть тот факт, что результатом DBMS_CRYPTO.Hash в Oracle являетсятакой же, как результат, возвращаемый функцией MD5 в MySQL.

Также использование CBC или CBE в Oracle дает тот же результат, поскольку IV не передается функции, таким образом,используется значение по умолчанию для IV: NULL

BOUNTY: Если кто-то может проверить мой последний комментарий, и тот факт, что при использовании одинакового заполнения с обеих сторон, даст одинаковые результатыполучает вознаграждение:

@ rossum Заполнение по умолчанию в MySQL - PKCS7, ммм ... О ... В Oracle используется PKCS5, не могу поверить, что я этого не заметил.Благодарю.(Кстати, у Oracle нет опции PAD_PKCS7, по крайней мере, не в 11g)

Ответы [ 3 ]

8 голосов
/ 10 сентября 2011

Функция MySQL MD5 возвращает строку из 32 шестнадцатеричных символов.Он помечен как двоичная строка, но это не 16-байтовые двоичные данные, которые можно было бы ожидать.

Таким образом, чтобы исправить это, эту строку необходимо преобразовать обратно в двоичные данные:

SELECT hex(aes_encrypt('test-data', unhex(MD5('test_key'))));

Результат:

8FCA326C25C8908446D28884394F2E22

Это снова строка из 32 шестнадцатеричных символов.Но в остальном это тот же результат, что и в Oracle.

И кстати:

  • MySQL использует заполнение PKCS7.
  • Заполнение PKCS5 и дополнение PKCS7 - одно и то же.Таким образом, опция заполнения Oracle является правильной.
  • MySQL использует режим блочного шифрования ECB.Поэтому вам придется соответствующим образом адаптировать код.(Это не имеет никакого значения для первых 16 байтов.)
  • MySQL не использует вектор инициализации (так же, как ваш код Oracle).
  • MySQL использует нестандартное свертывание ключей,Поэтому для достижения того же результата в MySQL и Oracle (или .NET или Java) используйте только ключи длиной 16 байт.
1 голос
/ 31 июля 2014

Просто хотел бы дать полное решение для манекенов, основанное на очень дидактическом ответе @ Codo.

РЕДАКТИРОВАТЬ: Чтобы быть точным в общих случаях, я нашел это: - "Заполнение PKCS # 5 является подмножествомДополнение PKCS # 7 для блоков размером 8 байт ".Строго говоря, PKCS5 не может быть применен к AES;они означают PKCS7, но используют их имена взаимозаменяемо.

О PKCS5 и PKCS7

/ * MySQL использует нестандартное сворачивание ключа.* Чтобы достичь того же результата в MySQL и Oracle (или .NET или Java), используйте только ключи длиной 16 байт (32 шестнадцатеричных символа) = 128-битное шифрование AES, MySQL AES_encrypt по умолчанию.* * Это означает, что MySQL допускает любую длину ключа от 16 до 32 байтов для 128-битного шифрования AES, но стандартная AES не позволяет использовать ключ не из 16 байтов, поэтому не используйте его, так как вы не сможетеиспользовать стандартную AES-дешифровку на другой платформе для ключей длиной более 16 байт, и был бы вынужден программировать свертывание ключа MySQL на этой другой платформе с использованием XOR и т. д. (это уже есть, но зачем делать странные-стандартные вещи, которые могут измениться, когда MySQL решит, и т. д.).Более того, я думаю, они говорят, что алгоритм, выбранный MySQL для этих случаев, является действительно плохим выбором по уровню безопасности ... * /

- ### ORACLE:

- Первыйключ хешируется с помощью md5, чтобы сделать его 128-битным (16 байтов, 32 шестнадцатеричных символа):

raw_key := DBMS_CRYPTO.Hash (UTL_I18N.STRING_TO_RAW ('test_key', 'AL32UTF8'), DBMS_CRYPTO.HASH_MD5); 

- MySQL использует AL32UTF8, по крайней мере по умолчанию

- Конфигурироватьпараметры шифрования:

encryption_type:= DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_ECB + DBMS_CRYPTO.PAD_PKCS5; 

- Строго говоря, это действительно PKCS7.

/ * И я выбираю ECB как более быстрый, если он применяется, и @Codo сказал, что он правильный, но в качестве стандартного (Oracle) AES128 будет принимать только 16-байтовые ключи, CBC также работает, так как я считаю, что это не такприменяется к 16-байтовому ключу.Может ли кто-нибудь это подтвердить?* /

- Затем данные шифруются с помощью AES:

encrypted_result := DBMS_CRYPTO.ENCRYPT(UTL_I18N.STRING_TO_RAW('test-data', 'AL32UTF8'), encryption_type, raw_key);

- Результат является двоичным (varbinary, blob).

- Можно использовать RAWTOHEX (), если вы хотите представить его в шестнадцатеричных символах.

В случае, если вы используете непосредственно 16-байтовую хэш-фразу в представлении шестнадцатеричных символов или 32 шестнадцатеричных случайных символа:

raw_key := HEXTORAW(32_hex_key)
encryption_type := 6 + 768 + 4096 -- (same as above in numbers; see Oracle Docum.) 
raw_data := UTL_I18N.STRING_TO_RAW('test-data', 'AL32UTF8')

encrypted_result := DBMS_CRYPTO.ENCRYPT( raw_data, encryption_type, raw_key )

- Расшифровка ORACLE:

decrypted_result := UTL_I18N.RAW_TO_CHAR( CRYPTO.DECRYPT( raw_data, encryption_type, raw_key ), 'AL32UTF8' )

- В SQL:

SELECT 
  UTL_I18N.RAW_TO_CHAR( 
    DBMS_CRYPTO.DECRYPT( 
    UTL_I18N.STRING_TO_RAW('test-data', 'AL32UTF8'), 
    6 + 768 + 4096, 
    HEXTORAW(32_hex_key) 
  ) , 'AL32UTF8') as "decrypted" 
FROM DUAL;

- ### Расшифровка MySQL:

- Функция MySQL MD5 возвращает строку из 32 шестнадцатеричных символов (= 16 байт = 128 бит).

- Она помечена как двоичная строка, но это не 16-байтовые двоичные данные, которые можно ожидать.

- ПРИМЕЧАНИЕ. Обратите внимание: в некоторых версиях вид возврата функций MD5, SHA1 и т. Д. Изменился с версии 5.3.x.См. Руководство по MySQL 5.7.

- чтобы исправить это, эту строку необходимо преобразовать обратно из шестнадцатеричных в двоичные данные с помощью unHex ():

SELECT hex(aes_encrypt('test-data', unhex(MD5('test_key')));

PS: я бы порекомендовал прочитатьулучшенное объяснение в MySQL 5.7 Manual, которое, кроме того, теперь позволяет гораздо больше настроек. Улучшено описание MySQL AES_ENCRYPT из руководства v5.7

0 голосов
/ 01 сентября 2011

Может быть CBC против ECB.Комментарий внизу этой страницы: http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html говорит, что функция mysql использует ECB

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...