Paragon Initiative Enterprises Blog

The latest information from the team that develops cryptographically secure PHP software.

What's New in Defuse Security's PHP Encryption Library Version 2

As part of our efforts to reduce the friction to adopt secure authenticated secret-key encryption in the PHP community, our Chief Development Officer has been helping Taylor Hornby develop the next version of Defuse Security's PHP Encryption Library (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 instead of a PHP-land cryptography library. We've contributed documentation for libsodium in PHP.

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.1Version 2.0.0Comment
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 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. 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:

<?php
use \Defuse\Crypto\Key;

$key = Key::createNewRandomKey();
$storeMe = $key->saveToAsciiSafeString();

To restore a key:

<?php
use \Defuse\Crypto\Key;

$key = Key::loadFromAsciiSafeString($storedString);

If you want to use a password, you can use KeyProtectedByPassword instead. This generates a random key then encrypts the key with your password.

<?php
use \Defuse\Crypto\KeyProtectedByPassword;

$key = KeyProtectedByPassword::createRandomPasswordProtectedKey($password);
$saveMe = $protected_key->saveToAsciiSafeString();

And then:

<?php
use \Defuse\Crypto\KeyProtectedByPassword;

$protected_key = KeyProtectedByPassword::loadFromAsciiSafeString($storedString);
$user_key = $protected_key->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, verify the signature, and just require it.

The library's official documentation includes a tutorial for getting started.

About the Author

P.I.E. Staff

Paragon Initiative Enterprises

Paragon Initiative Enterprises is a Florida-based company that provides software consulting, application development, code auditing, and security engineering services. We specialize in PHP Security and applied cryptography.


Need Technology Consultants?

Will tomorrow bring costly and embarrassing data breaches? Or will it bring growth, success, and peace of mind?

Our team of technology consultants have extensive knowledge and experience with application security and web/application development.

We specialize in cryptography and secure PHP development.

Let's Work Together Towards Success

Our Security Newsletters

Want the latest from Paragon Initiative Enterprises delivered straight to your inbox? We have two newsletters to choose from.

The first mails quarterly and often showcases our behind-the-scenes projects.

The other is unscheduled and gives you a direct feed into the findings of our open source security research initiatives.

Quarterly Newsletter   Security Announcements