3

I don't know much about encryption, but I was able to get AES working in PHP... somewhat. Here are a couple functions that I am using:

function aes_decrypt($val,$ky) 
{ 
    $key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 
    for($a=0;$a<strlen($ky);$a++) 
      $key[$a%16]=chr(ord($key[$a%16]) ^ ord($ky[$a])); 
    $mode = MCRYPT_MODE_ECB; 
    $enc = MCRYPT_RIJNDAEL_128; 
    $dec = @mcrypt_decrypt($enc, $key, $val, $mode, @mcrypt_create_iv( @mcrypt_get_iv_size($enc, $mode), MCRYPT_RAND) ); 
    return rtrim($dec,(( ord(substr($dec,strlen($dec)-1,1))>=0 and ord(substr($dec, strlen($dec)-1,1))<=16)? chr(ord( substr($dec,strlen($dec)-1,1))):null)); 
} 

function aes_encrypt($val,$ky) 
{ 
    $key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 
    for($a=0;$a<strlen($ky);$a++) 
      $key[$a%16]=chr(ord($key[$a%16]) ^ ord($ky[$a])); 
    $mode=MCRYPT_MODE_ECB; 
    $enc=MCRYPT_RIJNDAEL_128; 
    $val=str_pad($val, (16*(floor(strlen($val) / 16)+(strlen($val) % 16==0?2:1))), chr(16-(strlen($val) % 16))); 
    return mcrypt_encrypt($enc, $key, $val, $mode, mcrypt_create_iv( mcrypt_get_iv_size($enc, $mode), MCRYPT_RAND)); 
} 

These are slightly modified from a comment on the PHP documentation page for mcrypt. (I changed from dev_urandom to rand, as I am on a windows box, where dev_urandom is not available.)

Anyway the key I use in this functions is defined like this:

define("PSK", pack("H*", "abcd7b5ca46e12345678a8161fdacee9"));

I call my function like this:

echo bin2hex(aes_encrypt("wootwootwootwootwootwootwoo", PSK));

Now, the first 16 bytes (32 digits) of the resulting hex string are fine. The next 16 bytes do not match what is expected.

See, I am posting this data to an external webservice that then decrypts it. I (unfortunately) can't give the one test case I have without handing out my encryption key and data. I am terribly sorry about that, but I am hoping someone familiar with mcrypt can look at this and tell me what I am doing wrong.

Again, sorry about the lack of a solid test case, but I am greatly appreciative of any help you can give!

EDIT: It seems my provider that I am posting to is using a null IV. Following Rook's advice, I have switched to CBC mode, and removed the unnecessary code related to the key. Here are my new functions:

function aes_decrypt($val,$key)
{
    $mode = MCRYPT_MODE_CBC;
    $enc = MCRYPT_RIJNDAEL_128; 
    $dec = @mcrypt_decrypt($enc, $key, $val, $mode, null); 
    return rtrim($dec,(( ord(substr($dec,strlen($dec)-1,1))>=0 and ord(substr($dec, strlen($dec)-1,1))<=16)? chr(ord( substr($dec,strlen($dec)-1,1))):null)); 
}

function aes_encrypt($val,$key) 
{
    $mode = MCRYPT_MODE_CBC;
    $enc=MCRYPT_RIJNDAEL_128; 
    $val=str_pad($val, (16*(floor(strlen($val) / 16)+(strlen($val) % 16==0?2:1))), chr(16-(strlen($val) % 16))); 
    return mcrypt_encrypt($enc, $key, $val, $mode, null); 
}
Brad
  • 159,648
  • 54
  • 349
  • 530

2 Answers2

5

It is likely that this encryption service is using a different block cipher mode of operation like CBC. If a null iv is being used with CBC mode then the first block (in this case 16 bytes) of ECB and CBC will produce the same cipher text. ECB mode should never be used by anyone for any reason.

Here is an example ECB mode encrypted message:

alt text

rook
  • 66,304
  • 38
  • 162
  • 239
  • Your comments are helpful, and I appreciate the last edit, although you were definitely correct without it. After doing some research on how ECB and CBC works, I have switched to CBC. However, I am having trouble getting output that will function with my online service, which I have no control over. I've set a null IV (yes, frightening) and the first block lines up to what is needed, but the second block still doesn't match. I am experimenting with other modes now, but any advice you could give me would be most helpful. I do appreciate your time and response. – Brad Nov 19 '10 at 14:32
  • @Brad Your String2KeyFunction, (the for loop XoR'ing nulls) is uncommon. If they are using a different string2key then it maybe causing problems. Although if the key you are using is less than 16 bytes then its just a plaintext key, which is a poor design but also a common one. Sorry about the first post, that was uncalled for. – rook Nov 19 '10 at 16:00
  • @Rook, it turns out that bit doesn't matter anyway, as I was passing in a binary key of the correct length. I think that only existed to handle odd lengths of keys. I have removed it and am just using a predefined key. I believe the key part is correct, as the first block matches. Only the second block does not. I will edit my post above to reflect my current functions. – Brad Nov 19 '10 at 17:34
  • @Brad yeah thats a strange one I thought for sure it was cbc with a null iv. Maybe its the padding, but that is as unlikely at the s2k function. You could try the other modes, but ecb and cbc are the most alike. Tell me what you come up with. – rook Nov 19 '10 at 20:56
  • @Brad, did you figure it out? – rook Nov 27 '10 at 15:32
  • @Rook, not quite yet, but I am still experimenting. Your advice was most helpful. I will definitely post back here once I figure it out. Sorry about the delay... this is a work project, and I am on vacation for the moment. – Brad Nov 27 '10 at 16:13
  • @Rook, I finally figured it out. I was padding the string differently than they were. Thanks again for your help! – Brad Dec 06 '10 at 16:13
1

Me and a college of mine where coding an iPhone app and where using the above methods to encrypt and decrypt data. But we found an issue when I was encrypting the data to be read from his iPhone. The iPhone used PKCS7 padding. The above code was adding extra padding this would cause the iPhone decryption method to fail. We amended the code to fix the current issue :

public static function  aes128Encrypt($key,$val) 
{
    $mode = MCRYPT_MODE_CBC;
    $enc=MCRYPT_RIJNDAEL_128; 
    $blocksize= mcrypt_get_block_size($enc,$mode);
    $stringLength = strlen($val);
    $paddingLength =$blocksize-($stringLength%$blocksize);
    $val=str_pad($val,$paddingLength+$stringLength,chr($paddingLength));
    return base64_encode(mcrypt_encrypt($enc, $key, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")); 
}
Moddinu
  • 185
  • 1
  • 7