My system is safe, it uses encryption.
You heard/said this from time to time. Sure, but why and how is it safe? Do you really know this?
Laravel encryption/decryption is based on the Illuminate\Encryption\Encrypter
class, which is constructed passing an encryption key and a cipher (i.e. the encryption algorithm):
__construct($key, $cipher = 'AES-128-CBC')
It supports (among the others) the following main methods:
encrypt($value, $serialize = true)
decrypt($payload, $unserialize = true)
which, not surprisingly, are used to encrypt and decrypt data.
https://gist.github.com/4f1a73f316923576d6b0f2e96002c4fd
This is great! And it is enough to use it in the best way.
However, if you want to know what happens under the hood, keep reading.
Note that the results wouldn't be the very same since some values are computed randomly, so changes at every run.
Laravel's encrypter currently uses OpenSSL for performing AES-256 and AES-128 encryption. It also uses Message Authentication Code (MAC) protection, a mechanism to ensure data is not tampered after encryption.
Recalling the previous example, you may think that the encrypted string "eyJpdiI6ImdMd2dWcW5jMXBrUDBranRJZXQ5MEE9PSIsInZhbHVlIjoiNnhTODBSclB3ZVp3SFRRUWFWTHpReFQwYWQ1aXVmTmhXOXV5WHM2TzR1WT0iLCJtYWMiOiIwODQyZDhiMzZlNDQwZTZjYTRiYmI2MGE0MTgzNzk5NGNkZTU1Yzc5NDIyYzdjYmYwNzk2ZTA5MGNjYjc4MGYzIn0="
is by itself the ciphered version of the input. This is definitely true, but there is more to know about.
Indeed, it is a base64 conversion of a string. "What string?" you may ask... And you can get an answer by simply run:
https://gist.github.com/0bb51b39654aad27dfcc5f3ab20d22c5
which results in a json string similar to the following:
https://gist.github.com/d946d651636aa676ecae01b51eb45930
Now is more opaque than clearer... What is this?
This document is composed by the three main parts of encryption:
value
: the actual ciphered data, coded in base64iv
: the Initialization Vector is a randomly generated fixed-size data sequence inject at each run, preventing semantic-based attacks, see (Initialization vector - Wikipedia for more details). It is base64-coded toomac
: the Message Authentication Code is a signature used to detectvalue
tampering, generated hashingvalue
andiv
. It is represented in hex-string format
Note that both iv
and value
are base64 encoded too, since they are generic bytes sequence and may contain not printable values.
To understand how the payload is generated, let's give a closer look to the encrypt()
method:
https://gist.github.com/ffe9035a9a05efc294dca2ccfbeb1d71
Looking at the code, 5 steps are performed:
- Initialization Vector is generated on line
3
by generating 128 or 256 bits (according to the used cipher) of random data - Encrypted Value is generated on lines
5-8
by running OpenSSL over a (possibly) serialized version of the clear text data, using the chosen cipher, encryption key and IV. Note that the results is base64-coded - The MAC is generated by the
hash()
method, fed with base64 iv and value. Hashing is defined as: https://gist.github.com/910cafa37c8a20a1310e333a61d7e8d3
Looking at the code, 5 steps are performed:
- The json payload is extracted in line
3
. During extraction it is also validated by ensuring that: 1.1. It has an array form 1.2. It containsiv
,value
andmac
fields. 1.3.iv
lenghts is compatible with cipher requirements 1.4. Themac
is valid - Data is decrypted using OpenSSL (lines
5-12
) - Result is (possibly) unserialized and returned
This scheme provides security until the encryption key is kept secret. Let's see why:
- confidence: the clear text message can be recovered only by who knows the secret key
- integrity: if value is modified, decryption fails. If iv and value are both modified, the message could be potentially decryptable, but MAC protection will detect tampering and decryption fails. In any case, varying any combination of iv and/or value and/or mac, decryption fails due to payload corruption.
- The only way to deceive MAC protection is by knowing the encryption key, which allows to forge new valid ciphered full payloads.
Let's try: create a different encrypted message:
https://gist.github.com/01a300cfeb73cbdb1d8d32f71d159c2c
https://gist.github.com/d57c9af2720898224439062fdc088341
https://gist.github.com/858e59e1968df6772f3d104b3a1cb214
In each of the three cases the MAC control will fail preventing message decryption and DecryptException
is raised.
Now you should understand more in detail how Laravel encryption works under the hoods. Nothing changes in how you use it, but you earned more confidence in the tools you used. Moreover, you can now justify with your customer "how" your system is safe.