Incorrect key size when migrating Crypto ++ AES encryption to PHP mcrypt

I used to be able to port some C ++ CryptoPP Rijndael_128 CBC code to MCrypt PHP, but now I'm having problems with CFB mode. The C ++ and PHP results are not the same (well, the first byte matches, but that could be a match and everything else not). With some diagnostics, it looks like PHP mcrypt is not setting the key length correctly?

Here's C ++ (diagnostics and sundries removed for simplicity):

CFB_Mode<AES>::Encryption encryptor(g_encrypt_key, AES::DEFAULT_KEYLENGTH, g_encrypt_iv);

StringSource ss( sInput.c_str(), true, 
        new StreamTransformationFilter( encryptor, 
            new HexEncoder( new StringSink( sEncryptedOut ) )
        ));

      

And here's PHP:

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CFB, '')
mcrypt_generic_init($cipher, $g_encrypt_key, $g_encrypt_iv);

$sEncryptedOutput = mcrypt_generic( $cipher, $sInput);
mcrypt_generic_deinit($cipher);
mcrypt_module_close($cipher);

      

g_encrypt_key

and g_encrypt_iv

are equal to 16 bytes, and the bytes correspond to the C ++ and PHP versions. For the PHP version, it is a binary string built from bytes (yes, I checked that they are identical).

I've added calls to the PHP version to check block size, key size, etc. $cipher

... Block size and size iv are 16; the supported key sizes are reported as 16, 24 and 32 - all as expected.

Where I think the problem is that keyize is reported as 32 bytes. Looking at the mcrypt docs, the only way to configure the key is to provide the key of the required size. But I am transferring a 16 byte key! So why is it reporting the presence of a 32 byte key? If CFB mode is supposed to use a 32-byte key, then why is CryptoPP accepting it as well? What's the solution? Can I force PHP to use the 16 byte key that was provided? Or is there a parameter that I am missing, which by default differs from another parameter in CryptoPP than in MCrypt?

I use CFB mode because I want to minimize the length of the resulting encrypted data. A few bytes to be added in addition are significant in this application.

I need to be able to encrypt / decrypt in C ++, but only encrypt in PHP. AES is perhaps too large for my application - the minimum I need is "good byte scrambling", so the function of individual bytes in the data is not obvious.

+2


source to share


3 answers


It has been a while, but I had some similar issues with mcrypt and openSSL using CFB a couple of years ago. In the end I found that mcrypt was using a different default loopback size than openssl in CFB mode. That is, I believe that openSSL AES128 in CFB used a block size and feedback size of 128 bits, while mcrypt used a block size of 128 bits and a feedback size of 8 bits. I have no way of confirming this, it was just speculation at the time you read the old forum posts. Regardless of the truth of this theory, I was not the only person or the first to have this problem.

The solution for me was to use nOFB like you do. According to the PHP reference, mcrypt MCRYPT_MODE_NOFB

forces the loopback to equal the block size of the algorithm, in this case a 128 bit block / loopback for AES128 (Rijndael), which matches what the manpage for the mcrypt module claims is nOFB. This is good as everything I have found says the nOFB feedback is synchronous with the block size. So both mcrypt and OpenSSL in nOFB were now 128-bit / iv / block / feedback keys for AES128 and everything worked fine.



Regarding PHP reporting 256-bit keys (32 bytes), the function that returns the current encryption key size actually returns the maximum key size, which is not explicitly stated in the documentation. I know this because my little class that I use all the time for different projects works great with openSSL and any other AES libraries in CBC or nOFB. This would not be the case if mcrypt was adding my 128 bit (16 char) key with an extra 128 bits of null string or whatever, and was not technically correct anyway.

Not a very good answer, but the best I got from a very amateur foray into crypto a few years ago.

+4


source


Check phpseclib:

http://phpseclib.sourceforge.net/



You can set the key size and block size according to what you want.

eg. $ aes-> setKeyLength (128) or $ aes-> setKeyLength (256);

+2


source


I had this problem - a couple of points. By default, PHP Rijndael mode sets the loopback to 8 bits - for AES it should be the same length as the IV / Key.

You can do this by using 'ncfb' mode instead of 'cfb' or MCRYPT_MODE_CFB.

Full details of writing aes_cfb_128 compliant PHP code are in this Stackexchange security question: aes cfb 128 decryption / encryption issue between Erlang and PHP . In short this (from Tom Lick):

... for both CFB and OFB (which are different from each other and cannot be used interchangeably), you need to worry about "loopback length" which is not necessarily well documented in various cryptographic libraries. Both encryption and decryption must use the same feedback length to communicate.

+1


source







All Articles