I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 636 posts at DZone. You can read more from them at their website. View Full User Profile

PHP's mcrypt

02.25.2013
| 2978 views |
  • submit to reddit

This a symmetric encryption primer for PHP: you'll learn how to call the mcrypt API to encrypt and decrypt strings, using a single key in both processes.

The theory

In symmetric cryptography, the key for encrypting and decrypting data is the same and is shared between parties while being kept secrets. The primitives take as configuration the key and other parameters, and transforms a value into its encrypted version and back.

Once someone gets hold of an encrypted version and assuming the scheme and your implementation do not contain flaws, it is necessary to know the key to get to the plain text version.

There are many different algorithms in cryptography, but we will take a look at block ciphers only; this category of ciphers is able to encrypt a block of a small, fixed size at a time, but can be used in different operational modes to encrypt an arbitrarily long string. 

Example

The mcrypt extension provides functions for crypting and decrypting, but also for generating configuration and some reflection of the algorithms (such as the lenght of their key).

For example, let's choose the popular Triple DES algorithm, and choose a key for it:
$key = "0x0a0x880x090x790x6f0xac0x6c0x410x1c0xc00xe50x320xce0xfd0xa70xdd0x
250x3b0x3c0xe70x3d0xa00x190x54"; // generated at random.org, 24 bytes
This key must be stored somewhere, at least in a file outside the document root, but it will have to be accessible to PHP scripts.

Given the key, you can encrypt a string with:
mcrypt_encrypt(MCRYPT_3DES, $key, $string, MCRYPT_MODE_ECB);
and decrypt it with:
rtrim(mcrypt_decrypt(MCRYPT_3DES, $key, $encryptedData, MCRYPT_MODE_ECB), "\0"); 
// rtrim() will cut padding NULL bytes
I have chosen Triple DES in this example as AES is not available; it's usually safer to rely on a language implementation of a less powerful algorithm than to try implementing yourself one. I'm not a fan of importing libraries and frameworks by default, but cryptography is a difficult field and you're better off leaving the complexity of the mathematics involved to someone else.

In this example, we instantiated the block cipher in ECB (Electronic Code Book) mode: this means every block is encrypted separately, in the simplest variant of encryption modes. In the case of Triple DEs, the length of the block is 192 bits, as is that of the key.

With ECB, equal plain text blocks will always result in equal encrypted ones; this causes noticeable patterns in the encrypted data. For this reason, you should only use ECB to encrypt data smaller than a block (192 bits means 24 bytes of data), for example an email address.

Modes

Other modes of operations ramp up the complexity of implementation, but allows to encrypt arbitrarily long strings with a cipher that is only designed for a block of hundreds of bits. For example CBC (Cipher Block Chaining) uses the result of the encryption of block N in the computation of the encryption of block N+1, so that two equal blocks are effectively mapped to different encrypted versions.

However, this non deterministic output means that on the decrypting side additional information will be required with respect to the key. An initialization vector is the block 0 of an encryption mode, used as the preceding block of the first one to be encrypted. It's similar to a salt used in hashing, as it renders the output non predictable even for perfectly identical plain texts. You can specify an initialization vector, for example, in CBC mode.

The initialization vector must be random, uniform and unique for each value to crypt. It can be shared in plain text with whoever is receiving the crypted information; for example, you may send this JSON document over the wire:
{
    crypted: "...",
    iv: "",  // a X-long vector
}
The only other information necessary on the other side are the name of the algorithm and its mode, which are usually shared out-of-band during design.

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)