+ +
+

Encryption Library

+
+

Important

+

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

+
+

The Encryption Library provides two-way data encryption. To do so in +a cryptographically secure way, it utilizes PHP extensions that are +unfortunately not always available on all systems. +You must meet one of the following dependencies in order to use this +library:

+ +

If neither of the above dependencies is met, we simply cannot offer +you a good enough implementation to meet the high standards required +for proper cryptography.

+ +
+

Using the Encryption Library

+
+

Initializing the Class

+

Like most other classes in CodeIgniter, the Encryption library is +initialized in your controller using the $this->load->library() +method:

+
$this->load->library('encryption');
+
+
+

Once loaded, the Encryption library object will be available using:

+
$this->encryption
+
+
+
+
+

Default behavior

+

By default, the Encryption Library will use the AES-128 cipher in CBC +mode, using your configured encryption_key and SHA512 HMAC authentication.

+
+

Note

+

AES-128 is chosen both because it is proven to be strong and +because of its wide availability across different cryptographic +software and programming languages’ APIs.

+
+

However, the encryption_key is not used as is.

+

If you are somewhat familiar with cryptography, you should already know +that a HMAC also requires a secret key and using the same key for both +encryption and authentication is a bad practice.

+

Because of that, two separate keys are derived from your already configured +encryption_key: one for encryption and one for authentication. This is +done via a technique called HMAC-based Key Derivation Function (HKDF).

+
+
+

Setting your encryption_key

+

An encryption key is a piece of information that controls the +cryptographic process and permits a plain-text string to be encrypted, +and afterwards - decrypted. It is the secret “ingredient” in the whole +process that allows you to be the only one who is able to decrypt data +that you’ve decided to hide from the eyes of the public. +After one key is used to encrypt data, that same key provides the only +means to decrypt it, so not only must you chose one carefully, but you +must not lose it or you will also lose access to the data.

+

It must be noted that to ensure maximum security, such key should not +only be as strong as possible, but also often changed. Such behavior +however is rarely practical or possible to implement, and that is why +CodeIgniter gives you the ability to configure a single key that is to be +used (almost) every time.

+

It goes without saying that you should guard your key carefully. Should +someone gain access to your key, the data will be easily decrypted. If +your server is not totally under your control it’s impossible to ensure +key security so you may want to think carefully before using it for +anything that requires high security, like storing credit card numbers.

+

Your encryption key must be as long as the encyption algorithm in use +allows. For AES-128, that’s 128 bits or 16 bytes (charcters) long. +You will find a table below that shows the supported key lengths of +different ciphers.

+

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. In order to create +a proper key, you must use the Encryption library’s create_key() method

+
// $key will be assigned a 16-byte (128-bit) random key
+$key = $this->encryption->create_key(16);
+
+
+

The key can be either stored in your application/config/config.php, or +you can design your own storage mechanism and pass the key dynamically +when encrypting/decrypting.

+

To save your key to your application/config/config.php, open the file +and set:

+
$config['encryption_key'] = 'YOUR KEY';
+
+
+

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

+
// Get a hex-encoded representation of the key:
+$key = bin2hex($this->encryption->create_key(16));
+
+// Put the same value in your config with hex2bin(),
+// so that it is still passed as binary to the library:
+$config['encryption_key'] = hex2bin(<your hex-encoded key>);
+
+
+
+
+

Supported encryption ciphers and modes

+
+

Note

+

The terms ‘cipher’ and ‘encryption algorithm’ are interchangeable.

+
+
+

Portable ciphers

+

Because MCrypt and OpenSSL (also called drivers throughout this document) +each support different sets of encryption algorithms and often implement +them in different ways, our Encryption library is designed to use them in +a portable fashion, or in other words - it enables you to use them +interchangeably, at least for the ciphers supported by both drivers.

+

It is also implemented in a way that aims to match the standard +implementations in other programming languages and libraries.

+

Here’s a list of the so called “portable” ciphers, where +“CodeIgniter name” is the string value that you’d have to pass to the +Encryption library to use that cipher:

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cipher nameCodeIgniter nameKey lengths (bits / bytes)Supported modes
AES-128 / Rijndael-128aes-128128 / 16CBC, CTR, CFB, CFB8, OFB, ECB
AES-192aes-192192 / 24CBC, CTR, CFB, CFB8, OFB, ECB
AES-256aes-256256 / 32CBC, CTR, CFB, CFB8, OFB, ECB
DESdes56 / 7CBC, CFB, CFB8, OFB, ECB
TripleDEStripledes56 / 7, 112 / 14, 168 / 21CBC, CFB, CFB8, OFB
Blowfishblowfish128-448 / 16-56CBC, CFB, OFB, ECB
CAST5 / CAST-128cast588-128 / 11-16CBC, CFB, OFB, ECB
RC4 / ARCFourrc440-2048 / 5-256Stream
+
+

