
Encryption is a complicated topic and one that, when done incorrectly, could result in sensitive data being exposed to bad actors or lost due to an inability to decrypt that data at a later date.
The PHP Simple Encryption library is designed to simplify the process of encrypting and decrypting data while ensuring best practices are followed. By default is uses a secure encryption algorithm and generates a cryptologically strong initialization vector (more on that later) so developers do not need to become experts in encryption to securely store sensitive data.
Requirements
- PHP 7.2+
- Openssl PHP extension
Installation
To add PHP Simple Encryption to your project, add a dependency on stymiee/php-simple-encryption to your project’s composer.json file if you use Composer to manage the dependencies of your project. Here is a minimal example of a composer.json file that just defines a dependency on PHP Simple Encryption:
"require": { "stymiee/php-simple-encryption": "^1" }
Including it in your project is then as simple as including your vendor autoload file:
require('./vendor/autoload.php');
Basic Usage
Most encryption ciphers require three items to successfully encrypt text:
- A secret key (think of this as the password of the encrypted text)
- An initialization vector (IV)
- The text to be encrypted
The steps to properly encrypt text is as follows:
- Create a secret key
- Create a secure, randomly generated initialization vector
- Encrypt the text using the secret key and IV
- Securely store the secret key and IV for later use to decrypt the encrypted text
The steps to properly decrypt encrypted text is as follows:
- Securely retrieve the secret key and IV
- Decrypt the text using the secret key and IV
Below is an example showing both the encryption and decryption of text. Normally you would not encrypt data and then immediately decrypt it, but this is for illustration purposes only.
use Encryption\Encryption; use Encryption\Exception\EncryptionException; $text = 'Testing, testing, 123'; $key = 'secretkey'; try { $encryption = Encryption::getEncryptionObject(); $iv = $encryption->generateIv(); $encryptedText = $encryption->encrypt($text, $key, $iv); $decryptedText = $encryption->decrypt($encryptedText, $key, $iv); printf('Cipher : %s%s', $encryption->getName(), PHP_EOL); printf('IV : %s%s', base64_encode($iv), PHP_EOL); printf('Encrypted: %s%s', $encryptedText, PHP_EOL); printf('Decrypted: %s%s', $decryptedText, PHP_EOL); } catch (EncryptionException $e) { echo $e; }
Outputs
Cipher : AES-256-CBC IV : Cz5BfO8PDgwFTlDNXoFiAQ== Encrypted: Hj3xYHJnTWq5ZkHRGbnGdh4qRXd3PEzgI0Rbru9GynY= Decrypted: Testing, testing, 123
You will notice the secret key is in plain text in the example above. This value is something you can create however you want. Randomness is not considered important here. However, your initialization vector (IV) should be as random as possible. A common pitfall developers fall into when creating an IV is to choose a method of generation that is insufficiently random if it is random at all.
PHP Simple Encryption solves that problem by handling IV generation. IVs are generated using openssl_random_pseudo_bytes()
which generates a random string of bytes (of a chosen length). The randomness of these bytes will be cryptologically strong and should always be preferred to a home grown solution. Additionally, if a better method should become available, by using PHP Simple Encryption to generate your IV you can gain this benefit simply by updating your version of the library without the need to make any changes in your code.
But what happens if openssl_random_pseudo_bytes()
is unable to generate a cryptologically strong string of bytes? If this were to occur, most likely because the application is running on a older system, the library falls back to random_bytes()
which is PHP’s built in equivalent to openssl_random_pseudo_bytes()
.
In the unlikely event that openssl_random_pseudo_bytes()
and random_bytes()
both fail to produce an IV, the library offers the option to fall back to a built in random string generator. This IV generator does not generate a cryptologically strong value and should not be used in any environment where data security is a requirement. This can be enabled by passing true
to generateIv()
:
$iv = $encryption->generateIv(true);
true
should be a boolean and not a string or number.
Once you have generated an IV, you can use it to encrypt you value. But to decrypt that value later you will need that IV as part of the decryption process. generateIv()
will generate bytes that are not human friendly (but still computer friendly). To make it easier for humans to work with you should consider base64 encoding that string when storing it:
$savedIv = base64_encode($iv);
By default, PHP Simple Encryption uses the AES with 256-bit encryption in CBC (Cipher Blocker Chaining) mode (AES-256-CBC). This form of encryption is considered very secure which is why it is the default encryption method when encrypting data using this library. However, your business requirements may require you to use a different cipher. Perhaps to decrypt text encrypted by a third party or before this method of encryption was available. You can set the encryption cipher to any cipher supported by your system and the PHP Simple Encryption library. To do this you specify the name of the encryption cipher you wish to use when creating your encryption object.
$encryption = Encryption::getEncryptionObject('SM4-CFB');
Not every encryption algorithm requires an IV. Electronic codebook (ECB) mode is one such example.
use Encryption\Encryption; use Encryption\Exception\EncryptionException; $text = 'Testing, testing, 123'; $key = 'secretkey'; try { $encryption = Encryption::getEncryptionObject('AES-128-ECB'); $encryptedText = $encryption->encrypt($text, $key); $decryptedText = $encryption->decrypt($encryptedText, $key); printf('Cipher : %s%s', $encryption->getName(), PHP_EOL); printf('Encrypted: %s%s', $encryptedText, PHP_EOL); printf('Decrypted: %s%s', $decryptedText, PHP_EOL); } catch (EncryptionException $e) { echo $e; }
Outputs
Cipher : AES-128-ECB Encrypted: 2d8vGmPYXNIRbsvjnXgyzoIBEq0pAelbfYZSIakP+k8= Decrypted: Testing, testing, 123
Authenticated encryption with associated data (AEAD) takes encryption a step further and in addition to securing the data through encryption, it ensures the data’s authenticity as well. In addition to outputting encrypted text it also provides an authentication tag. This tag is used to authenticate the encrypted text. In other words it validates that the tag matches the encrypted text generated with it. CCM and GCM mode ciphers use this form of encryption.
use Encryption\Encryption; use Encryption\Exception\EncryptionException; $text = 'Testing, testing. 123'; $key = 'secretkey'; try { $encryption = Encryption::getEncryptionObject('AES-128-GCM'); $iv = $encryption->generateIv(); $encryptedText = $encryption->encrypt($text, $key, $iv, $tag); $decryptedText = $encryption->decrypt($encryptedText, $key, $iv, $tag); printf('Cipher : %s%s', $encryption->getName(), PHP_EOL); printf('IV : %s%s', base64_encode($iv), PHP_EOL); printf('Tag : %s%s', base64_encode($tag), PHP_EOL); printf('Encrypted: %s%s', $encryptedText, PHP_EOL); printf('Decrypted: %s%s', $decryptedText, PHP_EOL); } catch (EncryptionException $e) { echo $e; }
Outputs
Cipher : AES-128-GCM IV : /x3+e5+XCnjpf5ec Tag : yRuma5vRLsIfh/WIevOhEA== Encrypted: HJr+C5BUgcwf537RDSNcIysULilYP+Rq Decrypted: Testing, testing. 123
Under the hood of Encryption::encrypt()
the $tag
parameter is passed by reference to openssl_encrypt()
. A value is assigned to it upon a successful function call. You will need to store value. Like the IV, you may want to base64 encode it.
Supported Ciphers
The PHP Simple Encryption library currently defaults to AES-256-CBC
. This may change in future versions and will result in a major version bump when this occurs. To determine what cipher you are using you can call the getName()
method on your encryption object:
$encryption = Encryption::getEncryptionObject(); $cipherName = $encryptuion->getName(); // AES-256-CBC
To get a list of ciphers supported by your system and this library you can call Encryption::listAvailableCiphers()
to receive an array of available ciphers. This list is an intersection of available ciphers from your system’s installed version of Openssl and ciphers supported by this library.
$availableCiphers = Encryption::listAvailableCiphers(); var_export($availableCiphers);
Below is a list of PHP Simple Encryption’s supported ciphers as of the release of version 1.0.0:
AES | Aria | Blowfish/Camellia | Cast5/DES | Idea/RC2/SeedSM4 |
---|---|---|---|---|
aes-128-cbc | aria-128-cbc | bf-cbc | cast5-cbc | id-aes128-ccm |
aes-128-ccm | aria-128-ccm | bf-cfb | cast5-cfb | id-aes128-gcm |
aes-128-cfb | aria-128-cfb | bf-ecb | cast5-ecb | id-aes192-ccm |
aes-128-cfb1 | aria-128-cfb1 | bf-ofb | cast5-ofb | id-aes192-gcm |
aes-128-cfb8 | aria-128-cfb8 | camellia-128-cbc | chacha20 | id-aes256-ccm |
aes-128-ctr | aria-128-ctr | camellia-128-cfb | chacha20-poly1305 | id-aes256-gcm |
aes-128-ecb | aria-128-ecb | camellia-128-cfb | des-cbc | idea-cbc |
aes-128-gcm | aria-128-gcm | camellia-128-cfb | des-cfb | idea-cfb |
aes-128-ofb | aria-128-ofb | camellia-128-ctr | des-cfb1 | idea-ecb |
aes-128-xts | aria-192-cbc | camellia-128-ecb | des-cfb8 | idea-ofb |
aes-192-cbc | aria-192-ccm | camellia-128-ofb | des-ecb | rc2-40-cbc |
aes-192-ccm | aria-192-cfb | camellia-192-cbc | des-ede-cbc | rc2-64-cbc |
aes-192-cfb | aria-192-cfb | camellia-192-cfb | des-ede-cfb | rc2-cbc |
aes-192-cfb1 | aria-192-cfb8 | camellia-192-cfb | des-ede-ofb | rc2-cfb |
aes-192-cfb8 | aria-192-ctr | camellia-192-cfb | des-ede3-cbc | rc2-ecb |
aes-192-ctr | aria-192-ecb | camellia-192-ctr | des-ede3-cfb | rc2-ofb |
aes-192-ecb | aria-192-gcm | camellia-192-ecb | des-ede3-cfb1 | seed-cbc |
aes-192-gcm | aria-192-ofb | camellia-192-ofb | des-ede3-cfb8 | seed-cfb |
aes-192-ofb | aria-256-cbc | camellia-256-cbc | des-ede3-ofb | seed-ecb |
aes-256-cbc | aria-256-ccm | camellia-256-cfb | des-ofb | seed-ofb |
aes-256-ccm | aria-256-cfb | camellia-256-cfb | desx-cbc | sm4-cbc |
aes-256-cfb | aria-256-cfb1 | camellia-256-cfb | sm4-cfb | |
aes-256-cfb1 | aria-256-cfb8 | camellia-256-ctr | sm4-ctr | |
aes-256-cfb8 | aria-256-ctr | camellia-256-ecb | sm4-ecb | |
aes-256-ctr | aria-256-ecb | camellia-256-ofb | ||
aes-256-ecb | aria-256-gcm | |||
aes-256-gcm | aria-256-ofb | |||
aes-256-ofb | ||||
aes-256-xts |
Help & Support
If you require assistance using this library start by viewing the HELP.md file included in this package. It includes common problems and their solutions.
If you continue to have difficulty using this code please do not contact me through this website. Since this software is free to the community, the community can assist me in supporting it. I am an active participant at StackOverflow. Others also frequent it who are also capable of assiting you with this code. When posting your question there, or anywhere for that matter, be sure to include the following:
- A link to either this tutorial and/or the GitHub repository so others can see what software you are using and can download it if necessary so if they attempt to reproduce the problem you are having.
- Your code as it is implemented in your software. Make sure you format it so it is readable by others. Be sure to include all of the relevant pieces including:
- Your unencrypted text
- The key you are using
- The IV you are using
- The output of your method calls
- A description of what you are expecting your code to do (but it is not happening).
- Any error message you are getting.
Respect!!!
Hi.
Thanks for a very interesting article, and a very useful library.
Data-encryption has always been an interest of mine. I have studied many different ways that data can be “scrambled”, hashed, and also other means of checking data integrity.
With so much effort, not to mention lots of money, being devoted to breaking into computer systems and data exfiltration, data encryption becomes just as important as the security of the systems themselves. I have always believed in “security through layers” as the best way to approaching an effective solution in securing any system that is connected to any other.
Any contribution to the already existing, hopefully – good-quality, means of achieving better security – comes at a time when we constantly hear of data breaches and compromised systems, even involving the systems employed by many Fortune 500 companies.
I will like to experiment with the library you have offered up to the public, to further educate myself on what other applicable methods I may derive from my research. I am by no means a “security professional”, but an avid fan of technology – and how to get the best from its use. The field study of data-security and integrity is an on-going process of learning, and refining what we already knew – or did not know before.
My hearty congrats on a fine piece of work! 🙂
– Jim S.