Let's Make 2017 the Year of Simply Secure PHP Cryptography

Did you know that PHP powers more than 80% of websites on the Internet? (Currently reported to be 82.4%, but that figure changes over time.)

Despite its impressive market share, the PHP community hasn't historically received a great deal of support from the computer security industry. In particular, your options for public key encryption in PHP are both limited and insecure-by-default out-of-the-box. Your public key signature options aren't much better.

Our company recognizes the importance of securing software written in PHP to the Internet at large. For instance, if an attacker were to compromise WordPress's automatic update server, they could take control of more than 27% of websites in an instant. It's hard to estimate the DDoS bandwidth available to a botnet of that magnitude, but a back-of-the-envelope calculation yields lots. At the very least, it would be more than most (if not all) networks could mitigate today.

Fortunately, we do have a plan to prevent such disasters from ever happening.

Our Plan to Make Cryptography in PHP Simply Secure

This morning, I resurrected an earlier RFC to add libsodium to the PHP core (which was never voted on). This was an idea our team initially wanted to propose for 7.1, but that ended up not happening.

Shortly before the vote was going to open, one of the PHP internals team members had told me off-list that he would vote against such an effort unless the API was trimmed down to only what was essential, and others would likely do the same.

This is reasonable: Committing to maintaining an API that exposes features you already provide elsewhere or otherwise won't need isn't a wise move.

Unfortunately, I didn't have much opportunity to revisit the RFC to trim down the list of functions and constants before the PHP 7.1 feature freeze.

Fortunately, there's plenty of time between now and the PHP 7.2 feature freeze to hammer out these details.

If this RFC is successful, software written for PHP 7.2 and on will be able to make full use of modern cryptography (X25519, Ed25519, Xsalsa20-Poly1305, BLAKE2b, SipHash, Argon2i, etc.).

What About All the Software that Still Supports PHP 5?

WordPress (27.3% of websites) still supports PHP 5.2.4.

Joomla (3.4% of websites) still supports PHP 5.3.10.

Drupal (2.2% of websites) still supports PHP 5.5.9.

These projects can't require a feature that's only available in PHP 7.2. Even if I were to ask these projects to raise their minimum version to PHP 7.2.0 after it's available, that simply won't happen.

Although adding libsodium to the newest version of PHP will significantly improve the software written in 2018 and beyond, it doesn't do a lot of good for the software that powers a third of all websites on the Internet today.

Sodium_Compat: Libsodium for Every PHP Developer

Late last year, after weighing our options, I decided to write a pure-PHP implementation of the features available in libsodium. My efforts were largely successful, although not entirely.

One of the biggest challenges is, while password hashing algorithms such as scrypt and Argon2 are possible to implement in PHP, their performance will be abysmal. Even at the lowest settings (which takes 100 milliseconds with the PHP extension in PECL to compute), our Argon2i implementation took too long without any clear way to optimize it. For the time being, we've decided to just cut it out from our implementation.

The other challenge that is not solvable: There is no way to reliably zero out memory buffers in PHP.

With these caveats and limitations in mind, I'd like to introduce the PHP community to paragonie/sodium_compat.

Sodium_Compat - Design and Implementation Strategy

The most important feature in sodium_compat is that if the libsodium PHP extension (available in PECL) is installed, it will just use that instead of our implementation. This gives you access to the fastest performance available for your server hardware.

As with our other polyfill library, paragonie/random_compat, we strive for compatibility with PHP 5.2.4 to allow projects like WordPress to consider it for adoption in a future major release. (More on this later.) For this reason, we don't use namespaces. (We may release a PHP 7.0+ version that uses namespaces and scalar type declarations in the future. That hasn't been decided yet.)

If you don't have the PHP extension installed, and are running PHP 5.3.0 or later, our polyfill library will monkey-patch itself in place of the existing functions; e.g. ParagonIE_Sodium_Compat::crypto_sign() will be accessible via \Sodium\crypto_sign() . If the extension is already installed, it won't do this (unless the desired function doesn't already exist).

For string<->integer conversion, we opted for pack() instead of chr() to avoid cache-timing side channels. We also wrote alternatives to the native strlen() and substr() functions that will deliver the correct result even if mbstring.func_overload is enabled.

How Sodium_Compat Can Improve the Security of PHP Software

Libsodium is already one of the most trusted cryptography libraries on the Internet. With sodium_compat in play, WordPress can soon secure its automatic updates with Ed25519. Drupal and Joomla can consider adopting automatic updates (with cryptographic signatures as a first-class feature).

That's just the big three PHP projects. Everything in the PHP ecosystem will one day soon be able to offer secure cryptography.

However, there remains one big challenge left to tackle:

Before our company can recommend that anyone use sodium_compat, it needs to be audited by a third party that specializes in cryptography software.

We have a Github ticket opened to discuss getting a third-party audit. In the meantime: This library is still considered experimental; please use at your own risk.