Important

+

Because of how MCrypt works, if you fail to provide a key +with the appropriate length, you might end up using a different +algorithm than the one configured, so be really careful with that!

+
+
+

Note

+

In case it isn’t clear from the above table, Blowfish, CAST5 +and RC4 support variable length keys. That is, any number in the +shown ranges is valid, although in bit terms that only happens +in 8-bit increments.

+
+
+

Note

+

Even though CAST5 supports key lengths lower than 128 bits +(16 bytes), in fact they will just be zero-padded to the +maximum length, as specified in RFC 2144.

+
+
+

Note

+

Blowfish supports key lengths as small as 32 bits (4 bytes), but +our tests have shown that only lengths of 128 bits (16 bytes) or +higher are properly supported by both MCrypt and OpenSSL. It is +also a bad practice to use such low-length keys anyway.

+
+
+
+

Driver-specific ciphers

+

As noted above, MCrypt and OpenSSL support different sets of encryption +ciphers. For portability reasons and because we haven’t tested them +properly, we do not advise you to use the ones that are driver-specific, +but regardless, here’s a list of most of them:

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cipher nameDriverKey lengths (bits / bytes)Supported modes
AES-128OpenSSL128 / 16CBC, CTR, CFB, CFB8, OFB, ECB, XTS
AES-192OpenSSL192 / 24CBC, CTR, CFB, CFB8, OFB, ECB, XTS
AES-256OpenSSL256 / 32CBC, CTR, CFB, CFB8, OFB, ECB, XTS
Rijndael-128MCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
Rijndael-192MCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
Rijndael-256MCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
GOSTMCrypt256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
TwofishMCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
CAST-128MCrypt40-128 / 5-16CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
CAST-256MCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
Loki97MCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
SaferPlusMCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
SerpentMCrypt128 / 16, 192 / 24, 256 / 32CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
XTEAMCrypt128 / 16CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
RC2MCrypt8-1024 / 1-128CBC, CTR, CFB, CFB8, OFB, OFB8, ECB
RC2OpenSSL8-1024 / 1-128CBC, CFB, OFB, ECB
Camellia-128OpenSSL128 / 16CBC, CFB, CFB8, OFB, ECB
Camellia-192OpenSSL192 / 24CBC, CFB, CFB8, OFB, ECB
Camellia-256OpenSSL256 / 32CBC, CFB, CFB8, OFB, ECB
SeedOpenSSL128 / 16CBC, CFB, OFB, ECB
+
+

Note

+

If you wish to use one of those ciphers, you’d have to pass +its name in lower-case to the Encryption library.

+
+
+

Note

+

You’ve probably noticed that all AES cipers (and Rijndael-128) +are also listed in the portable ciphers list. This is because +drivers support different modes for these ciphers. Also, it is +important to note that AES-128 and Rijndael-128 are actually +the same cipher, but only when used with a 128-bit key.

+
+
+

Note

+

CAST-128 / CAST-5 is also listed in both the portable and +driver-specific ciphers list. This is because OpenSSL’s +implementation doesn’t appear to be working correctly with +key sizes of 80 bits and lower.

+
+
+

Note

+

RC2 is listed as supported by both MCrypt and OpenSSL. +However, both drivers implement them differently and they +are not portable. It is probably worth noting that we only +found one obscure source confirming that it is MCrypt that +is not properly implementing it.

+
+
+
+

Encryption modes

+

Different modes of encryption have different characteristics and serve +for different purposes. Some are stronger than others, some are faster +and some offer extra features. +We are not going in depth into that here, we’ll leave that to the +cryptography experts. The table below is to provide brief informational +reference to our more experienced users. If you are a beginner, just +stick to the CBC mode - it is widely accepted as strong and secure for +general purposes.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mode nameCodeIgniter nameDriver supportAdditional info
CBCcbcMCrypt, OpenSSLA safe default choice
CTRctrMCrypt, OpenSSLConsidered as theoretically better than CBC, but not as widely available
CFBcfbMCrypt, OpenSSLN/A
CFB8cfb8MCrypt, OpenSSLSame as CFB, but operates in 8-bit mode (not recommended).
OFBofbMCrypt, OpenSSLN/A
OFB8ofb8MCryptSame as OFB, but operates in 8-bit mode (not recommended).
ECBecbMCrypt, OpenSSLIgnores IV (not recommended).
XTSxtsOpenSSLUsually used for encrypting random access data such as RAM or hard-disk storage.
StreamstreamMCrypt, OpenSSLThis is not actually a mode, it just says that a stream cipher is being used. Required because of the general cipher+mode initialization process.
+
+
+
+

