Delphi DEC library (Rijndael) cifrado

Estoy tratando de usar la biblioteca DEC 3.0 ( Delphi Encryption Compedium Part I ) para cifrar los datos en Delphi 7 y enviarlos a un script PHP a través de POST, donde los estoy desencriptando con mcrypt (RIJNDAEL_256, modo ECB).

Parte Delphi:

uses Windows, DECUtil, Cipher, Cipher1; function EncryptMsgData(MsgData, Key: string): string; var RCipher: TCipher_Rijndael; begin RCipher:= TCipher_Rijndael.Create(KeyStr, nil); RCipher.Mode:= cmECB; Result:= RCipher.CodeString(MsgData, paEncode, fmtMIME64); RCipher.Free; end; 

Parte de PHP:

 function decryptMsgContent($msgContent, $sKey) { return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $sKey, base64_decode($msgContent), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)); } 

El problema es que el descifrado de PHP no funciona y la salida es incomprensible, a diferencia de los datos reales.

Por supuesto, la Key Delphi y la Key PHP $Key son la misma cadena de 24 caracteres.

Ahora sé que DEC 3.0 es antiguo y está desactualizado, y no soy un experto en cifrado y no puedo saber si la implementación es en realidad Rijndael 256. Tal vez alguien pueda decirme en qué se diferencia esta implementación del mcrypt de PHP con RIJNDAEL_256. Tal vez el tamaño de la clave es diferente, o el tamaño del bloque, pero no puede distinguirlo del código. Aquí hay un extracto de Cipher1.pas:

 const { don't change this } Rijndael_Blocks = 4; Rijndael_Rounds = 14; class procedure TCipher_Rijndael.GetContext(var ABufSize, AKeySize, AUserSize: Integer); begin ABufSize := Rijndael_Blocks * 4; AKeySize := 32; AUserSize := (Rijndael_Rounds + 1) * Rijndael_Blocks * SizeOf(Integer) * 2; end; 

Pregunta de lado:

Sé que no se recomienda el modo ECB y usaré CBC tan pronto como el ECB esté funcionando. La pregunta es, ¿tengo que transmitir el IV generado en Delphi al script PHP también? ¿O saber que la clave es suficiente, como para el BCE?

Está llamando a TCipher.Create (const Password: String; AProtection: TProtection); constructor, que calculará un hash de la contraseña antes de pasarla al método Init, que realiza la progtwigción de claves estándar del algoritmo implementado. Para anular esta derivación de clave, use:

 function EncryptMsgData(MsgData, Key: string): string; var RCipher: TCipher_Rijndael; begin RCipher:= TCipher_Rijndael.Create('', nil); RCipher.Init(Pointer(Key)^,Length(Key),nil); RCipher.Mode:= cmECB; Result:= RCipher.CodeString(MsgData, paEncode, fmtMIME64); RCipher.Free; 

fin;

OK, para resumir, hubo 3 problemas con mi código:

  1. Debido a mi escasa comprensión de mcrypt y los cifrados en general, MCRYPT_RIJNDAEL_256 se refiere al bloque de 128 bits y no se refiere al tamaño de clave. Mi elección correcta debería haber sido MCRYPT_RIJNDAEL_128, que es el estándar AES y también es compatible con DEC 3.0.

  2. DEC tiene su propia derivación de clave predeterminada, por lo que necesitaba evitarla para no tener que implementarla también en PHP. En realidad, estoy usando mi propio algoritmo de derivación de claves que fue fácil de reproducir en PHP (primeros 32 caracteres de sha1 (clave)).

  3. DEC no rellena el texto simple a un múltiplo del tamaño de bloque del cifrado, como mcrypt espera, así que tuve que hacerlo manualmente.

Proporcionar código de trabajo a continuación:

Delphi:

 uses Windows, DECUtil, Cipher, Cipher1, CryptoAPI; function EncryptMsgData(MsgData, Key: string): string; var RCipher: TCipher_Rijndael; KeyStr: string; begin Result:= ''; try // key derivation; just making sure to feed the cipher a 24 chars key HashStr(HASH_SHA1, Key, KeyStr); KeyStr:= Copy(KeyStr, 1, 24); RCipher:= TCipher_Rijndael.Create('', nil); RCipher.Init(Pointer(KeyStr)^, Length(KeyStr), nil); RCipher.Mode:= cmECB; Result:= RCipher.CodeString(MsgData + StringOfChar(#0,16-(Length(MsgData) mod 16)), paEncode, fmtMIME64); RCipher.Free; except end; end; 

PHP:

 function decryptMsgContent($msgContent, $sKey) { $sKey = substr(sha1(sKey), 0, 24); return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $sKey, base64_decode($msgContent), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB), MCRYPT_RAND))); } 

Una clave de 256 bits que encontré es de 32 caracteres, o 32 bytes. No 24. Este puede ser el problema.

[EDITAR]

Combiné las ideas de todos (análisis, etc.) en una sola idea con una solución.

Además, está utilizando la combinación de códigos (- debería ser Encodestring (

He pegado el código fuente de Encrypt and Decrypt a continuación:


 function EncryptMsgData(MsgData, Key: AnsiString): AnsiString; var RCipher: TCipher_Rijndael; begin RCipher:= TCipher_Rijndael.Create('', nil); RCipher.Init(Pointer(Key)^,Length(Key),nil); RCipher.Mode:= cmCBC; Result:= RCipher.EncodeString(MsgData); RCipher.Free; end; function DecryptMsgData(MsgData, Key: AnsiString): AnsiString; var RCipher: TCipher_Rijndael; begin RCipher:= TCipher_Rijndael.Create('',nil); RCipher.Init(Pointer(Key)^,Length(Key),nil); RCipher.Mode:= cmCBC; Result:= RCipher.DecodeString(MsgData); RCipher.Free; end; 

Use eso con una clave de 32 caracteres y obtendrá un cifrado y descifrado adecuados.

Para almacenar y utilizar los datos encriptados como una cadena, es posible que desee utilizar Base64Encode (

Pero no te olvides de Base64Decode antes de descifrar.

Esta es la misma técnica necesaria para Blowfish. A veces, los personajes son en realidad como un retroceso, y realizan la función en lugar de mostrarse en la pantalla. Base64Encode básicamente convierte los caracteres a algo que puede mostrar en texto.

Antes de transferir los datos codificados a través de Internet o a otra aplicación en el mismo u otro idioma, DEBE codificar y decodificar en base 64 para no perder datos. ¡No lo olvides también en PHP!