Today, I wanted to gain a deeper understanding of AES encryption.
I have succesfully used AES encryption with ipsec vpn's.
But here I want to examine what are the inputs and outputs from the AES algorithm,
and do some sanity checks with test data using
openssl from the command-line.
On the wikipedia page for
AES, they mention, "..Test vectors are a set of known ciphers for a given input and key.
NIST distributes the reference of AES test vectors as AES Known Answer Test (KAT) Vectors (in ZIP format)."
That sounds like what I need as a reference, so I downloaded:
http://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip
...and selected (guessed?) file "CBCVarKey128.rsp" as suitable, because I wanted to use a 128 bit key length,
Here is one example (from 128 possible examples) from that file:
KEY = 80000000000000000000000000000000
IV = 00000000000000000000000000000000
PLAINTEXT = 00000000000000000000000000000000
CIPHERTEXT = 0edd33d3c621e546455bd8ba1418bec8
Ok, first let's sanity check we can generate the required
PLAINTEXT.
I'm using
xxd to do this, as I explained in an
earlier blog post.
# echo -n '00000000000000000000000000000000' | xxd -p -r | hexdump -C
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000010
So the above looks good. We are generating the 16 bytes of test data, from a 32 character hexadecimal string.
Openssl allow you to specify the Key and the '
Initialization Vector'
on the command like, as hexadecimal strings, using the '-K' and '-iv' parameters.
Be careful, thats an uppercase K for the key.
As another sanity check, it is useful to use the '-P' option, again uppercase,
to get openssl to report back what it thinks are the values of the Key and IV.
So lets try this:
# echo -n '00000000000000000000000000000000' | xxd -p -r | openssl enc -aes-128-cbc -P -nosalt -K '80000000000000000000000000000000' -iv '00000000000000000000000000000000'
key=80000000000000000000000000000000
iv =00000000000000000000000000000000
Ok, thats good. They Key and IV values are what we were expecting.
By the way, for this sort of validation check, we don't want to use a salt, hence the use of the '-nosalt' option.
Right, lets remove the '-P' and see what data comes out:
# echo -n '00000000000000000000000000000000' | xxd -p -r | openssl enc -aes-128-cbc -nosalt -K '80000000000000000000000000000000' -iv '00000000000000000000000000000000' | hexdump -C
00000000 0e dd 33 d3 c6 21 e5 46 45 5b d8 ba 14 18 be c8 |.Ý3ÓÆ!åFE[غ..¾È|
00000010 fe 3d e6 e1 86 98 08 4f 63 de e5 04 42 ff 94 d2 |þ=æá...OcÞå.Bÿ.Ò|
00000020
Oh, that strange!
I'm trying to encrypt 16-bytes, but the output is 32 bytes long!
But the first 16 bytes of output looks correct!
The answer to this is padding. If you specify the '-nopad' option, then you get the expected 16 bytes of output:
echo -n '00000000000000000000000000000000' | xxd -p -r | openssl enc -aes-128-cbc -nopad -nosalt -K '80000000000000000000000000000000' -iv '00000000000000000000000000000000' | xxd -p
0edd33d3c621e546455bd8ba1418bec8
Good. Thats the
CIPHERTEXT output we were expecting!
If you check '
man enc' you see that the '-nopad' option, disables standard block padding.
And the man page also notes "All the block ciphers normally use
PKCS#5 padding also known as standard block padding".
By the way, in the above tests, the IV is all-zeroes, so we can abbreviate the command like this:
echo -n '00000000000000000000000000000000' | xxd -p -r | openssl enc -aes-128-cbc -nopad -nosalt -K 80000000000000000000000000000000 -iv 0 | xxd -p
0edd33d3c621e546455bd8ba1418bec8
To finish off, lets try some decryption, reversing what we did above:
# echo -n '0edd33d3c621e546455bd8ba1418bec8' | xxd -p -r | openssl enc -aes-128-cbc -d -nosalt -K 80000000000000000000000000000000 -iv 0 -nopad | xxd -p
00000000000000000000000000000000
Ok, that looks good. I think I am begining to get the hang of this!