Choosing the Right Cryptography Library for your PHP Project: A Guide

If the words on this page are confusing, please read our guide to cryptography terms and concepts first.

Cryptography is not magic. Adding encryption to an application doesn't automatically make it secure against attackers (especially if you aren't authenticating your ciphertext). But if you do need it to satisfy a business need, conventional wisdom states that you almost certainly should not try to design your own cryptography. Instead, you should use an existing cryptography library.

Okay, great. So which PHP cryptography library should I use?

That depends on your exact requirements. Let's look at some good choices. (We won't cover any terrible choices.)

Secure PHP Cryptography Library Recommendations

What follows is a list of PHP cryptography libraries that we would ever feel confident deploying in a production environment. This list is prioritized based on three criteria:

How secure is the library if used correctly? How hard is it to do something dangerous? How easy is it for a non-cryptographer to use to its fullest?

Halite - Paragon Initiative Enterprises

We're not just recommending this one because we wrote it, it's our first suggestion because you get all the security of using libsodium with a simple and intuitive interface. It's free software and the source code is readily available.

Benefits of Using Halite:

Mainline: Symmetric-key authenticated encryption Symmetric-key authentication (e.g. for API messages) Asymmetric-key authenticated encryption Asymmetric-key anonymous encryption Asymmetric-key digital signatures

Whole-file cryptography (see: all mainline features)

Encrypted cookies

Password storage

You don't have to know what a nonce is, and you don't need to particularly care about authenticated encryption. Halite does all of that for you.

We built Halite so PHP developers could get all the security benefits of the libsodium extension, but with a simpler interface. Check out the Halite documentation to see how easy it is to use. (Although the API is stable, the documentation is incomplete but it covers enough to get you started.)

The only downside is that you must be able to install the libsodium PHP extension to use Halite. For many projects, this is a no-go.

Installation Guide:

Install the libsodium PHP extension. composer require paragonie/halite

Libsodium - Frank Denis

Obviously, if you don't like any of the design decisions we made with Halite, you can (read: should) consider just using libsodium directly.

Benefits of Using Libsodium:

Symmetric-key authenticated encryption (also: AEAD)

Symmetric-key authentication

Asymmetric-key authenticated encryption

Asymmetric-key anonymous encryption

Asymmetric-key digital signatures

Cryptographic hash functions

Password storage

A swiss army knife of cryptography primitives (e.g. Elliptic Curve Diffie-Hellman over Curve25519)

The ability to wipe (zero-fill) memory in PHP

So much more

Hats off to Frank Denis for maintaining one of the most reliable, cross-platform cryptography libraries in the world, and also to the team that wrote NaCl (which libsodium is forked from).

Installation guide:

See the relevant documentation.

PHP Encryption - Defuse Security

If you can't install PHP extensions from PECL (so no libsodium ever), this library should be your Plan B. In general, you should even prioritize it over whatever your framework provides, as our security team often finds vulnerabilities in the symmetric-key encryption features that PHP frameworks provide.

Benefits of using Defuse Security's PHP Encryption Library:

Symmetric-key authenticated encryption

It solves a single problem that most people get wrong (and solves it well). Version 2 of the library (coming soon!) will also include whole-file encryption, but it's not out yet, so we can't give it credit for that just yet.

Installation guide:

composer require defuse/php-encryption

If you must implement symmetric-key encryption, use Defuse's library above. Defuse Security's library gives you Authenticated Encryption, whereas phpseclib's AES implementation does not authenticate ciphertexts, so if you use it, you will be vulnerable to chosen-ciphertext attacks. (Their interactive documentation also dangerously defaults to ECB mode, which is the worst block cipher mode.)

Even though phpseclib exposes far too low-of-a-level an API for general purpose symmetric-key cryptography for us to recommend it to PHP developers that lack any cryptography background, they offer a better asymmetric-key cryptography interface than ext/openssl .

If you absolutely must implement asymmetric-key cryptography (public-key encryption, digital signatures) and you can't use libsodium for whatever reason, then you want to use phpseclib's implementation while strictly following the cryptography right answers given by Colin Percival.

