Page 1 of 1

Using PHP's mcrypt to encrypt/decrypt AES from other source

Posted: Thu Sep 18, 2008 7:25 am
by Haravikk
Hi there!

I'm having something of a problem using mcrypt and I'm hoping someone can help. Now, I should preface this by saying that mcrypt itself may not be the real issue, but I'll get to that.

What I have is a program running in another programming language that correctly implements CBC and CFB encryption modes for AES, supporting 128, 192, and 256-bit keys. It also supports null-padding (which I believe is what mcrypt uses with CBC mode). Anyway, what I want to do is send an encrypted message from this program to a PHP script, decrypt it using mcrypt and then encrypt a response. However, I can't get it to work!

I have however managed to get the message to decrypt correctly using Java, and encrypt a response, so I know it's not my program's implementation of AES. So the problem is definitely somewhere within my mcrypt code, but I can't figure out where.

Anyway, here's a sample of the php code:

Code: Select all

<?php 
$myKey = pack('H*', '1234567890ABCDEF0123456789ABCDEF'); 
$myIV  = pack('H*', '89ABCDEF0123456789ABCDEF01234567'); 
$myMsg = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChi="; 
 
echo 'Key: ' . bin2hex($myKey) . '<br />'; 
echo 'IV: ' . bin2hex($myIV) . '<br />'; 
 
echo 'Decrypted: ' . getDecrypt( 
    $myMsg, 
    $myKey, 
    $myIV 
); 
  
function getEncrypt($sStr, $sKey, $sIV) { 
    return base64_encode( 
        mcrypt_encrypt( 
            MCRYPT_RIJNDAEL_128,  
            $sKey,  
            $sStr,  
            MCRYPT_MODE_CFB,  
            $sIV 
        ) 
    ); 
} 
 
function getDecrypt($sStr, $sKey, $sIV) { 
    return mcrypt_decrypt( 
        MCRYPT_RIJNDAEL_128,  
        $sKey,  
        base64_decode($sStr),  
        MCRYPT_MODE_CFB,  
        $sIV 
    ); 
} 
 
?>
The CFB encrypted, base64 string should decrypt into the message "Hello world! I am a lovely message waiting to be encrypted!", but it does not, I just get garbage characters.

My suspicion at the moment is that it may be something to do with the way mcrypt works, and my inputs to it. It seems that mcrypt works using 8-bit characters (extended ASCII) which is fair-enough, as AES is a byte-manipulating cipher anyway. However, both my program and Java natively use UTF-16, and convert the output to UTF-8 before base64 encoding, and I have no idea how this affects PHP as I've never needed to worry about it before.

I've trauled examples, but all of them seem focused on encrypting/decrypting within PHP only, and have no notes on communicating with other AES implementations. I'd rather not port my own implementation to PHP as it is unlikely to be as fast as mcrypt (and duplicates a ton of work).

Any help is much appreciated!

P.S - I also have a sample CBC encrypted version of the same message which is NULL padded, if this is any easier to work-with:
slihkO6t9I/yfvfUpI0Rthagd/z8j1s5qh/PSbKGBg4N3PoQgUFdcCVnqOYku53cVx+IDgo8d0gPGaBR5YzORQ=

Re: Using PHP's mcrypt to encrypt/decrypt AES from other source

Posted: Thu Sep 18, 2008 11:16 am
by Maugrim_The_Reaper
Unfortunately, you might be right - encryption in PHP depends a lot on UTF-8 conversion. Have you tried mixing in iconv or mbstring to do the conversion to see if it has an impact? The only thing here is that the test message doesn't need UTF-8 per se (I wouldn't have thought so at least).

More likely though might be the padding - are you sure everything is using null padding? Outside PHP it's not always the default. Java could be PKCS5 instead.

Re: Using PHP's mcrypt to encrypt/decrypt AES from other source

Posted: Thu Sep 18, 2008 1:04 pm
by Haravikk
The program I'm trying to have PHP communicate with is written entirely by myself, including the AES implementation as there was no available library to use. The padding for mcrypt as far as I can tell is STATE-bits wide (so 128 for AES) null-padding if you're using a mode that requires padding, namely ECB or CBC. CFB, OFB and other modes don't require padding as they just XOR the final state with any leftover bytes of data.

As for character-encoding, I've been trying mb_convert_encoding and similar to see what effect they have, but I haven't had much luck so am hoping someone more familiar with them may know where I should be putting such functions, or which ones are best suited to use with mcrypt.

Java's padding support includes the more common zero pad + pad-length, i.e - if you're 9 bytes short it would add 8 zero-bytes and 1 byte with the number 9 in it. I can never remember what this method is called, but my program supports that as well, but as far as I'm aware I can't use it with mcrypt.

Re: Using PHP's mcrypt to encrypt/decrypt AES from other source

Posted: Sat Sep 20, 2008 7:42 am
by Haravikk
I should probably note in case there was any confusion; my program is not written in Java, I mention Java as I was am able to encrypt/decrypt messages compatible with my program using Java's Cipher class, which allows me to assume that my program is not the issue, as I've tried various sample messages and got the same results in both my program and in Java.

Re: Using PHP's mcrypt to encrypt/decrypt AES from other source

Posted: Sat Oct 25, 2008 3:27 pm
by Haravikk
Hey, I'm really sorry to bump this, but I've been trying off and on with no luck thus-far. I'm just not sure I'm understanding at all, and the only documentation I've found for mcrypt and character encoding hasn't really been helping me any, I've tried loads of different combinations to no avail.

Would I have been better posting this under PHP Code? It's not really a security issue, but more of one whereby once I've got the right input to mcrypt, I'll get the right answer out. I know my input string is a valid one as I can decrypt it in other languages, so it's definitely been encrypted properly as AES in CFB mode with the keys/input-vectors provided. Could it be that I'm grabbing the key/input-vector data incorrectly? I really don't know, as PHP confuses me at the best of times, as I'm used to working with arrays of bytes, and pointers, PHP seems to sugar-coat some things in ways I just don't understand :)