Message Length

+

It’s probably important for you to know that 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 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 a possible character set in use.

+

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

+
+
+

Configuring the library

+

For usability, performance, but also historical reasons tied to our old +Encrypt Class, the Encryption library is designed to +use repeatedly the same driver, encryption cipher, mode and key.

+

As noted in the “Default behavior” section above, this means using an +auto-detected driver (OpenSSL has a higher priority), the AES-128 ciper +in CBC mode, and your $config['encryption_key'] value.

+

If you wish to change that however, you need to use the initialize() +method. It accepts an associative array of parameters, all of which are +optional:

+ ++++ + + + + + + + + + + + + + + + + + + + +
OptionPossible values
driver‘mcrypt’, ‘openssl’
cipherCipher name (see Supported encryption ciphers and modes)
modeEncryption mode (see Encryption modes)
keyEncryption key
+

For example, if you were to change the encryption algorithm and +mode to AES-256 in CTR mode, this is what you should do:

+
$this->encryption->initialize(
+        array(
+                'cipher' => 'aes-256',
+                'mode' => 'ctr',
+                'key' => '<a 32-character random string>'
+        )
+);
+
+
+

Note that we only mentioned that you want to change the ciper and mode, +but we also included a key in the example. As previously noted, it is +important that you choose a key with a proper size for the used algorithm.

+

There’s also the ability to change the driver, if for some reason you +have both, but want to use MCrypt instead of OpenSSL:

+
// Switch to the MCrypt driver
+$this->encryption->initialize(array('driver' => 'mcrypt'));
+
+// Switch back to the OpenSSL driver
+$this->encryption->initialize(array('driver' => 'openssl'));
+
+
+
+
+

Encrypting and decrypting data

+

Encrypting and decrypting data with the already configured library +settings is simple. As simple as just passing the string to the +encrypt() and/or decrypt() methods:

+
$plain_text = 'This is a plain-text message!';
+$ciphertext = $this->encryption->encrypt($plain_text);
+
+// Outputs: This is a plain-text message!
+echo $this->encryption->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.

+
+

Important

+

Both methods will return FALSE in case of an error. +While for encrypt() this can only mean incorrect +configuration, you should always check the return value +of decrypt() in production code.

+
+
+

How it works

+

If you must know how the process works, here’s what happens under +the hood:

+
    +
  • $this->encryption->encrypt($plain_text)
      +
    1. Derive an encryption key and a HMAC key from your configured +encryption_key via HKDF, using the SHA-512 digest algorithm.
    2. +
    3. Generate a random initialization vector (IV).
    4. +
    5. Encrypt the data via AES-128 in CBC mode (or another previously +configured cipher and mode), using the above-mentioned derived +encryption key and IV.
    6. +
    7. Prepend said IV to the resulting cipher-text.
    8. +
    9. Base64-encode the resulting string, so that it can be safely +stored or transferred without worrying about character sets.
    10. +
    11. Create a SHA-512 HMAC authentication message using the derived +HMAC key to ensure data integrity and prepend it to the Base64 +string.
    12. +
    +
  • +
  • $this->encryption->decrypt($ciphertext)
      +
    1. Derive an encryption key and a HMAC key from your configured +encryption_key via HKDF, using the SHA-512 digest algorithm. +Because your configured encryption_key is the same, this +will produce the same result as in the encrypt() method +above - otherwise you won’t be able to decrypt it.
    2. +
    3. Check if the string is long enough, separate the HMAC out of +it and validate if it is correct (this is done in a way that +prevents timing attacks against it). Return FALSE if either of +the checks fails.
    4. +
    5. Base64-decode the string.
    6. +
    7. Separate the IV out of the cipher-text and decrypt the said +cipher-text using that IV and the derived encryption key.
    8. +
    +
  • +
+
+
+

Using custom parameters

+

Let’s say you have to interact with another system that is out +of your control and uses another method to encrypt data. A +method that will most certainly not match the above-described +sequence and probably not use all of the steps either.

+

The Encryption library allows you to change how its encryption +and decryption processes work, so that you can easily tailor a +custom solution for such situations.

+
+

Note

+

It is possible to use the library in this way, without +setting an encryption_key in your configuration file.

+
+

All you have to do is to pass an associative array with a few +parameters to either the encrypt() or decrypt() method. +Here’s an example:

