note 47973 added to function.mcrypt-encrypt
| From: | jesse at pctest dot com | Date: | Tue, 07 Dec 2004 22:43:11 +0000 |
| Subject: | note 47973 added to function.mcrypt-encrypt | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-81499@lists.php.net to get a copy of this message | ||
Solving 3DES incompatibilities with .NET's TripleDESCryptoServiceProvider
mcrypt's 3DES only accepts 192 bit keys, but Microsoft's .NET and many other tools accept
both 128 and 192 bit keys.
If your key is too short, mcrypt will 'helpfully' pad null characters onto the end, but
.NET refuses to use a key where the last third is all null (this is a Bad Key). This prevents you
from emulating mcrypt's "short key" behaviour in .NET.
How to reconcile this? A little DES theory is in order
3DES runs the DES algorithm three times, using each third of your 192 bit key as the 64 bit DES key
Encrypt Key1 -> Decrypt Key2 -> Encrypt Key3
and both .NET and PHP's mcrypt do this the same way.
The problem arises in short key mode on .NET, since 128 bits is only two 64 bit DES keys
The algorithm that they use then is:
Encrypt Key1 -> Decrypt Key2 -> Encrypt Key1
mcrypt does not have this mode of operation natively.
but before you go and start running DES three times yourself, here's a Quick Fix
<?php
$my_key = "12345678abcdefgh"; // a 128 bit (16 byte) key
$my_key .= substr($my_key,0,8); // append the first 8 bytes onto the end
$secret = mcrypt_encrypt(MCRYPT_3DES, $my_key, $data, MCRYPT_MODE_CBC, $iv); //CBC is the default
mode in .NET
?>
And, like magic, it works.
There's one more caveat: Data padding
mcrypt always pads data will the null character
but .NET has two padding modes: "Zeros" and "PKCS7"
Zeros is identical to the mcrypt scheme, but PKCS7 is the default.
PKCS7 isn't much more complex, though:
instead of nulls, it appends the total number of padding bytes (which means, for 3DES, it can be a
value from 0x01 to 0x07)
if your plaintext is "ABC", it will be padded into:
0x41 0x42 0x43 0x05 0x05 0x05 0x05 0x05
You can remove these from a decrypted string in PHP by counting the number of times that last
character appears, and if it matches it's ordinal value, truncating the string by that many
characters:
<?php
$block = mcrypt_get_block_size('tripledes', 'cbc');
$packing = ord($text{strlen($text) - 1});
if($packing and ($packing < $block)){
for($P = strlen($text) - 1; $P >= strlen($text) - $packing; $P--){
if(ord($text{$P}) != $packing){
$packing = 0;
}
}
}
$text = substr($text,0,strlen($text) - $packing);
?>
And to pad a string that you intend to decrypt with .NET, just add the chr() value of the number of
padding bytes:
<?php
$block = mcrypt_get_block_size('tripledes', 'cbc');
$len = strlen($dat);
$padding = $block - ($len % $block);
$dat .= str_repeat(chr($padding),$padding);
?>
That's all there is to it.
Knowing this, you can encrypt, decrypt, and duplicate exactly any .NET 3DES behaviour in PHP.
----
Manual Page -- http://www.php.net/manual/en/function.mcrypt-encrypt.php
Edit -- http://master.php.net/manage/user-notes.php?action=edit+47973
Delete -- http://master.php.net/manage/user-notes.php?action=delete+47973&report=yes
Reason: bad code -- http://master.php.net/manage/user-notes.php?action=delete+47973&report=yes&reason=bad+code
Reason: spam -- http://master.php.net/manage/user-notes.php?action=delete+47973&report=yes&reason=spam
Reason: useless example -- http://master.php.net/manage/user-notes.php?action=delete+47973&report=yes&reason=useless+example
Reason: contains commercial links -- http://master.php.net/manage/user-notes.php?action=delete+47973&report=yes&reason=contains+commercial+links
Reason: useless note -- http://master.php.net/manage/user-notes.php?action=delete+47973&report=yes&reason=useless+note
Reject -- http://master.php.net/manage/user-notes.php?action=reject+47973&report=yes
Search -- http://master.php.net/manage/user-notes.php