2011-09-01 32 views
7

Necesito comparar datos entre una base de datos Oracle y una base de datos MySQL.Encriptación AES en Oracle y MySQL están dando resultados diferentes

En Oracle, los datos se cifran primero con el algoritmo AES-128 y luego se procesan los hash. Lo que significa que no es posible recuperar los datos y descifrarlos.

Los mismos datos están disponibles en MySQL y en texto sin formato. Entonces, para comparar los datos, intenté encriptar y luego mezclar los datos de MySQL mientras seguía los mismos pasos que hice en Oracle.

Después de muchos intentos, finalmente descubrí que el aes_encrypt en MySQL arroja resultados diferentes a los de 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); 

El resultado para el código de Oracle será: 8FCA326C25C8908446D28884394F2E22

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

El resultado para el código de MySQL será: DC7ACAC07F04BBE0ECEC6B6934CF79FE

Me estoy perdiendo algo? ¿O los métodos de encriptación entre diferentes idiomas no son los mismos?

ACTUALIZACIÓN: De acuerdo con los comentarios a continuación, creo que debería mencionar el hecho de que el resultado de DBMS_CRYPTO.Hash en Oracle es el mismo que el resultado devuelto por la función MD5 en MySQL.

También usando CBC o CBE en Oracle da el mismo resultado, ya que el IV no se pasa a la función, por lo que el valor predeterminado de la IV se usa que es NULL

BOUNTY: Si alguien puede verificar mi último comentario, y el hecho de que si se utiliza el relleno misma en ambos lados, rendirá mismos resultados obtiene la recompensa:

@rossum el relleno por defecto en MySQL es PKCS7, mmm ... Oh .. En Oracle está usando PK CS5, no puedo creer que no haya notado eso. Gracias. (Por cierto Oracle no tiene la opción PAD_PKCS7, no en al menos 11 g)

+0

A primera vista Sospecho que el problema sea aquí: ' 'test_key', 'AL32UTF8'' Me parece que MySQL tiene un conjunto de caracteres diferente en sus datos y por tanto diferentes de datos antes de aplicar el cifrado. – Johan

+0

Sospecho que el cifrado debe ser el mismo, por lo que me aseguraré de que las claves sean las mismas. es decir, ¿MD5 devuelve cadena hexadecimal o bytes sin procesar. Si es hexadecimal, ¿qué pasa con el caso? Lamentablemente, no tengo acceso a Oracle con DBMS_CRYPTO instalado. – Sodved

+0

@Sodved Sí, el hashing MD5 está dando el mismo resultado en ambas bases de datos, que es '8C32D1183251DF9828F929B935AE0419'. Y dado que ese es el caso de @Johan, no debería ser un problema de codificación ya que el hash MD5 es el mismo – Dan

Respuesta

8

MySQL MD5 función devuelve una cadena de 32 caracteres hexadecimales. Está marcado como una cadena binaria, pero no son los datos binarios de 16 bytes que cabría esperar.

Así que para solucionarlo, esta cadena se debe convertir de nuevo a los datos binarios:

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

El resultado es:

8FCA326C25C8908446D28884394F2E22 

Es más una cadena de 32 caracteres hexadecimales. Pero de lo contrario es el mismo resultado que con Oracle.

Y por cierto:

  • MySQL utiliza el relleno PKCS7.
  • El relleno PKCS5 y el relleno PKCS7 son lo mismo. Entonces la opción de relleno de Oracle es correcta.
  • MySQL utiliza el modo de cifrado de bloques ECB. Por lo tanto, deberá adaptar el código en consecuencia. (No hace ninguna diferencia para los primeros 16 bytes.)
  • MySQL no utiliza ningún vector de inicialización (lo mismo que su código Oracle).
  • MySQL usa llaves plegables no estándar. Entonces, para lograr el mismo resultado en MySQL y Oracle (o .NET o Java), solo use claves de 16 bytes de largo.
0

