Encryption Service

Important

DO NOT use this or any other encryption library for password storage! Passwords must be hashed instead, and you should do that through PHP’s Password Hashing extension.

The Encryption Service provides two-way symmetric (secret key) data encryption. The service will instantiate and/or initialize an encryption handler to suit your parameters as explained below.

Encryption Service handlers must implement CodeIgniter’s simple EncrypterInterface. Using an appropriate PHP cryptographic extension or third-party library may require additional software to be installed on your server and/or might need to be explicitly enabled in your instance of PHP.

The following PHP extensions are currently supported:

This is not a full cryptographic solution. If you need more capabilities, for example, public-key encryption, we suggest you consider direct use of OpenSSL or one of the other Cryptography Extensions. A more comprehensive package like Halite (an O-O package built on libsodium) is another possibility.

Note

Support for the MCrypt extension has been dropped, as that has been deprecated as of PHP 7.2.

Using the Encryption Library

Like all services in CodeIgniter, it can be loaded via Config\Services:

<?php

$encrypter = \Config\Services::encrypter();

Assuming you have set your starting key (see Configuring the Library), encrypting and decrypting data is simple - pass the appropriate string to encrypt() and/or decrypt() methods:

<?php

$plainText  = 'This is a plain-text message!';
$ciphertext = $encrypter->encrypt($plainText);

// Outputs: This is a plain-text message!
echo $encrypter->decrypt($ciphertext);

And that’s it! The Encryption library will do everything necessary for the whole process to be cryptographically secure out-of-the-box. You don’t need to worry about it.

Configuring the Library

The example above uses the configuration settings found in app/Config/Encryption.php.

Option

Possible values (default in parentheses)

key

Encryption key starter

driver

Preferred handler, e.g., OpenSSL or Sodium (OpenSSL)

digest

Message digest algorithm (SHA512)

blockSize

[SodiumHandler only] Padding length in bytes (16)

cipher

[OpenSSLHandler only] Cipher to use (AES-256-CTR)

encryptKeyInfo

[OpenSSLHandler only] Encryption key info ('')

authKeyInfo

[OpenSSLHandler only] Authentication key info ('')

rawData

[OpenSSLHandler only] Whether the cipher-text should be raw (true)

You can replace the config file’s settings by passing a configuration object of your own to the Services call. The $config variable must be an instance of the Config\Encryption class.

<?php

$config         = new \Config\Encryption();
$config->key    = 'aBigsecret_ofAtleast32Characters';
$config->driver = 'OpenSSL';

$encrypter = \Config\Services::encrypter($config);

Configuration to Maintain Compatibility with CI3

New in version 4.3.0.

Since v4.3.0, you can decrypt data encrypted with CI3’s Encryption. If you need to decrypt such data, use the following settings to maintain compatibility.

<?php

use Config\Encryption;
use Config\Services;

$config         = new Encryption();
$config->driver = 'OpenSSL';

// Your CI3's 'encryption_key'
$config->key = hex2bin('64c70b0b8d45b80b9eba60b8b3c8a34d0193223d20fea46f8644b848bf7ce67f');
// Your CI3's 'cipher' and 'mode'
$config->cipher = 'AES-128-CBC';

$config->rawData        = false;
$config->encryptKeyInfo = 'encryption';
$config->authKeyInfo    = 'authentication';

$encrypter = Services::encrypter($config, false);

Supported HMAC Authentication Algorithms

For HMAC message authentication, the Encryption library supports usage of the SHA-2 family of algorithms:

Algorithm

Raw length (bytes)

Hex-encoded length (bytes)

SHA512

64

128

SHA384

48

96

SHA256

32

64

SHA224

28

56

The reason for not including other popular algorithms, such as MD5 or SHA1 is that they are no longer considered secure enough and as such, we don’t want to encourage their usage. If you absolutely need to use them, it is easy to do so via PHP’s native hash_hmac() function.

Stronger algorithms of course will be added in the future as they appear and become widely available.

Default Behavior

By default, the Encryption Library uses the OpenSSL handler. That handler encrypts using the AES-256-CTR algorithm, your configured key, and SHA512 HMAC authentication.

Setting Your Encryption Key

Your encryption key must be as long as the encryption algorithm in use allows. For AES-256, that’s 256 bits or 32 bytes (characters) long.

The key should be as random as possible, and it must not be a regular text string, nor the output of a hashing function, etc. To create a proper key, you can use the Encryption library’s createKey() method.

<?php

// $key will be assigned a 32-byte (256-bit) random key
$key = \CodeIgniter\Encryption\Encryption::createKey();

// for the SodiumHandler, you can use either:
$key = sodium_crypto_secretbox_keygen();
$key = \CodeIgniter\Encryption\Encryption::createKey(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);

The key can be stored in app/Config/Encryption.php, or you can design a storage mechanism of your own and pass the key dynamically when encrypting/decrypting.

To save your key to your app/Config/Encryption.php, open the file and set:

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Encryption extends BaseConfig
{
    public $key = 'YOUR KEY';

    // ...
}

Encoding Keys or Results

You’ll notice that the createKey() method outputs binary data, which is hard to deal with (i.e., a copy-paste may damage it), so you may use bin2hex(), or base64_encode to work with the key in a more friendly manner. For example:

<?php

// Get a hex-encoded representation of the key:
$encoded = bin2hex(\CodeIgniter\Encryption\Encryption::createKey(32));

// Put the same value with hex2bin(),
// so that it is still passed as binary to the library:
$key = hex2bin('your-hex-encoded-key');

You might find the same technique useful for the results of encryption:

<?php

// Encrypt some text & make the results text
$encoded = base64_encode($encrypter->encrypt($plaintext));

Using Prefixes in Storing Keys

