ETOOBUSY 🚀 minimal blogging for the impatient
AES - Cipher
TL;DR
Putting together the pieces to encrypt stuff with AES, in Perl.
At this point, we have all the moving parts we need to assemble the Cipher function, let’s go!
sub cipher ($input, $key_schedule) {
return _generic_cipher(
$input, $key_schedule, \&add_round_key,
\&mix_columns, \&shift_rows, \&sub_bytes
);
} ## end sub cipher
Wait… what?!?
It turns out that the Cipher operation has an inverse to go from the ciphertext back to the plaintext, which is called InvCipher. This is built by doing all the operations in Cipher the other way around. So far so good.
The AES standard, on the other hand, introduces an equivalent algorithm EqInvCipher whose shape is exactly the same as Cipher, only with a few setup modifications.
From an implementation point of view, then, it can be convenient to
encapsulate the common behaviour into its own _generic_cipher
, and use
it from the outside, feeding the right data/moving parts. So we also
have the inverse almost for free:
sub equivalent_inv_cipher ($input, $modified_key_schedule) {
return _generic_cipher($input, $modified_key_schedule, \&add_round_key,
\&inv_mix_columns, \&inv_shift_rows, \&inv_sub_bytes);
}
All functions assume that the key schedule will be fed in, so the
functions signature aim to remind us that cipher
needs the regular
output of key_expansion
, while inv_cipher
needs something out of
modify_key_schedule_*
.
So, again, how is this generic ciphering implemented? Here it is:
sub _generic_cipher ($input, $key_schedule, $ark, $mxc, $shr, $sby) {
my $state = [split m{}mxs, $input];
my ($first, @mids) = $key_schedule->@*;
my $last = pop @mids;
$ark->($state, $first);
$ark->($mxc->($shr->($sby->($state))), $_) for @mids;
$ark->($shr->($sby->($state)), $last);
return join '', $state->@*;
} ## end sub _generic_cipher
Almost straight from page 15 of AES, with the comfort of Perl:
$ark
is the AddRoundKey operation - it could have been fixed toadd_round_key
in the implementation, as it’s the same as its inverse so it’s fed by bothcipher
andequivalent_inv_cipher
$mxc
is the right version between MixColumns/InvMixColumns$shr
is the right version between ShiftRows/InvShiftRows$sby
is the right version between SubBytes/InvSubBytes
The key schedule contains the parts of the expanded key that can be used in the different rounds, where the first and last ones have to be treated specially. I admit that I initially wrote this:
my ($first, @mids, $last) = $key_schedule->@*; # WRONG WRONG WRONG!
but of course this will not work in Perl because @mids
sucks
everything after the first item, leaving $last
with nothing (i.e.
undef
).
This technically is everything we needed, although it’s still a bit low level. In the next post we’ll take a look at an API that’s slightly higher level.
Stay safe!