PHP cryptography - proceed with care

A couple of case studies from PHP world demonstrating how important it is that application framework authors provide carefully designed cryptography interface to programmes. Otherwise it's almost certaint that will be implemented incorrectly.

I've been pentesting an application written in PHP. The data flow was as follows:

  1. Take data from the user A.
  2. Encrypt the data using hard-coded key and make an URL of it (like
  3. Send the URL in email to user B.
  4. User B clicks on URL, application decrypts data and displays it on the page.

Apart from cross-site request forgery and cross-site scripting issues there was yet another problem — with the encryption. Specifically, the application was built using CodeIgniter framework for PHP and it's encryption module has no message integrity checking. If you modified a character in the ENCRYPTED string, the decryption function will process this happily and you would see garbage characters on the final output page. See Practical Padding Oracle Attacks paper to understand what happens next.

I searched for other examples of encryption usage in PHP world.

A Cryptastic class does verify integrity, but for some strange reason it uses PBKDF2 with 1000 iterations of SHA-256. What purpose does it serve, apart from slowing the whole process down? No idea.

$mac = $this->pbkdf2($iv . $msg, $k, 1000, 32);     # create mac

This particular function PBKDF2 was designed to be intentionally slow when it's used for password hashing. But authenticity verification doesn't need to be slow. There's no security benefit from slowness in this particular usage scenario.

Official PHP manual page for mcrypt_encrypt() shows an example on how this function should be used — again, without message integrity. There is one comment that highlight that (and it got -1). There's another code example in comments that also check for integrity (also got -1).

Ideal programmer interface should probably look like Bernstein's NaCl crypto box concept. It's takes message m, key k and nonce n, and guarantees both confidentiality and integrity. And that's it. It doesn't expose any cryptic cipher-suite aliases and other internals that confuse programmers and are error prone. You can still break things — like using trivial key or non-once nonce — but the attack surface is reduced.

c = crypto_secretbox(m,n,k);

Microsoft CryptoAPI functions for encryption offer optional integrity protection (CryptEncrypt ). Newer DataProtector class "protects stored data from viewing and tampering", which suggests built-in integrity protection (concept similar to Windows DPAPI CryptProtectData ).

You should also get familiar with combined authentication and encryption modes for block ciphers, such as OCB or CCM, as they provide exactly what we have discussed above — a single interface to both security functions. For Python I can recommend pyOCB and there's PHP-CryptLib that implements CCM mode.