Шифрование AES в Oracle и MySQL дает разные результаты

мне нужно сравнить данные между базой данных 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);

результатом для кода oracle будет: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

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

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

3 ответов


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

чтобы исправить это, эта строка должна быть преобразована обратно в двоичные данные:

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

результат:

8FCA326C25C8908446D28884394F2E22

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

и кстати:

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

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

изменить: Для того, чтобы быть точным в общих случаях, я нашел это: - "PKCS#5 padding является подмножеством PKCS#7 padding для 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 decrypt в другой платформе для ключей с более чем 16 байт, и будет obligued программы складывать в 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.

/* и я выбираю ЕЦБ для того, чтобы быть быстрее, если применяется и @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 Decryption:

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 расшифровка:

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

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

-- Примечание: обратите внимание, что вид возврата функций MD5, SHA1 и т. д. изменился в некоторых версиях с 5.3.х. См. В руководстве по работе с MySQL 5.7.

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

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

С. П.: Я бы рекомендовал прочитать улучшенное объяснение в MySQL 5.7 руководство, которое более того теперь позволяет намного больше конфигурации. MySQL aes_encrypt улучшенное объяснение от v5.7 руководство


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