Much of what I'm about to explain can be gleaned from @ircmaxwell's excellent slidedeck: Cryptography For The Average Developer which you should check out immediately. I'll reiterate one of his main points: Avoid writing code that deals with encryption/decryption. Unless you understand all the factors you will probably flub it.
MCRYPT_RIJNDAEL_128 closely matches AES
The Advanced Encryption Standard was created by The National Institute of Standards and Technology. NIST chose the Rijandael cipher from a competitive pool of cryptographic experts.
Common confusion: the numbers in AES and Mycrpt refer to different things
- AES-128 refers to 128 bit key size
- AES-256 refers to 256 bit key size
- MCRYPT_RIJNDAEL_128 refers to a 128 bit cipher block size
- MCRYPT_RIJNDAEL_256 refers to a 256 bit cipher block size
Key size and block size
Key Size refers to the length of the secret used to encrypt/decrypt. A 256 bit key is 32 bytes, roughly 32 characters.
Block Size is a property of block ciphers (i.e. all AES candidates) which chunk out the data to a specific size during the cipher process.
- AES specifies a 128 bit cipher block
- Mcrypt's Rijndaels all accept 256 bit keys
- based on key/block size MCRYPT_RIJNDAEL_128 seems to conform closest to AES-256
- there are other factors to consider — like how many transformation rounds occur? — it's hard to verify this aspect without digging into the source code
Mode of Operation
The mode is an important element.
Both ECB and CBC mode pad your plaintext into the block size. If you're encrypting 1 byte of data with a 128 bit block size you will get 15 null bytes. Padding opens up the possibility for a padding oracle attack.
Beyond padding ECB does not make use of an Initialization Vector (IV) which leaves you open to a potential vulnerability: prefer CBC or CFB mode.
You can avoid both problems by using CFB mode which does not need padding and therefore does not require post-decryption trimming.
Initialization Vector (IV)
When creating your IV you need a crypto-strong random source: MCRYPT_RAND
is not random enough — MCRYPT_DEV_RANDOM
or MCRYPT_DEV_URANDOM
are preferred.
$iv_size = mcrypt_get_iv_size(
MCRYPT_RIJNDAEL_128,
MCRYPT_MODE_CFB
);
$iv = mcrypt_create_iv(
$iv_size,
MCRYPT_DEV_URANDOM
);
Finally, for your friends
In order to decrypt your friend will need to know:
- the cipher —
MCRYPT_RIJNDAEL_128
- the block mode —
MCRYPT_MODE_CFB
- the IV — each element you encrypt should get a unique IV, so you'll want to append the IV to the encrypted data
- the key — this is secret, and should stay the same for all encryptions; if your key gets compromised rotate it out
Only the key needs to stay secret. Depending on your transport method you should consider implementing a data integrity check to ensure the ciphertext data wasn't tampered with. Again, see @ircmaxwell's excellent slidedeck: Cryptography For The Average Developer for an example of creating an HMAC fingerprint using hash_hmac()
.
It should be obvious that the maintenance all of these moving parts is rife with complexity. Tread carefully.
Other ciphers
Mcrypt gives you other cipher options. Some, like DES, are not recommended. Others were candidates for AES, like Blowfish, TwoFish, and Serpent. Rijandael is a vetted, proven cipher, and is recommended.