The State of Cryptography in PHP

With the release date for PHP 7 drawing near, let's take a look at everything good and bad about developing cryptography features in PHP, what got fixed in PHP 7, and what remains to be fixed in a future version of PHP.

A Brief History of Cryptography Improvements in PHP 5

PHP 5.2 and before No cross-platform CSPRNG without the mcrypt extension No symmetric-key encryption without mcrypt either

PHP 5.3 PHP gets openssl_encrypt() and openssl_decrypt() for symmetric-key encryption Finally a cross-platform CSPRNG ( openssl_random_pseudo_bytes() ) albeit not the best one

PHP 5.4 Improved openssl_encrypt() and openssl_decrypt() API

PHP 5.5 For user account management, password_hash() and password_verify() saves the day hash_pbkdf2() for deriving encryption keys from passwords

PHP 5.6 hash_equals() allows developers to prevent timing attacks



The PHP programming language has come a long way throughout the lifetime of PHP 5. In the beginning, you had to implement your own ciphers and CSPRNG interfaces or install a PHP extension to offer basic security. As the language matured, it has become easier to implement secure cryptographic protocols without writing your own low-level features.

Cryptography is Better in PHP 7

PHP 5 has several CSPRNG interfaces, but it's not immediately clear which one should be used (or even can):

mcrypt_create_iv() is great (provided you specify MCRYPT_DEV_URANDOM and not MCRYPT_RAND , but you can't access it without enabling the mcrypt extension

is great (provided you specify and , but you can't access it without enabling the mcrypt extension openssl_random_pseudo_bytes() taps into a userspace CSPRNG provided by the OpenSSL library rather than the operating sytem's CSPRNG (e.g. /dev/urandom )

taps into a userspace CSPRNG provided by the OpenSSL library rather than the operating sytem's CSPRNG (e.g. ) Reading from /dev/urandom or using COM('CAPICOM.Utilities.1') leaves a lot of room for implementation error.

To make things clear, simple, and unambiguous, PHP 7 ships with two simple functions powered by your operating system's CSRPNG.

string random_bytes(int) - Generate a string of random bytes

- Generate a string of random bytes int random_int(int, int) - Generate a random integer between two integers (inclusive)

If you'd like to give these new functions a whirl and don't have PHP 7 installed yet, Paragon Initiative Enterprises maintains a polyfill for PHP 5 projects called random_compat.

composer require paragonie/random_compat # Enjoy random_bytes() and random_int() in PHP 5!

We've previously covered common uses for CSPRNGs if you need a starting point.

PECL Libsodium is Stable

The PHP bindings for the Sodium cryptography library has finally reached the stable channel in PECL. To help developers get acclimated with this library, we wrote an online book about libsodium development in PHP. You can read it for free online; downloadable copies are coming soon.

To PHP 7.1 and Beyond

There have been great leaps and bounds in the maturity of the PHP programming language, especially when it comes to cryptography features. With PHP 7.0 arriving in the coming months, we've been thinking about what we could build to make PHP 7.1 or 8.0 continue this momentum.

Make Libsodium a Core Library in 7.1 or 8.0

It's great that the PHP bindings for libsodium can be installed via pecl install libsodium (assuming you already installed the underlying library), but in future versions of PHP it would be even better if it were bundled with the rest of the language.

Three reasons:

Libsodium offers high-speed constant-time elliptic curve cryptography. The closest we can get to what libsodium offers with OpenSSL is slow RSA with sub-optimal padding schemes and an RC4 seal interface. Libsodium is currently the only way to perform AEAD in PHP. Even though OpenSSL claims to support aes-256-gcm , it doesn't actually work. Libsodium, like NaCl before it, was developed to be simple, secure and hard to misuse. OpenSSL and Mcrypt are (clearly) not.

Our Chief Development Officer has opened an RFC to add libsodium to PHP.

Let's Offer a Pluggable Cryptography Interface in 7.1

One of the initiatives our team has been leading is the development of a simple cryptography frontend for 7.1. Our idea is to make the interface simple and backend-agnostic (like PDO rather than MySQLi). The current draft will support OpenSSL and Libsodium and only allow authenticated encryption (Encrypt then MAC) or AEAD constructions.

$default_crypter = new \Php\Crypto\Asymmetric; $error_msg = $default_crypter->seal( $message, $recipient_public_key ); $fips = new \Php\Crypto\Symmetric([ 'driver' => 'openssl', 'cipher' => 'aes' ]); $fips->encrypt($some_message, $some_key);

The development of a prototype is currently being discussed and conducted at paragonie/pco_prototype. Everyone is welcome to join this discussion.

Add More Hash Functions to the Existing Hash API

Although our Chief Development Officer previously opened a feature request on the PHP bug tracker for new hash functions in PHP 7, this did not get discussed in time for inclusion in 7.0. We would instead like to make it happen in PHP 7.1.

Add Argon2 to PHP's Password API

Later versions of PHP (7.1, maybe 7.2) should be updated so that password_hash() and password_verify() supports Argon2, the winner of the Password Hashing Competition. Whether or not this will be the new PASSWORD_DEFAULT algorithm remains to be decided.

Note that Argon2 is already being added to libsodium.

PHP has come a long way, and it has a long road ahead of it. Whatever challenges or opportunities await us, the development team at Paragon Initiative Enterprises will continue to do everything we can to make security as easy as PIE for software developers the world over.