PHP AES encryption... no idea what I'm doing
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 som开发者_开发知识库eone 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);
}
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:
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"));
}
精彩评论