1

I am using a Delphi component from chillkat which does AES encryption for me. It works like a charm and the server accepts my encrypted requests. So I tried to create a php pendant by using mcrypt. But the PHP mcypt result is different in comparison with the Delphi Chillcat result - even if all the parameters are the same. Therefore the server rejects the php requests.

All the encryption settings are the same:

  • Cipher Name: AES 128
  • Cipher mode: ECB
  • Padding scheme: Pad with NULL
  • Key length: 128
  • Key: 1234567890ABE1234567890ABE1234DB
  • String to encrypt: This is a really cool teststring

This is the little php script:

<?php 
    $key = '1234567890ABE1234567890ABE1234DB';
    function string_encrypt($string, $key) {
        $crypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_ECB);
        return $crypted_text;
    }

    function string_decrypt($encrypted_string, $key) {
        $decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_string, MCRYPT_MODE_ECB);
        return trim($decrypted_text);
    }

    echo $test_str = 'This is a really cool teststring';   echo '<br />';
    $enc_str = string_encrypt($test_str, $key);
    echo bin2hex($enc_str);                                     echo '<br />';
    echo string_decrypt($enc_str, $key);                        echo '<br />';

    ?>

The php output is: e355fbcd91ada4b835e1b030cc9741759219f59fe441ba62e628eca2e8289eb3

This is the Delphi Code:

function encrypt(s:PWideChar;mode,padding:integer;algo,cipher,keylength:string):string;
var
crypt: HCkCrypt2;
success: Boolean;
ivHex: PWideChar;
keyHex: PWideChar;
encStr: PWideChar;
decStr: PWideChar;

begin
crypt := CkCrypt2_Create();

//  AES is also known as Rijndael.
CkCrypt2_putCryptAlgorithm('aes');
// "pki", "aes", "blowfish", "blowfish2", "des", "3des", "rc2", "arc4", "twofish", "pbes1" and "pbes2"

//  CipherMode may be "ecb" or "cbc"
CkCrypt2_putCipherMode(crypt,'ecb');

//  KeyLength may be 128, 192, 256
try
  CkCrypt2_putKeyLength(crypt,128);
Except
  showmessage('The encryption key you have used seems to be invalid');
end;


//  The padding scheme determines the contents of the bytes
//  that are added to pad the result to a multiple of the
//  encryption algorithm's block size.  AES has a block
//  size of 16 bytes, so encrypted output is always
//  a multiple of 16.

