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:

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).

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 use the encrypted 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(<yourhex-encodedkey>);

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 name

CodeIgniter name

Key lengths (bits / bytes)

Supported modes

AES-128 / Rijndael-128

aes-128

128 / 16

CBC, CTR, CFB, CFB8, OFB, ECB

AES-192

aes-192

192 / 24

CBC, CTR, CFB, CFB8, OFB, ECB

AES-256

aes-256

256 / 32

CBC, CTR, CFB, CFB8, OFB, ECB

DES

des

56 / 7

CBC, CFB, CFB8, OFB, ECB

TripleDES

tripledes

56 / 7, 112 / 14, 168 / 21

CBC, CFB, CFB8, OFB

Blowfish

blowfish

128-448 / 16-56

CBC, CFB, OFB, ECB

CAST5 / CAST-128

cast5

88-128 / 11-16

CBC, CFB, OFB, ECB

RC4 / ARCFour

rc4

40-2048 / 5-256

Stream

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.

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 name

Driver

Key lengths (bits / bytes)

Supported modes

AES-128

OpenSSL

128 / 16

CBC, CTR, CFB, CFB8, OFB, ECB, XTS

AES-192

OpenSSL

192 / 24

CBC, CTR, CFB, CFB8, OFB, ECB, XTS

AES-256

OpenSSL

256 / 32

CBC, CTR, CFB, CFB8, OFB, ECB, XTS

Rijndael-128

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

Rijndael-192

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

Rijndael-256

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

GOST

MCrypt

256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

Twofish

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

CAST-128

MCrypt

40-128 / 5-16

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

CAST-256

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

Loki97

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

SaferPlus

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

Serpent

MCrypt

128 / 16, 192 / 24, 256 / 32

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

XTEA

MCrypt

128 / 16

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

RC2

MCrypt

8-1024 / 1-128

CBC, CTR, CFB, CFB8, OFB, OFB8, ECB

RC2

OpenSSL

8-1024 / 1-128

CBC, CFB, OFB, ECB

Camellia-128

OpenSSL

128 / 16

CBC, CFB, CFB8, OFB, ECB

Camellia-192

OpenSSL

192 / 24

CBC, CFB, CFB8, OFB, ECB

Camellia-256

OpenSSL

256 / 32

CBC, CFB, CFB8, OFB, ECB

Seed

OpenSSL

128 / 16

CBC, 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.

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 name

CodeIgniter name

Driver support

Additional info

CBC

cbc

MCrypt, OpenSSL

A safe default choice

CTR

ctr

MCrypt, OpenSSL

Considered as theoretically better than CBC, but not as widely available

CFB

cfb

MCrypt, OpenSSL

N/A

CFB8

cfb8

MCrypt, OpenSSL

Same as CFB, but operates in 8-bit mode (not recommended).

OFB

ofb

MCrypt, OpenSSL

N/A

OFB8

ofb8

MCrypt

Same as OFB, but operates in 8-bit mode (not recommended).

ECB

ecb

MCrypt, OpenSSL

Ignores IV (not recommended).

XTS

xts

OpenSSL

Usually used for encrypting random access data such as RAM or hard-disk storage.

Stream

stream

MCrypt, OpenSSL

This is not actually a mode, it just says that a stream cipher is being used. Required because of the general cipher+mode initialization process.

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.

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'));

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

$this->encryption->encrypt($plain_text)

Derive an encryption key and a HMAC key from your configured
encryption_key via HKDF, using the SHA-512 digest algorithm.

Generate a random initialization vector (IV).

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.

Prepend said IV to the resulting cipher-text.

Base64-encode the resulting string, so that it can be safely
stored or transferred without worrying about character sets.

Create a SHA-512 HMAC authentication message using the derived
HMAC key to ensure data integrity and prepend it to the Base64
string.

$this->encryption->decrypt($ciphertext)

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.

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 agains it). Return FALSE if either of
the checks fails.

Base64-decode the string.

Separate the IV out of the cipher-text and decrypt the said
cipher-text using that IV and the derived encryption key.

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.

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.