Specifically:

RSA Encryption : RSA-OAEP, taking care to $rsa->setMGFHash('sha256') first

: RSA-OAEP, taking care to first RSA Signatures: RSA-PSS, once again explicitly using MGF1+SHA256

If you happen to be a cryptography expert, you can ignore our warnings and use phpseclib for symmetric-key cryptography as well. But most programmers aren't, so please don't.

Benefits of using PHPSecLib:

Symmetric-key authentication (via HMAC, which PHP offers too)

Asymmetric-key anonymous encryption (RSA)

Asymmetric-key digital signatures (RSA)

Installation guide:

composer require phpseclib/phpseclib

Update (2015-11-19): Easy RSA - Paragon Initiative Enterprises

After this blog post was published, we wrote EasyRSA as a drop-in implementation of our advice. EasyRSA uses phpseclib in an opinionated, secure-by-default manner.

EasyRSA Encryption Process

Problem: Encrypt an incredibly large string with RSA, even though RSA itself doesn't support encrypting large strings of data.

The naive solution is to break your input string into chunks then encrypt each one individually. Unfortunately, this is very similar to the dreaded ECB mode. Also: It would be terribly slow. This is a bad idea.

Our solution:

Generate an ephemeral encryption key Encrypt your message using Defuse Security's PHP symmetric-key encryption library Encrypt the ephemeral key with the given RSA public key (using a mode that actually isn't vulnerable to padding oracles) Base64-encode and concatenate both ciphertexts with a version tag prefix Append a checksum (truncated SHA256 hash) of step 4 to make it easier to detect transmission / storage errors

To decrypt a message:

Verify the checksum and version tag Decrypt the ephemeral key using the correct RSA private key Use the decrypted key in step 2 to obtain the plaintext

EasyRSA only uses RSAES-OAEP + MGF1-SHA256 with e = 65537 for public-key encryption, which is not known to be vulnerable to any padding oracle attacks.

EasyRSA Signature Process

RSA signatures are comparatively straightforward: Calculate an RSA signature using RSASS-PSS + MGF1-SHA256 with e = 65537, then verify it configured to only accept those kind of signatures.

But seriously, if you want secure cryptography for your PHP project, try to find a way to use libsodium. We're pushing to make libsodium a core extension in PHP 7.1, so hopefully this will be as easy as "update to the latest version of PHP" in the near future.

About Our PHP Cryptography Library Recommendations

What About Other Libraries?

If any library is not listed above, its absence can be explained by one of three possible reasons:

We have audited the library, and it wasn't secure enough for us to recommend it in good conscience. (Chances are, we've also notified the authors of any vulnerabilities we found so they can be fixed.) It's an extremely narrow use case (e.g. Crypt_GPG ) and, while secure, isn't relevant to the most common use cases for cryptography. We are very busy and haven't had a chance to audit it yet. (We might not even know it exists.)

If you're interested in some of the libraries we've found to be vulnerable, check out our security advisories page.

What Should I Use to Encrypt Passwords in PHP?

Well, you don't encrypt passwords, you hash them with an appropriate password-hashing algorithm. Currently, the best password library to use is the one built into PHP: password_hash() and password_verify() . This is unlikely to change for 99% of programmers or businesses. It's just that good.

However, if you're storing passwords in a database that sits on a separate server from your web application, you can make password compromises less likely by encrypting the hashes (not encrypting the passwords themselves). In which case, check out Halite's Password class.

Important Security Advice Disclaimer

Although we do employ some of the leading experts in secure PHP development (and we specialize in applied cryptography), without understanding your specific project requirements and threat model, they weren't in a position to guide you to the best solution to meet your ends when they wrote this.

So if you, for example, need asymmetric encryption and elect to use Defuse Security's symmetric encryption library instead, please don't say, "Paragon Initiative Enterprises told me to do it this way!"

If you want our security advice, specific to your project, please consider hiring us for our security consulting services.

Or, in legalese: The information on this page is provided as-is and without warranty. Use it at your own risk.