Advanced symmetric encryption
ROT13 is a nice algorithm to learn to get into the feel of how symmetric encryption works, but to get real encryption you need to use the Mcrypt extension in PHP. This extension is quite complicated to work with because you need to call a number of functions to get started. To encrypt data you need to use seven different functions, which are: mcrypt_module_open(), mcrypt_create_iv(), mcrypt_enc_get_iv_size(), mcrypt_enc_get_key_size(), mcrypt_generic_init(), mcrypt_generic(), mcrypt_generic_deinit(), and finally mcrypt_module_close().
Usually I would print these function names inside the chapter header to make it easy for you to find topics by flicking through the book, but having all of those in the chapter header makes for quite a messy title!
Here are the function prototypes:
resource mcrypt_module_open ( string algorithm, string algorithm_directory, string mode, string modedirectory)
string mcrypt_create_iv ( int size, int source)
int mcrypt_get_iv_size ( resource td)
int mcrypt_get_key_size ( resource td)
int mcrypt_generic_init ( resource td, string key, string iv)
string mcrypt_generic ( resource td, string data)
bool mcrypt_generic_deinit ( resource td)
bool mcrypt_module_close ( resource td)
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_256, '', MCRYPT_MODE_CFB, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$ks = mcrypt_enc_get_key_size($td);
$key = substr(sha1('Your Secret Key Here'), 0, $ks);
mcrypt_generic_init($td, $key, $iv);
$ciphertext = mcrypt_generic($td, 'This is very important data');
print $iv . "\n";
print trim($ciphertext) . "\n";
That's quite a complicated script, so let me break it down into easier-to-swallow chunks. First things first, the random number generator is seeded with a pseudo-random value, which is important because our IV will be created by calling the random number generator. The first function called is mcrypt_module_open(), which opens an encryption algorithm for use - it takes four parameters, of which we only care about parameters one and three, which are the name of the algorithm to use and the type of block cipher to use. Parameter three can be left as is in all your code because it is generally best left as the constant MCRYPT_MODE_CFB. Parameter one is key, though, as it is where you select what encryption algorithm you want to use - leave it as Rijndael (also known as AES) for now; we'll look at alternatives soon.
Moving on, the next function called is mcrypt_create_iv(), which creates an initialisation vector for our encryption. IVs aren't used to make the key any more difficult guess, instead their purpose is to make the plaintext more innocuous - a process referred to as "whitening", because the goal of the IV is to make your plaintext look more like white noise by randomising it a little before encryption. Mcrypt_create_iv() takes two parameters, which are the size of the IV to create and the method to use to create the IV.
The first parameter is filled with the return value from mcrypt_enc_get_iv_size(), which returns the length the IV should be for the encryption algorithm passed in as its only parameter. The second parameter can one of MCRYPT_RAND, MCRYPT_DEV_RANDOM, or MCRYPT_DEV_URANDOM. The first generates the IV uses the system software randomiser, the second uses the Unix device /dev/random, and the third uses the Unix device /dev/urandom. For maximum portability use MCRYPT_RAND - it is not as random as the other two, but it will work wherever you put it. If you use MCRYPT_RAND, remember to first seed the random number generated with srand()!
Mcrypt_create_iv() returns an IV for the algorithm we selected with mcrypt_module_open(). Next up we call mcrypt_enc_get_key_size() to get the maximum key size our algorithm (parameter one) will take, then we create a key for that algorithm using substr() and sha1(). The return value of mcrypt_enc_get_key_size() is the largest key this algorithm accepts, so we pass a plaintext key into sha1() to get a hashed value, then copy as many characters from it as the algorithm method will accept.
The next two functions, mcrypt_generic_init(), and mcrypt_generic(), initialise the encryption engine with the algorithm, IV, and key we selected, then perform the encryption. Mcrypt_generic_init() takes three parameters, which are the algorithm resource to use, the IV we created with mcrypt_create_iv(), and the key we created using sha1() and substr(). Mcrypt_generic takes two parameters, which are the algorithm resource and the data we actually want to encrypt - it returns the encrypted value, our ciphertext, which we store in $ciphertext.
So, after lots of function calls we have finally performed encryption with the function mcrypt_generic(). To end the script, we need to do some clean up, which is where mcrypt_generic_deinit() and mcrypt_module_close() come in - both take the algorithm resource as their only parameter, and clean up the module.
Author's Note: It's possible to perform encryption using the mcrypt library but with fewer functions. Generally speaking this is not recommended: using an IV and doing things properly ensures the data is secured properly. Please remember that the only thing worse than not being secured is not being secured and thinking you are secured!
To recap, we select an encryption algorithm and block cipher, create an IV to whiten our plaintext a little, create a secret key that encrypts our data, initialise the algorithm to use our IV and key, run the encryption itself to get our ciphertext, then clean up.
In order to give you an idea of how much better this form of encryption is compared to something as simple as ROT13, the script ends by printing out both the IV and the final encrypted value.
Next chapter: Symmetric decryption >>
Previous chapter: Basic symmetric encryption in action
Home: Table of Contents