Friday, August 03, 2007

DES != DES

For those of you that read my blog whom are not techies, you may proceed to skip this post, or be forewarned that the contents of this post will mostly be relevant only for techies (I can make up words if I want to). The rest of you may proceed forthwith.

From the Wikipedia article on DES
The Data Encryption Standard (DES) is a cipher (a method for encrypting information) selected as an official Federal Information Processing Standard (FIPS) for the United States in 1976, and which has subsequently enjoyed widespread use internationally.

I was recently presented with the task of communicating from a PHP website to an ASP.NET site via a webservice method. Easy enough, use SOAP pass the appropriate parameters and you're done. The problem arose in that the ASP.NET designers chose have the parameters encrypted manually as opposed to using the SSL. This meant the above mentioned DES.

DES is a block cipher, meaning that all encrypted bits resulting from this algorithm are going to be a block of 64 bits or in the case of ascii 8 characters. All plain-text passed in for encryption must be padded at the end with a predetermined character in order to meet the criteria of an 8 character block.

Both .NET and PHP have a library call to encrypt data using the DES algorithm. PHP uses the '\0' or null character as the padding character for its 8 character blocks. It also forces to select what is called the cipher mode, which can be a number of algorithms I won't get into. Microsoft on the other hand does not indicate either the default cipher mode or the character used for padding.

After most of an 8 hour day I figured out the defaults for .NET thanks to some resourceful people blogging about it on the internet. .NET's DES algorithm uses the Cipher Block Chaining (CBC) cipher mode and the PKCS7 algorithm to determine the character added to the end of a short block. With the help of my resource I was able to implement PKC7S in my PHP code using the following code:

$imod = strlen($plain_text) % 8;
$ipad = 8 - $imod;
for ($iX = 0; $iX < 8 - $imod; $iX++)
$plain_text .= chr($ipad);

I hope someone else can find that as useful as I did. A few other useful things I found out are that strings in PHP are by default ASCII encoded, when decoding in PHP from PHP make sure to use rtrim($text, "\0") before returning, and try/catch blocks are only available in >= PHP 5. It was very gratifying to complete this and have it function properly, so that is why I share.