You may take advantage of two special prefixes in storing your encryption keys: hex2bin: and base64:. When these prefixes immediately precede the value of your key, Encryption will intelligently parse the key and still pass a binary string to the library.

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class Encryption extends BaseConfig
{
    // In Encryption, you may use
    public $key = 'hex2bin:<your-hex-encoded-key>';
    // or
    public $key = 'base64:<your-base64-encoded-key>';
    // ...
}

Similarly, you can use these prefixes in your .env file, too!

// For hex2bin
encryption.key = hex2bin:<your-hex-encoded-key>

// or
encryption.key = base64:<your-base64-encoded-key>

Padding

Sometimes, the length of a message may provide a lot of information about its nature. If a message is one of “yes”, “no” and “maybe”, encrypting the message doesn’t help: knowing the length is enough to know what the message is.

Padding is a technique to mitigate this, by making the length a multiple of a given block size.

Padding is implemented in SodiumHandler using libsodium’s native sodium_pad and sodium_unpad functions. This requires the use of a padding length (in bytes) that is added to the plaintext message prior to encryption, and removed after decryption. Padding is configurable via the $blockSize property of Config\Encryption. This value should be greater than zero.

Important

You are advised not to devise your own padding implementation. You must always use the more secure implementation of a library. Also, passwords should not be padded. Usage of padding in order to hide the length of a password is not recommended. A client willing to send a password to a server should hash it instead (even with a single iteration of the hash function). This ensures that the length of the transmitted data is constant, and that the server doesn’t effortlessly get a copy of the password.

Encryption Handler Notes

OpenSSL Notes

The OpenSSL extension has been a standard part of PHP for a long time.

CodeIgniter’s OpenSSL handler uses the AES-256-CTR cipher.

The key your configuration provides is used to derive two other keys, one for encryption and one for authentication. This is achieved by way of a technique known as an HMAC-based Key Derivation Function (HKDF).

Sodium Notes

The Sodium extension is bundled by default in PHP as of PHP 7.2.0.

Sodium uses the algorithms XSalsa20 to encrypt, Poly1305 for MAC, and XS25519 for key exchange in sending secret messages in an end-to-end scenario. To encrypt and/or authenticate a string using a shared-key, such as symmetric encryption, Sodium uses the XSalsa20 algorithm to encrypt and HMAC-SHA512 for the authentication.

Note

CodeIgniter’s SodiumHandler uses sodium_memzero in every encryption or decryption session. After each session, the message (whether plaintext or ciphertext) and starter key are wiped out from the buffers. You may need to provide again the key before starting a new session.

Message Length

An encrypted string is usually longer than the original, plain-text string (depending on the cipher).

This is influenced by the cipher algorithm itself, the initialization vector (IV) prepended to the cipher-text, and the HMAC authentication message that is also prepended. Furthermore, the encrypted message is also Base64-encoded so that it is safe for storage and transmission regardless of the character-set in use.

Keep this information in mind when selecting your data storage mechanism. Cookies, for example, can only hold 4K of information.

Using the Encryption Service Directly

Instead of (or in addition to) using Services as described in Using the Encryption Library, you can create an “Encrypter” directly, or change the settings of an existing instance.

<?php

// create an Encryption instance
$encryption = new \CodeIgniter\Encryption\Encryption();

// reconfigure an instance with different settings
$encrypter = $encryption->initialize($config);

Remember, that $config must be an instance of Config\Encryption class.

Class Reference

class CodeIgniter\Encryption\Encryption
static createKey([$length = 32])
Parameters
  • $length (int) – Output length

Returns

A pseudo-random cryptographic key with the specified length, or false on failure

Return type

string

Creates a cryptographic key by fetching random data from the operating system’s sources (i.e. /dev/urandom).

initialize([Encryption $config = null])
Parameters
  • $config (Config\Encryption) – Configuration parameters

Returns

CodeIgniter\Encryption\EncrypterInterface instance

Return type

CodeIgniter\Encryption\EncrypterInterface

Throws

CodeIgniter\Encryption\Exceptions\EncryptionException

Initializes (configures) the library to use different settings.

Example:

<?php

$encrypter = $encryption->initialize(['cipher' => 'AES-256-CTR']);

Please refer to the Configuring the Library section for detailed info.

CodeIgniter\Encryption\EncrypterInterface
encrypt($data[, $params = null])
Parameters
  • $data (string) – Data to encrypt

  • $params (array|string|null) – Configuration parameters (key)

Returns

Encrypted data

Return type

string

Throws

CodeIgniter\Encryption\Exceptions\EncryptionException

Encrypts the input data and returns its ciphertext.

If you pass parameters as the second argument, the key element will be used as the starting key for this operation if $params is an array; or the starting key may be passed as a string.

If you are using the SodiumHandler and want to pass a different blockSize on runtime, pass the blockSize key in the $params array.

Examples:

<?php

$ciphertext = $encrypter->encrypt('My secret message');
$ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']);
$ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]);
$ciphertext = $encrypter->encrypt('My secret message', 'New secret key');
$ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]);
decrypt($data[, $params = null])
Parameters
  • $data (string) – Data to decrypt

  • $params (array|string|null) – Configuration parameters (key)

Returns

Decrypted data

Return type

string

Throws

CodeIgniter\Encryption\Exceptions\EncryptionException

Decrypts the input data and returns it in plain-text.

If you pass parameters as the second argument, the key element will be used as the starting key for this operation if $params is an array; or the starting key may be passed as a string.

If you are using the SodiumHandler and want to pass a different blockSize on runtime, pass the blockSize key in the $params array.

Examples:

<?php

echo $encrypter->decrypt($ciphertext);
echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']);
echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]);
echo $encrypter->decrypt($ciphertext, 'New secret key');
echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]);