As part of our efforts to reduce the friction to adopt secure authenticated secret-key encryption in the PHP community, our [Chief Development Officer](https://paragonie.com/blog/author/scott-arciszewski) has been helping Taylor Hornby develop the next version of [Defuse Security's PHP Encryption Library](https://github.com/defuse/php-encryption) (henceforth, referred to as, "Defuse Crypto"). After a year of research and development, we're happy to announce that version 2 is now available for use in your PHP projects.
As always, if you're allowed to install PHP extensions, you should really consider using [PECL libsodium](https://github.com/jedisct1/libsodium-php) instead of a PHP-land cryptography library. We've contributed [documentation for libsodium in PHP](https://paragonie.com/book/pecl-libsodium).
If you cannot (for whatever reason) install PHP extensions, **you're much better off using Defuse Crypto than attempting to write your own cryptography library**.
## Changes to `Crypto` at a Glance
| Version 1.2.1 | Version 2.0.0 | Comment |
Class Path |
Global namespace |
PSR-4 vendor namespace |
Everything is in \Defuse\Crypto now. |
Encryption |
AES-128-CBC |
AES-256-CTR |
256-bit keys offer $2^{128}$ post-quantum security |
Message Integrity |
HMAC-SHA256 |
HMAC-SHA256 |
No change was necessary. |
Key-Splitting |
Unsalted HKDF-HMAC-SHA256 |
Salted HKDF-HMAC-SHA256 |
Each message gets its own HKDF salt in addition to its own CTR nonce. |
Version Tag? |
No |
Yes |
The header is included in the MAC |
Output encoding |
Raw binary |
Hexadecimal |
We found that defaulting to raw binary was confusing to many users. |
Encryption keys |
Strings |
Objects |
See below for details. |
## New Features in Version 2.0.0
### File Encryption
The flagship feature of the next version of Defuse Crypto is the ability to encrypt large files (e.g. up to 2GB safely on a 32-bit OS) while using very low amounts of RAM.
File encryption is facilitated by a new class, `\Defuse\Crypto\File`. This was originally designed by our CDO, and then improved greatly by Taylor Hornby and many open source contributors. We have benchmarked encrypting and decrypting a 173 MB file in under 4 seconds with less than 4 MB peak memory usage using `\Defuse\Crypto\File`.
## Changes and Improvements in Version 2.0.0
### PSR-4 Namespace
Between the last release (1.2.1) and Version 2, we have refactored the library to use the namespace `\Defuse\Crypto` in compliance with PSR-4.
Previously, you could just use `Crypto::encrypt()` and `Crypto::decrypt()`. Now you have to options: Add a `use` statement or explicitly define the namespace.
### Version Tagging
When you encrypt data in Defuse Crypto 2.0.0 and newer, a fixed header is prefixed to the encrypted payload. This header contains the version of the library used for encrypting the message. This allows the library maintainers to publish a newer version with stronger algorithms (should a weakness ever be found in AES-128-CBC, HMAC-SHA-256, etc.) without rendering previously encrypted messages inaccessible.
A version tag for consists of 4 bytes: `D3 F5 XX XX`. the first two are a magic value specific to this library, the next two are the major and minor version. The header for version 2.0.x will be `D3 F5 02 00`. Should we need to update anything, version 2.1.x will use `D3 F5 02 01` and 3.0.x will use `D3 F5 03 00`. Patch releases (the third number) will not change the header.
If you have previously encrypted data with an earlier version of this library, you can use `\Defuse\Crypto\Crypto::legacyDecrypt($your_ciphertext, $your_key)` to decrypt it. We recommend you decrypt all your old data and re-encrypt it with the new tagged format, as `legacyDecrypt()` will not exist in Version 3.
This feature affects both the existing `\Defuse\Crypto\Crypto` class and the new `\Defuse\Crypto\File` class.
### Version 2 uses AES in Counter Mode, Exclusively
Where the original version of Defuse Crypto used AES-128 in CBC (Cipher Block Chaining) mode, version 2 will use CTR (Counter) mode instead. There are many reasons contributing to this change:
* CTR made far more sense for the design of the `File` API
* Simplicity -- why use two different modes when only one is needed?
* Public recommendations from [cryptographers](http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html) favor CTR over CBC
* One more reason (see below)
### HKDF Now Uses Random Salts (Stored with Ciphertext)
In addition to a random nonce for AES-128-CTR encryption, the library also generates and stores a random 256-bit salt for the HKDF key splitting feature.
The reason for this change is subtle: If you encrypt $2^{64}$ messages with a random nonce, you have a 50% chance of generating at least one duplicate nonce. In probability, this is referred to as the [Birthday paradox](https://en.wikipedia.org/wiki/Birthday_problem). A duplicate nonce can degrade the security of your cryptosystem if you use the same key. Since version 1 of the library already introduced HKDF key splitting (to separate encryption keys from authentication keys), we added a 256-bit salt (which is also authenticated by the HMAC) for the HKDF calculation.
* The situation before: Constant encryption and authentication keys, random IV. Collision after $2^{64}$ messages.
* The situation now: Deterministic encryption and authentication keys from a random salt, random IV. Collision after $2^{192}$ messages.
For the record 50% collision probability at $2^{64}$ is a rare event and $2^{192}$ is pretty close to "never going to happen before the heat death of the universe".
This change affects both the existing `\Defuse\Crypto\Crypto` class and the new `\Defuse\Crypto\File` class.
Keys Are Objects, Not Strings
Before version 2, users needed to generate a random key and then figure out how to persist it. This also had the drawback that some users were tempted to use a human-readable password instead of a proper encryption key.
Version 2 uses Key objects instead of strings:
saveToAsciiSafeString();
To restore a key:
saveToAsciiSafeString();
And then:
unlock($password);
// Now you can use $user_key directly without having to persist the password in memory
### Hexadecimal Encoding by Default
Due to feedback from the developer community (whom were largely frustrated with MySQL altering their raw binary data and rendering it unusable), `\Defuse\Crypto\Crypto::encrypt()` has been changed to hex-encode output by default. If you want raw binary, simply pass `true` as the third argument; this usage is consistent with the `hash()` and `hash_hmac()` functions.
This change affects both `Crypto::encrypt()` and `Crypto::decrypt()`. `Crypto::legacyDecrypt()` expects raw binary strings.
## How to Get Started with Defuse Crypto 2.0.0
If you're using Composer, you can simply run this command.
composer require defuse/php-encryption:^2.0
For non-Composer-users: download the [PHP Archive and GPG signature bundled with the release](https://github.com/defuse/php-encryption/releases/tag/v2.0.0), verify the signature, and just `require` it.
The [library's official documentation includes a tutorial](https://github.com/defuse/php-encryption/blob/master/docs/Tutorial.md) for getting started.