{
Possible values are:

0 = RFC 1423 padding scheme: Each padding byte is set to the number of padding bytes.
If the data is already a multiple of algorithm's block size bytes, an extra block is
appended each having a value equal to the block size. (for example, if the algorithm's
block size is 16, then 16 bytes having the value 0x10 are added.). (This is also known as
PKCS5 padding: PKCS #5 padding string consists of a sequence of bytes, each of which
is equal to the total number of padding bytes added. )

1 = FIPS81 (Federal Information Processing Standards 81) where the last byte contains
the number of padding bytes, including itself, and the other padding bytes are set to random values.

2 = Each padding byte is set to a random value. The decryptor must know
how many bytes are in the original unencrypted data.

3 = Pad with NULLs. (If already a multiple of the algorithm's block size,
no padding is added).

4 = Pad with SPACE chars(0x20). (If already a multiple of algorithm's block size, no padding is added).
}
CkCrypt2_putPaddingScheme(crypt,3);

//  EncodingMode specifies the encoding of the output for
//  encryption, and the input for decryption.
//  It may be "hex", "url", "base64", or "quoted-printable".
CkCrypt2_putEncodingMode(crypt,'hex');

//  An initialization vector is required if using CBC mode.
//  ECB mode does not use an IV.
//  The length of the IV is equal to the algorithm's block size.
//  It is NOT equal to the length of the key.
ivHex := '';
CkCrypt2_SetEncodedIV(crypt,ivHex,'hex');

//  The secret key must equal the size of the key.  For
//  256-bit encryption, the binary secret key is 32 bytes.
//  For 128-bit encryption, the binary secret key is 16 bytes.

keyHex := '1234567890ABE1234567890ABE1234DB';
CkCrypt2_SetEncodedKey(crypt,keyHex,'hex');

//  Encrypt a string...
//  The input string is 44 ANSI characters (i.e. 44 bytes), so
//  the output should be 48 bytes (a multiple of 16).
//  Because the output is a hex string, it should
//  be 96 characters long (2 chars per byte).


 //encryption
 if mode = 0 then
 begin
   encStr := CkCrypt2__encryptStringENC(crypt,s);
   result := encStr;
 end
 else
 begin
  result := CkCrypt2__decryptStringENC(crypt,s);
 end;


CkCrypt2_Dispose(crypt);
End;

The chillkat Delphi component's output is: 780F849AB30690433409D4FB7B3357735296A6E76D3AA6B6D6C769BE99F32041

I thought both outputs should produce the same value, as all the input parameters are equal, right ?

Mr. Ajin
  • 325
  • 1
  • 3
  • 16
  • Have you seen [all these](http://stackoverflow.com/questions/tagged/delphi+php+encryption)? – Jan Doggen Jun 09 '15 at 14:11
  • I have just red them. There were a few hints which I tried to implement, but it does not work. Although in one thread this website was mentioned: [link](http://aes.online-domain-tools.com/) and this site is able to encrypt my Delphi code and vice versa. – Mr. Ajin Jun 09 '15 at 15:12

2 Answers2

2

MCrypt expects the key to be a binary string, but you pass a hex encoded string into it.

Use

$key = hex2bin($key);

or

$key = pack('H*', $key);

depending on PHP support. This must be done before calling mcrypt_encrypt().


Security:

Don't ever use ECB mode. It's not semantically secure. There is a lot that an attacker can get from ciphertexts without decrypting them. You need to use at the very least CBC mode with a random IV. You should also have an authentication tag of your ciphertexts.

This answer gives you every thing you need to know about this. One thing left, don't use MCrypt. It's an old unmaintained library.

This answer is also very helpful in that regard with a different way of achieving the same thing.

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • The output does not change if I add this line. Besides, I had to add the function hex2bin manually, since it could not be found on my server. – Mr. Ajin Jun 09 '15 at 14:59
  • That's impossible. The key is different, so the result must be different. In any case, I added an alternative way of decoding hex. – Artjom B. Jun 09 '15 at 15:27
  • "I had to add the function hex2bin manually, since it could not be found on my server." What version of PHP are you running? – Scott Arciszewski Jun 09 '15 at 15:49
  • another problem is in "String to encrypt: This is a really cool teststring" what does it even mean ? ciphers do not work with letters/strings - they work with raw bytes! so how is the length and/or end of string marked in the raw binary data? and how is the letters of the string converted to bytes ? Depending on his code and Delphi version, the string might be represented in standard 7-bits ANSI codepage, UTF8 ( for this string would be the same) or 16-bits UCS-2 (standard for Delphi 2009 and forth) with his code i totally cannot say how does it work inside... – Arioch 'The Jun 10 '15 at 00:21
  • So if i would make the code, i would 1) document for myself the EXACT specification of string-to-binary and binary-to-string conversions, considering lenghst, charsets and whatever is important to my task. Then 2) i would implement conversion from strings to raw binary data and back in both PHP and Delphi, and compare the result matches. I would never let this intimate and unpredictable part to the guesswork of randomly using some other lib function without checkign its parameters. 3) would use Delphi native Spring4Delphi or TLockBox3 libs for raw binary (never strings!) AES crypto – Arioch 'The Jun 10 '15 at 00:24
  • @Arioch That's a good point. I forgot too much about delphi to provide an answer in that regard. You're welcome to provide your own answer. – Artjom B. Jun 10 '15 at 06:30
  • I do not know a thing on PHP though. That is just a common misconception that one can cypher a string that often backfires – Arioch 'The Jun 10 '15 at 09:16
0

thanks to your your nice inputs, I was able to receive a positive answer from the server with the following 4 lines of code:

$key = pack('H*', "*5DB");
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,$mytxt, MCRYPT_MODE_ECB);
$hex2 = bin2hex($ciphertext);
echo strtoupper($hex2);

However, I have learned that

  • ECB is unsecure
  • mcrypt is old and unmaintained

I will check alternatives and update my code accordingly. Thanks again !

Mr. Ajin
  • 325
  • 1
  • 3
  • 16