Шифрование 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, но используют их имена взаимозаменяемы.
/* 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