Secure your device with ASCON, the new encryption standard for small devices (Java)
On Feb. 7th. 2023 NIST (https://csrc.nist.gov/News/2023/lightweight-cryptography-nist-selects-ascon) announced the selection of the encryption algorithm family ASCON as new standard for encryption on small devices:
The team has decided to standardize the Ascon family for lightweight cryptography applications as it meets the needs of most use cases where lightweight cryptography is required. Congratulations to the Ascon team! NIST thanks all of the finalist teams and the community members who provided feedback that contributed to the selection.
My first impression was — “why do we need a new encryption algorithm, we do have AES-CBC, AES-GCM and the Libsodium encryption schemes ?”. But then I realized that these algorithms usually run fast on modern computers and smartphones because they have special instruction sets in their microcontrollers that optimize the algorithms running. The new algorithm is dedicated to those devices with a different chipset like Bluetooth beacons or sensors or NFC/RFID environments that run with limited resources (“small devices”).
The ASCON algorithm works very similar to the well known AES-GCM algorithm as it provides an authenticated encryption and can authenticate (unencrypted) additional data (“AEAD”) as well.
This is the profile of the algorithm:
- encryption type: symmetric encryption
- key length: 128 bit (16 byte)
- block length: 128 bit (16 byte)
- nonce length: 128 bit (16 byte)
- authentication tag length: 128 bit (16 byte)
You find more details on the algorithm on the inventor`s website (https://ascon.iaik.tugraz.at/index.html); the latest specification update is available on the NIST page: https://csrc.nist.gov/csrc/media/Projects/lightweight-cryptography/documents/finalist-round/status-updates/ascon-update.pdf. The algorithm was invented by Christoph Dobraunig, Maria Eichlseder, Florian Mendel and Martin Schläffer.
Now we are moving over to the practical side and run an encryption and decryption on an Android device (Android 13 / SDK 33) using the Java reference code (https://github.com/ascon/javaascon). At the moment there are 3 algorithms choosen (Ascon-128, Ascon-128a and Ascon-80pq), but the Java reference code provides only code for the first two ones. The major security provider for Java (Bouncy Castle, https://github.com/bcgit/bc-java/) is updating the sources in these days so within the next time an implementation with all of them should be available as well.
The sample app will inform you about the purpose of the app and lets you chose the algorithm (Ascon128v12 orAscon128av128):
To run the code in MainActivity.java just copy the two files “Ascon128v12.java” and “Ascon128av12.java” from the reference code to your package (and change the package name accordingly). There are four methods available for each algorithm and for the reason of clarity I did not make just one method for each purpose:
- ascon128v12Encryption: The method takes the 16 bytes long key and nonce, the plaintext and (optional) additional data; each in form of a byte array. The additional data will not get encrypted but are part of the authentication checksum. The output is the ciphertext that is of length (plaintext + authentication tag [16 bytes length]) or 0 byte if any error occurs. The (complete) ciphertext is a concatenation of the encrypted data and the authentication tag (“ciphertext | authentication tag”)
- ascon128v12Decryption: The method takes the 16 bytes long key and nonce, the (complete) ciphertext and (optional) additional data; each in form of a byte array. The additional data will not get decrypted but are part of the authentication checksum so you need to provide the exact same data as used on encryption. The output is the plaintext or and empty string if any error occurs.
- ascon128v12SplitCiphertext: This is just a service method that splits the (concatenated) complete ciphertext in the ciphertext and the authentication tag. As e.g. some Bluetooth Low Energy devices limit the transmission of data to 20 bytes per transmission it is helpful to have the ciphertext and authentication tag in different variables.
- ascon128v12ConcatenateCiphertext: This is the companion method to the “split method” — it takes the ciphertext and authentication tag and combines them to a “complete ciphertext”.
These are the results when running a complete encryption and decryption on an emulator:
The code needed for the encryption is very simple — provide a 16 bytes long key and nonce, the plaintext to encrypt and (optional) some additional data and receive the encrypted and authenticated ciphertext (all data are byte arrays) [this code is for ASCON-128V12]:
private byte[] ascon128v12Encryption(@NonNull byte[] key, @NonNull byte[] nonce, @NonNull byte[] plaintext, byte[] additionalData) {
// sanity checks
if (key.length != 16) {
Log.e(TAG, "the key length has to be 16, found " + key.length);
return new byte[0];
}
if (nonce.length != 16) {
Log.e(TAG, "the nonce length has to be 16, found " + nonce.length);
return new byte[0];
}
int additionalDataLength;
if (additionalData == null) {
additionalDataLength = 0;
} else {
additionalDataLength = additionalData.length;
}
byte[] s = {};
byte[] ciphertext = new byte[plaintext.length + Ascon128v12.CRYPTO_ABYTES];
int clen = Ascon128v12.crypto_aead_encrypt(ciphertext, ciphertext.length, plaintext, plaintext.length, additionalData, additionalDataLength, s, nonce, key);
return ciphertext;
}
Running the decryption is as simple as the encryption — provide the same encryption key and nonce, the ciphertext and (optional) the additional data and receive the decrypted = plaintext:
private byte[] ascon128v12Decryption(@NonNull byte[] key, @NonNull byte[] nonce, @NonNull byte[] ciphertext, byte[] additionalData) {
// sanity checks
if (key.length != 16) {
Log.e(TAG, "the key length has to be 16, found " + key.length);
return new byte[0];
}
if (nonce.length != 16) {
Log.e(TAG, "the nonce length has to be 16, found " + nonce.length);
return new byte[0];
}
int additionalDataLength;
if (additionalData == null) {
additionalDataLength = 0;
} else {
additionalDataLength = additionalData.length;
}
byte[] s = {};
byte[] plaintext = new byte[ciphertext.length + Ascon128v12.CRYPTO_ABYTES];
int plen = Ascon128v12.crypto_aead_decrypt(plaintext, plaintext.length, s, ciphertext, ciphertext.length, additionalData, additionalDataLength, nonce, key);
if (plen != -1) {
return Arrays.copyOfRange(plaintext, 0, plen);
} else {
return new byte[0];
}
}
Please do not forget: if you use additional data on encryption it is mandatory to use the exact same data for decryption !
The complete code for the app is available on my GitHub repository: https://github.com/AndroidCrypto/AsconEncryption.
Have fun with the new algorithm!