+
// Assume that we have $ciphertext, $key and $hmac_key
+// from on outside source
+
+$message = $this->encryption->decrypt(
+        $ciphertext,
+        array(
+                'cipher' => 'blowfish',
+                'mode' => 'cbc',
+                'key' => $key,
+                'hmac_digest' => 'sha256',
+                'hmac_key' => $hmac_key
+        )
+);
+
+
+

In the above example, we are decrypting a message that was encrypted +using the Blowfish cipher in CBC mode and authenticated via a SHA-256 +HMAC.

+
+

Important

+

Note that both ‘key’ and ‘hmac_key’ are used in this +example. When using custom parameters, encryption and HMAC keys +are not derived like the default behavior of the library is.

+
+

Below is a list of the available options.

+

However, unless you really need to and you know what you are doing, +we advise you to not change the encryption process as this could +impact security, so please do so with caution.

+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionDefault valueMandatory / OptionalDescription
cipherN/AYesEncryption algorithm (see Supported encryption ciphers and modes).
modeN/AYesEncryption mode (see Encryption modes).
keyN/AYesEncryption key.
hmacTRUENoWhether to use a HMAC. +Boolean. If set to FALSE, then hmac_digest and +hmac_key will be ignored.
hmac_digestsha512NoHMAC message digest algorithm (see Supported HMAC authentication algorithms).
hmac_keyN/AYes, unless hmac is FALSEHMAC key.
raw_dataFALSENoWhether the cipher-text should be raw. +Boolean. If set to TRUE, then Base64 encoding and +decoding will not be performed and HMAC will not +be a hexadecimal string.
+
+

Important

+

encrypt() and decrypt() will return FALSE if +a mandatory parameter is not provided or if a provided +value is incorrect. This includes hmac_key, unless hmac +is set to FALSE.

+
+
+
+

Supported HMAC authentication algorithms

+

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

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
AlgorithmRaw length (bytes)Hex-encoded length (bytes)
sha51264128
sha3844896
sha2563264
sha2242856
+

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.

+
+
+
+
+

Class Reference

+
+
+class CI_Encryption
+
+
+initialize($params)
+
+++ + + + + + + + +
Parameters:
    +
  • $params (array) – Configuration parameters
  • +
+
Returns:

CI_Encryption instance (method chaining)

+
Return type:

CI_Encryption

+
+

Initializes (configures) the library to use a different +driver, cipher, mode or key.

+

Example:

+
$this->encryption->initialize(
+        array('mode' => 'ctr')
+);
+
+
+

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

+
+ +
+
+encrypt($data[, $params = NULL])
+
+++ + + + + + + + +
Parameters:
    +
  • $data (string) – Data to encrypt
  • +
  • $params (array) – Optional parameters
  • +
+
Returns:

Encrypted data or FALSE on failure

+
Return type:

string

+
+

Encrypts the input data and returns its ciphertext.

+

Example:

+
$ciphertext = $this->encryption->encrypt('My secret message');
+
+
+

Please refer to the Using custom parameters section for information +on the optional parameters.

+
+ +
+
+decrypt($data[, $params = NULL])
+
+++ + + + + + + + +
Parameters:
    +
  • $data (string) – Data to decrypt
  • +
  • $params (array) – Optional parameters
  • +
+
Returns:

Decrypted data or FALSE on failure

+
Return type:

string

+
+

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

+

Example:

+
echo $this->encryption->decrypt($ciphertext);
+
+
+

Please refer to the Using custom parameters secrion for information +on the optional parameters.

+
+ +
+
+create_key($length)
+
+++ + + + + + + + +
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).

+
+ +
+
+hkdf($key[, $digest = 'sha512'[, $salt = NULL[, $length = NULL[, $info = '']]]])
+
+++ + + + + + + + +
Parameters:
    +
  • $key (string) – Input key material
  • +
  • $digest (string) – A SHA-2 family digest algorithm
  • +
  • $salt (string) – Optional salt
  • +
  • $length (int) – Optional output length
  • +
  • $info (string) – Optional context/application-specific info
  • +
+
Returns:

A pseudo-random key or FALSE on failure

+
Return type:

string

+
+

Derives a key from another, presumably weaker key.

+

This method is used internally to derive an encryption and HMAC key +from your configured encryption_key.

+

It is publicly available due to its otherwise general purpose. It is +described in RFC 5869.

+

However, as opposed to the description in RFC 5869, this implementation +doesn’t support SHA1.

+

Example:

+
$hmac_key = $this->encryption->hkdf(
+        $key,
+        'sha512',
+        NULL,
+        NULL,
+        'authentication'
+);
+
+// $hmac_key is a pseudo-random key with a length of 64 bytes
+
+
+
+ +
+ +
+
+ + +