This is an Ada 2012 / SPARK 2014 project that implements the Ascon Authenticated Encryption with Additional Data Algorithm, the NIST Lightweight Cryptography standard. It was also selected as a finalist in the CAESAR competition. Ascon was designed by Christoph Dobraunig, Maria Eichlseder, Florian Mendel and Martin Schläffer.
This project implements both of the recommended Ascon variants in v1.1 and v1.2 of the
specification. A single generic package can be instantiated with the relevant parameters. There are
a few additional requirements on the target system which should not be a problem - for example it
must support operations on the Interfaces.Unsigned_64
type.
This project is free software (using the ISC permissive licence) and is provided with no
warranties, as set out in the file LICENSE
.
The main generic package is Ascon
which implements the high-level API. This consists of just two
procedures, AEADEnc
and AEADDec
. The former procedure takes in a key K
, a 'nonce' N
,
optional associated data A
(not encrypted) and the optional message to be encrypted M
and
returns the encrypted cipher-text C
and the authentication tag T
. The latter procedure performs
the decryption and returns the decoded message and a Boolean that indicates whether the message was
valid. If either of the A
or M
parameters are not used, the constant Null_Storage_Array
can
be passed to the routines.
Packages Ascon128v11
and Ascon128av11
are instantiations of the generic package with the
parameters recommended in version 1.1 of the specification. Packages Ascon128v12
and
Ascon128av12
are instantiations of the generic package with the parameters recommended in version
1.2 of the specification.
Ascon_Definitions
defines some constrained types used in the generic formal parameters and
Ascon.Load_Store
contains functions that convert between standard word sizes and Storage_Array
in Little-Endian format.
Ascon.Access_Internals
allows access to the lower-level API which allows you to follow the
internal state of the cipher as it processes some data. Ascon.Utils
contains useful helper
functions for printing out Storage_Array
and State
types.
Three example programs are included. ascon128_demo
is a simple example of using the high-level
API and demonstrates successful encryption and decryption, and also unsuccessful decryption if the
tag is altered.
ascon_test_vectors
uses the lower-level API to print the trace of a sample encryption for both of
the suggested variants of Ascon128. These can be compared with the output of the reference C code
provided by the Ascon designers. In order to get a more detailed trace from the reference C code,
the line //#define PRINTSTATE
in ascon.c
should be un-commented.
ascon_check_padding
checks that authenticated encryption and decryption works correctly when the
lengths of the associated data and message vary. This is primarily to check for any bugs in the
implementation of the padding.
As the code is written in the SPARK 2014 subset of Ada 2012, it is possible to formally verify properties of the code and eliminate the possibility of run-time exceptions.
The GPL SPARK prover gnatprove
shipped with GNAT Community 2021 from
AdaCore is used for this project. It is also able to prove the
absence of all potential sources of run-time exceptions without manual intervention. This includes
checking for the non-initialization of arrays, which was not possible before GNAT Community 2020.
It also proves that AEADDec
will not return any decrypted data if the tag verification failed.
The project has been updated to work withe Alire package manager, so it can be built with the usual
command alr build
. The tests
directory contains a sub-project that includes tests of the code.
Alternatively, the gprbuild
project files can be used directly. These have the usual flags
available, but with one custom flag:
ascon_spark_load_store
can only be set toexplicit
(the default). This setting is reserved for possible future accelerated big-/little-endian conversions.
Note that the file ascon-compare_tags.adb
is given special treatment, as it is never optimized
regardless of the optimization flags selected. This is deliberate, in an attempt to prevent the
compiler from optimizing the tag check to 'short-circuit' - that is, to prevent it from re-writing
the code to return early if two tags differ at an early position. This optimization can produce a
timing small side-channel which can, in certain situations, leak information to opponents. This is
also the reason why the comparison of the two tag arrays is not written in the most obvious way.
To verify the code, GNATprove can be invoked via the GnatStudio IDE. Alternatively the following command line can be used:
-
SPARK from GNAT Community 2021
gnatprove -P ascon_spark.gpr -j0 -Xload_store=explicit -Xmode=debug --level=0
Add --report=all
if you want to see the checks that are proved as well.