PHP To CPP Cryptography
For GUIterm I decided I wanted to generate an encrypted registration key on the web server for decoding by the client. This took a bit to work out, but I'm happy to report the successful results below.
Example: Encrypting With PHP
Now, I'm no crypto junkie. Indeed, other than the high-level theory, I really don't know jack about encryption. ECB? IV? No idea. However, here's some siimple PHP code to get you started encrypting a string of data with triple-DES, and then outputting the result in a base64 encoded string:
// First, choose a key and an IV. The key is 24 characters (bytes) long,
// and the IV is 8. What's the IV? I'm not exactly sure -- apparently
// it's some kind of random number. Whatever.
$key = "012345678901234567890123";
$iv = "01234567";
echo "key = '$key', iv = '$iv'\n";
// Now choose the plaintext message
$plainText = "Let us meet at 9 o'clock at the secret place.";
echo "plainText = '$plainText'\n";
// Set up an encryption descriptor. This is basically just an object that
// encapsulates the encryption algorithm. 'tripledes' is the name of the
// algorithm, which is simply the DES algorithm done three times back to
// back. 'ecb' describes how to encrypt different blocks. See, DES
// actually only encrypts 8-byte blocks at a time. To encrypt more than 8
// bytes of data, you break the data up into 8-byte chunks (padding the
// last chunk with NULL, if need be), and then encrypt each block
// individually. Now, ECB (which stands for "Electronic Code Book", for
// whatever that's worth) means that each 8-byte block is encrypted
// independently. This has pros and cons that I don't care to discuss.
// The other option is CBC ("Cipher Block Chaining") which links the blocks,
// such as by XORing each block with the encrypted result of the previous
// block. Security geeks probably really get excited about this, but for my
// needs, I don't really care.
$td = mcrypt_module_open( 'tripledes', '', 'ecb', '' );
mcrypt_generic_init( $td, $key, $iv );
// Grab some interesting data from the descriptor.
// $maxKeySize = 24, meaning 24 bytes
// $maxIVSize = 8, meaning 8 bytes
$maxKeySize = mcrypt_enc_get_key_size( $td );
$maxIVSize = mcrypt_enc_get_iv_size( $td );
echo "maxKeySize=$maxKeySize, maxIVSize=$maxIVSize\n";
// Let's encrypt the data. So simple! For easy transmission, let's also
// encode it into base64 (the encrypted data is straight binary, so might
// have unprintable or even null characters, and thus isn't a valid string.)
$encryptedData = mcrypt_generic( $td, $plainText );
$base64EncryptedData = base64_encode( $encryptedData );
echo "encryptedData = [base64]'$base64EncryptedData'\n";
// Just for fun, let's decrypt it and verify the result. Because DES pads
// the end of the original block with NULL bytes, let's trim those off to
// create the final result.
$base64DecryptedData = base64_decode( $base64EncryptedData );
$decryptedData = rtrim( mdecrypt_generic( $td, $base64DecryptedData ), "\0" );
echo "decryptedData = '$decryptedData'\n";
// And finally, clean up the encryption object
Result: Encrypted Data
The above code, when executed on my server at least, produces this output:
key = '012345678901234567890123', iv = '01234567'
plainText = 'Let us meet at 9 o'clock at the secret place.'
encryptedData = [base64]'SQNtu2Aubug3LZipHrJLwIe+Nm2To158td3s12MJoBRttjKk3sDmRqbpYpxV70nP'
decryptedData = 'Let us meet at 9 o'clock at the secret place.'
Example: Decrypting With Crypto++
Now that we've encrypted some data on our server, let's do something with that on the client side. On this front, there's some good news, and there's some bad news.
The good news is that there is a library, called Crypto++, that is free (even for closed-source, commercial products) that does just about everything under the sun relating to encryption / decryption, base64 / hex encoding / decoding, GZip compression / decompression, and more.
The bad news is that it uses an utterly insane
amount of C++ templating. I mean, I thought that after nine years, I could safely say I was good at C++. But I'm shamed and humbled by what it does. I quite frankly have no idea how to use it. It is so absurdly complex that I cannot figure out any method to its templatized maddness. Furthermore, it seems that almost nobody else can figure it out either, because there is virtually no documentation, no tutorials (don't be fooled, the "tutorial" it offers is really more of an overview of what's in each header nfile), little newbie discussion. There aren't even any comments in the code. There's an article about hex encoding and decoding
, and another about compression and decompression
, but almost nothing else. Indeed, the dearth of documentation was my impetus for doing this article. Anyway.
So, download Crypto++
, and try out the following simple code fragment:
// Include the relevant headers
#include // STL string library; not part of Crypto++
// Use the Crypto++ namespace
using namespace CryptoPP;
// Use the same base64 encoded, encrypted data as generated by PHP
string base64CipherText =
// Decode the data using the handy Crypto++ base64 decoder. Base64 uses
// 3 characters to store 2 characters, and I'm not sure how the Get()
// method works below (again, there's no documentation), but that seems
// to work fine. I'd have to think more why that conversion works, but
// it does.
const int BUFFER_LENGTH = 128;
base64Decoder.Put( (byte*)base64CipherText.c_str( ), base64CipherText.size( ) );
base64Decoder.Get( ciphertext, base64CipherText.size( ) * 3 / 2 );
// Set up the same key and IV as was used in PHP
const int KEY_LENGTH = 24;
const int BLOCK_SIZE = DES::BLOCKSIZE;
byte key[KEY_LENGTH], iv[DES::BLOCKSIZE];
memcpy( key, "012345678901234567890123", KEY_LENGTH );
memcpy( iv, "01234567", DES::BLOCKSIZE );
// Now just decrypt using triple-DES and ECB block encoding
// **NOTE: If you get an exception here, try removing the 'iv' parameter -- thanks Rich!
ECB_Mode<DES_EDE3>::Decryption ecbDecryption( key, KEY_LENGTH, iv );
ecbDecryption.ProcessData( plaintext, ciphertext, BUFFER_LENGTH );
// That's it! Now 'finalplaintext' should contain the string:
// "Let us meet at 9 o'clock at the secret place."
// If you're interested in encrypting, it's pretty straightforward, too
ECB_Mode<DES_EDE3>::Encryption ecbEncryption( key, KEY_LENGTH, iv );
ecbEncryption.ProcessData( newciphertext, plaintext, BUFFER_LENGTH);
// Now 'newciphertext' should be identical to 'ciphertext'
That's it! It looks pretty simple here, and it really is. I expect were I to master Crypto++, it'd be totally obvious how to use it. But I haven't mastered it, so that's as much as I know. If you have any questions, don't hesitate to write me at firstname.lastname@example.org
. In the meantime, enjoy your crytography!