Podría ser CBC vs BCE. Comentario en la parte inferior de esta página: http://dev.mysql.com/doc/refman/5.5/en/encryption-functions.html dice que la función mysql usa ECB

+0

He visto ese comentario y he intentado con ECB en Oracle para ver si da un resultado diferente, pero ese no fue el caso. Que en realidad es el resultado esperado porque ECB y CBC son básicamente los mismos si el IV no se envió a la función de cifrado. (El valor predeterminado es 'NULL') – Dan

+0

@Dan: solo son lo mismo si se está encriptando un solo bloque. Con el relleno, lo que comenzó exactamente como un solo bloque (16 bytes) puede extenderse a dos bloques debido al relleno. – rossum

1

Simplemente me gustaría dar la solución completa para los tontos basada en la respuesta muy didáctica de @ Codo.

EDIT: Para ser exacto en casos generales, he encontrado esto: - "PKCS # 5 relleno es un subconjunto de PKCS # 7 relleno para tamaños de bloque de 8 bytes". Así que estrictamente PKCS5 no se puede aplicar a AES; quieren decir PKCS7 pero usan sus nombres indistintamente.

About PKCS5 and PKCS7

/* MySQL utiliza el plegado de una no estándar una tecla. * Para obtener el mismo resultado en MySQL y Oracle (o .NET o Java), solo usa claves de 16 bytes de longitud (32 símbolos hexadecimales) = 128 bits cifrado AES, el MySQL AES_encrypt predeterminado. * * Esto significa que MySQL admite cualquier longitud de clave entre 16 y 32 bytes para encriptación AES de 128 bits, pero no está permitido por el estándar AES utilizar una clave que no sea de 16 bytes, así que no lo use como no lo ganó t poder utilizar el descifrado AES estándar en otra plataforma para claves con más que 16 bytes, y estaría obligado a programar el plegado de MySQL de la clave en esa otra plataforma, con el material XOR, etc. (es ya está ahí fuera, pero ¿por qué hacer cosas extrañas no estándar thay puede cambiar cuando MySQL decida, etc.). Por otra parte, creo que dicen que el algoritmo elegido por MySQL para aquellos casos es una muy mala elegir en un nivel de seguridad ... */

- ### ORACLE:

- En primer lugar la clave se hash con md5 para que sea una clave de 128 bits (16 bytes, símbolos 32 hex):

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

- MySQL utiliza AL32UTF8, al menos de forma predeterminada

- Configurar los parámetros de cifrado:

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

- Estrictamente hablando, es realmente PKCS7.

/* Y elijo BCE por ser más rápido si se aplica y @Codo dijo que es la correcta, pero como estándar (Oracle) AES128 sólo aceptará 16 teclas bytes, CBC también funciona, ya que creo que no son aplicado a una clave de 16 bytes. ¿Alguien podría confirmar esto?*/

- A continuación, los datos se cifran con AES:

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

- El resultado es binario (varbinary, blob).

- Se puede usar RAWTOHEX() para si desea representarlo en caracteres hexadecimales.

En caso de usar directamente los 16 bytes frase de contraseña de trazos en la representación de caracteres hexadecimales o 32 caracteres hexadecimales aleatorios:

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 descifrado:

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

- En 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; 

- ### Desencriptación de MySQL:

- La función MD5 de MySQL devuelve una cadena de 32 caracteres hexadecimales (= 16 bytes = 128 bits).

- Está marcado como una cadena binaria, pero no son los 16 bytes de datos binarios que uno esperaría.

- NOTA: Tenga en cuenta que el tipo de retorno de las funciones MD5, SHA1, etc. ha cambiado en algunas versiones desde 5.3.x. Vea el manual de MySQL 5.7.

- Así que para solucionarlo, esta cadena debe ser convertida de nuevo a partir hexagonal para datos binarios con unHex():

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

PS: Yo recomendaría que lea la explicación mejorado en MySQL 5.7 Manual, que, además, ahora permite una configuración mucho más. MySQL AES_ENCRYPT improved explanation from v5.7 manual

Cuestiones relacionadas