1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00

ASCON-128 finalist from the CAESAR competition

This commit is contained in:
Rhys Weatherley
2018-04-27 11:01:29 +10:00
parent 84962a2008
commit 455549f835
8 changed files with 2067 additions and 2 deletions

View File

@@ -0,0 +1,403 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
This example runs tests on the Ascon128 implementation to verify
correct behaviour.
*/
#include <Crypto.h>
#include <CryptoLW.h>
#include <Ascon128.h>
#include "utility/ProgMemUtil.h"
#define MAX_PLAINTEXT_LEN 43
#define MAX_AUTHDATA_LEN 17
struct TestVector
{
const char *name;
uint8_t key[16];
uint8_t plaintext[MAX_PLAINTEXT_LEN];
uint8_t ciphertext[MAX_PLAINTEXT_LEN];
uint8_t authdata[MAX_AUTHDATA_LEN];
uint8_t iv[16];
uint8_t tag[16];
size_t authsize;
size_t datasize;
};
// Test vectors for Ascon128, generated with the reference Python version:
// https://github.com/meichlseder/pyascon
static TestVector const testVectorAscon128_1 PROGMEM = {
.name = "Ascon128 #1",
.key = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.plaintext = {0x61, 0x73, 0x63, 0x6f, 0x6e},
.ciphertext = {0x86, 0x88, 0x62, 0x14, 0x0e},
.authdata = {0x41, 0x53, 0x43, 0x4f, 0x4e},
.iv = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.tag = {0xad, 0x65, 0xf5, 0x94, 0x22, 0x58, 0xda, 0xd5,
0x3c, 0xaa, 0x7a, 0x56, 0xf3, 0xa2, 0x92, 0xd8},
.authsize = 5,
.datasize = 5
};
static TestVector const testVectorAscon128_2 PROGMEM = {
.name = "Ascon128 #2",
.key = {0x0d, 0x49, 0x29, 0x92, 0x65, 0x8b, 0xd8, 0xa3,
0xe4, 0x7b, 0xf9, 0x10, 0xd4, 0xc5, 0x87, 0xad},
.plaintext = {0x61},
.ciphertext = {0xc5},
.authdata = {0},
.iv = {0x5a, 0xcb, 0x17, 0x2a, 0x1a, 0x93, 0x3d, 0xb1,
0x8a, 0x6a, 0x40, 0xac, 0x6e, 0x4c, 0x68, 0xd0},
.tag = {0x2e, 0x0b, 0xf2, 0xb1, 0xfc, 0xd8, 0x64, 0x69,
0x01, 0x1c, 0x4f, 0x8b, 0x78, 0x4a, 0x65, 0x0d},
.authsize = 0,
.datasize = 1
};
static TestVector const testVectorAscon128_3 PROGMEM = {
.name = "Ascon128 #3",
.key = {0x91, 0xb3, 0x9d, 0x22, 0xf3, 0xb7, 0x7f, 0x51,
0x33, 0x0a, 0xa3, 0xa4, 0xea, 0x38, 0xea, 0xa2},
.plaintext = {0},
.ciphertext = {0},
.authdata = {0x64},
.iv = {0x2e, 0xec, 0x64, 0x25, 0xb3, 0xec, 0xf0, 0x63,
0xb4, 0x3e, 0x29, 0xc7, 0x68, 0x29, 0x3c, 0x49},
.tag = {0xfd, 0x24, 0x0e, 0x3c, 0x3d, 0xc4, 0x11, 0x0d,
0xe1, 0x54, 0x4c, 0xd5, 0x24, 0x18, 0xd9, 0x4c},
.authsize = 1,
.datasize = 0
};
static TestVector const testVectorAscon128_4 PROGMEM = {
.name = "Ascon128 #4",
.key = {0x72, 0xfd, 0x18, 0xde, 0xbd, 0xee, 0x86, 0x13,
0x4f, 0x7c, 0x44, 0x29, 0x84, 0x37, 0x56, 0x06},
.plaintext = {0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x78, 0x74},
.ciphertext = {0x91, 0xd0, 0xc3, 0x88, 0xea, 0xc0, 0xe6, 0xd9},
.authdata = {0x61, 0x73, 0x73, 0x64, 0x61, 0x74, 0x31, 0x32},
.iv = {0x91, 0x5f, 0xf8, 0xff, 0xca, 0xd8, 0xae, 0x1d,
0xf4, 0x45, 0xeb, 0x03, 0xe2, 0x18, 0xfd, 0x25},
.tag = {0x16, 0x69, 0x74, 0xbf, 0xbd, 0x43, 0xd7, 0xa8,
0xfe, 0x43, 0xf0, 0xce, 0xe2, 0xdd, 0xb9, 0xf8},
.authsize = 8,
.datasize = 8
};
static TestVector const testVectorAscon128_5 PROGMEM = {
.name = "Ascon128 #5",
.key = {0x8a, 0xa5, 0xed, 0xc5, 0x88, 0x49, 0x75, 0xc8,
0xd1, 0xa1, 0xb8, 0x44, 0xd0, 0x15, 0x50, 0x5a},
.plaintext = {0x54, 0x68, 0x65, 0x20, 0x72, 0x61, 0x69, 0x6e,
0x20, 0x69, 0x6e, 0x20, 0x73, 0x70, 0x61, 0x69,
0x6e, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x73, 0x20,
0x6d, 0x61, 0x69, 0x6e, 0x6c, 0x79, 0x20, 0x6f,
0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x6c,
0x61, 0x69, 0x6e},
.ciphertext = {0x4a, 0xb4, 0xe2, 0x87, 0x90, 0x07, 0x4b, 0x78,
0x88, 0x70, 0x71, 0xc0, 0x62, 0xd6, 0xab, 0x6b,
0x32, 0xd4, 0xb1, 0xec, 0xc7, 0xd8, 0x44, 0x93,
0x36, 0x9a, 0x38, 0x81, 0xd6, 0x65, 0x2f, 0x85,
0xaa, 0xf9, 0x70, 0x90, 0x61, 0x97, 0x3e, 0x1f,
0x60, 0x12, 0x66},
.authdata = {0x48, 0x6f, 0x77, 0x20, 0x6e, 0x6f, 0x77, 0x20,
0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x63, 0x6f,
0x77},
.iv = {0xbc, 0x52, 0x27, 0xa5, 0x72, 0x58, 0xfe, 0x00,
0xcb, 0x7b, 0x0f, 0x31, 0xa4, 0xb6, 0xff, 0xda},
.tag = {0x92, 0xfe, 0x72, 0xf8, 0x69, 0xc9, 0x95, 0x41,
0x1f, 0xc4, 0x57, 0xde, 0xa6, 0xf2, 0xf9, 0x2d},
.authsize = 17,
.datasize = 43
};
TestVector testVector;
Ascon128 acorn;
byte buffer[128];
bool testCipher_N(Ascon128 *cipher, const struct TestVector *test, size_t inc)
{
size_t posn, len;
uint8_t tag[16];
if (!inc)
inc = 1;
cipher->clear();
if (!cipher->setKey(test->key, 16)) {
Serial.print("setKey ");
return false;
}
if (!cipher->setIV(test->iv, 16)) {
Serial.print("setIV ");
return false;
}
memset(buffer, 0xBA, sizeof(buffer));
for (posn = 0; posn < test->authsize; posn += inc) {
len = test->authsize - posn;
if (len > inc)
len = inc;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < test->datasize; posn += inc) {
len = test->datasize - posn;
if (len > inc)
len = inc;
cipher->encrypt(buffer + posn, test->plaintext + posn, len);
}
if (memcmp(buffer, test->ciphertext, test->datasize) != 0) {
Serial.print(buffer[0], HEX);
Serial.print("->");
Serial.print(test->ciphertext[0], HEX);
return false;
}
cipher->computeTag(tag, sizeof(tag));
if (memcmp(tag, test->tag, sizeof(tag)) != 0) {
Serial.print("computed wrong tag ... ");
return false;
}
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
for (posn = 0; posn < test->authsize; posn += inc) {
len = test->authsize - posn;
if (len > inc)
len = inc;
cipher->addAuthData(test->authdata + posn, len);
}
for (posn = 0; posn < test->datasize; posn += inc) {
len = test->datasize - posn;
if (len > inc)
len = inc;
cipher->decrypt(buffer + posn, test->ciphertext + posn, len);
}
if (memcmp(buffer, test->plaintext, test->datasize) != 0)
return false;
if (!cipher->checkTag(tag, sizeof(tag))) {
Serial.print("tag did not check ... ");
return false;
}
return true;
}
void testCipher(Ascon128 *cipher, const struct TestVector *test)
{
bool ok;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" ... ");
ok = testCipher_N(cipher, test, test->datasize);
ok &= testCipher_N(cipher, test, 1);
ok &= testCipher_N(cipher, test, 2);
ok &= testCipher_N(cipher, test, 5);
ok &= testCipher_N(cipher, test, 8);
ok &= testCipher_N(cipher, test, 13);
ok &= testCipher_N(cipher, test, 16);
if (ok)
Serial.println("Passed");
else
Serial.println("Failed");
}
void perfCipherSetKey(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" SetKey ... ");
start = micros();
for (count = 0; count < 1000; ++count) {
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
}
elapsed = micros() - start;
Serial.print(elapsed / 1000.0);
Serial.print("us per operation, ");
Serial.print((1000.0 * 1000000.0) / elapsed);
Serial.println(" per second");
}
void perfCipherEncrypt(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" Encrypt ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
for (count = 0; count < 500; ++count) {
cipher->encrypt(buffer, buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void perfCipherDecrypt(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" Decrypt ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
for (count = 0; count < 500; ++count) {
cipher->decrypt(buffer, buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void perfCipherAddAuthData(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" AddAuthData ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
memset(buffer, 0xBA, 128);
for (count = 0; count < 500; ++count) {
cipher->addAuthData(buffer, 128);
}
elapsed = micros() - start;
Serial.print(elapsed / (128.0 * 500.0));
Serial.print("us per byte, ");
Serial.print((128.0 * 500.0 * 1000000.0) / elapsed);
Serial.println(" bytes per second");
}
void perfCipherComputeTag(Ascon128 *cipher, const struct TestVector *test)
{
unsigned long start;
unsigned long elapsed;
int count;
memcpy_P(&testVector, test, sizeof(TestVector));
test = &testVector;
Serial.print(test->name);
Serial.print(" ComputeTag ... ");
cipher->setKey(test->key, 16);
cipher->setIV(test->iv, 16);
start = micros();
for (count = 0; count < 1000; ++count) {
cipher->computeTag(buffer, 16);
}
elapsed = micros() - start;
Serial.print(elapsed / 1000.0);
Serial.print("us per operation, ");
Serial.print((1000.0 * 1000000.0) / elapsed);
Serial.println(" per second");
}
void perfCipher(Ascon128 *cipher, const struct TestVector *test)
{
perfCipherSetKey(cipher, test);
perfCipherEncrypt(cipher, test);
perfCipherDecrypt(cipher, test);
perfCipherAddAuthData(cipher, test);
perfCipherComputeTag(cipher, test);
}
void setup()
{
Serial.begin(9600);
Serial.println();
Serial.print("State Size ... ");
Serial.println(sizeof(Ascon128));
Serial.println();
Serial.println("Test Vectors:");
testCipher(&acorn, &testVectorAscon128_1);
testCipher(&acorn, &testVectorAscon128_2);
testCipher(&acorn, &testVectorAscon128_3);
testCipher(&acorn, &testVectorAscon128_4);
testCipher(&acorn, &testVectorAscon128_5);
Serial.println();
Serial.println("Performance Tests:");
perfCipher(&acorn, &testVectorAscon128_4);
}
void loop()
{
}

View File

@@ -0,0 +1,356 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "Ascon128.h"
#include "Crypto.h"
#include "utility/EndianUtil.h"
#include "utility/RotateUtil.h"
#include "utility/ProgMemUtil.h"
#include <string.h>
/**
* \class Ascon128 Ascon128.h <Ascon128.h>
* \brief ASCON-128 authenticated cipher.
*
* Ascon128 is an authenticated cipher designed for memory-limited
* environments with a 128-bit key, a 128-bit initialization vector,
* and a 128-bit authentication tag. It was one of the finalists
* in the CAESAR AEAD competition.
*
* References: http://competitions.cr.yp.to/round3/asconv12.pdf,
* http://ascon.iaik.tugraz.at/
*
* \sa AuthenticatedCipher
*/
/**
* \brief Constructs a new Ascon128 authenticated cipher.
*/
Ascon128::Ascon128()
#if defined(CRYPTO_LITTLE_ENDIAN)
: posn(7)
, authMode(1)
#else
: posn(0)
, authMode(1)
#endif
{
}
/**
* \brief Destroys this Ascon128 authenticated cipher.
*/
Ascon128::~Ascon128()
{
clean(state);
}
/**
* \brief Gets the size of the Ascon128 key in bytes.
*
* \return Always returns 16, indicating a 128-bit key.
*/
size_t Ascon128::keySize() const
{
return 16;
}
/**
* \brief Gets the size of the Ascon128 initialization vector in bytes.
*
* \return Always returns 16, indicating a 128-bit IV.
*
* Authentication tags may be truncated to 8 bytes, but the algorithm authors
* recommend using a full 16-byte tag.
*/
size_t Ascon128::ivSize() const
{
return 16;
}
/**
* \brief Gets the size of the Ascon128 authentication tag in bytes.
*
* \return Always returns 16, indicating a 128-bit authentication tag.
*/
size_t Ascon128::tagSize() const
{
return 16;
}
bool Ascon128::setKey(const uint8_t *key, size_t len)
{
if (len != 16)
return false;
memcpy(state.K, key, 16);
#if defined(CRYPTO_LITTLE_ENDIAN)
state.K[0] = be64toh(state.K[0]);
state.K[1] = be64toh(state.K[1]);
#endif
return true;
}
bool Ascon128::setIV(const uint8_t *iv, size_t len)
{
// Validate the length of the IV.
if (len != 16)
return false;
// Set up the initial state.
state.S[0] = 0x80400C0600000000ULL;
state.S[1] = state.K[0];
state.S[2] = state.K[1];
memcpy(state.S + 3, iv, 16);
#if defined(CRYPTO_LITTLE_ENDIAN)
state.S[3] = be64toh(state.S[3]);
state.S[4] = be64toh(state.S[4]);
posn = 7;
authMode = 1;
#else
posn = 0;
authMode = 1;
#endif
// Permute the state with 12 rounds starting at round 0.
permute(0);
// XOR the end of the state with the original key.
state.S[3] ^= state.K[0];
state.S[4] ^= state.K[1];
return true;
}
void Ascon128::encrypt(uint8_t *output, const uint8_t *input, size_t len)
{
if (authMode)
endAuth();
const uint8_t *in = (const uint8_t *)input;
uint8_t *out = (uint8_t *)output;
while (len > 0) {
// Encrypt the next byte using the first 64-bit word in the state.
((uint8_t *)(state.S))[posn] ^= *in++;
*out++ = ((const uint8_t *)(state.S))[posn];
--len;
// Permute the state for b = 6 rounds at the end of each block.
#if defined(CRYPTO_LITTLE_ENDIAN)
if (posn > 0) {
--posn;
} else {
permute(6);
posn = 7;
}
#else
if ((++posn) == 8) {
permute(6);
posn = 0;
}
#endif
}
}
void Ascon128::decrypt(uint8_t *output, const uint8_t *input, size_t len)
{
if (authMode)
endAuth();
const uint8_t *in = (const uint8_t *)input;
uint8_t *out = (uint8_t *)output;
while (len > 0) {
// Decrypt the next byte using the first 64-bit word in the state.
*out++ = ((const uint8_t *)(state.S))[posn] ^ *in;
((uint8_t *)(state.S))[posn] = *in++;
--len;
// Permute the state for b = 6 rounds at the end of each block.
#if defined(CRYPTO_LITTLE_ENDIAN)
if (posn > 0) {
--posn;
} else {
permute(6);
posn = 7;
}
#else
if ((++posn) == 8) {
permute(6);
posn = 0;
}
#endif
}
}
void Ascon128::addAuthData(const void *data, size_t len)
{
if (!authMode)
return;
const uint8_t *in = (const uint8_t *)data;
while (len > 0) {
// Incorporate the next byte of auth data into the internal state.
((uint8_t *)(state.S))[posn] ^= *in++;
--len;
// Permute the state for b = 6 rounds at the end of each block.
#if defined(CRYPTO_LITTLE_ENDIAN)
if (posn > 0) {
--posn;
} else {
permute(6);
posn = 7;
}
#else
if ((++posn) == 8) {
permute(6);
posn = 0;
}
#endif
}
authMode = 2; // We have some auth data now.
}
void Ascon128::computeTag(void *tag, size_t len)
{
// End authentication mode if there was no plaintext/ciphertext.
if (authMode)
endAuth();
// Pad the last block, add the original key, and permute the state.
((uint8_t *)(state.S))[posn] ^= 0x80;
state.S[1] ^= state.K[0];
state.S[2] ^= state.K[1];
permute(0);
// Compute the tag and convert it into big-endian in the return buffer.
uint64_t T[2];
T[0] = htobe64(state.S[3] ^ state.K[0]);
T[1] = htobe64(state.S[4] ^ state.K[1]);
if (len > 16)
len = 16;
memcpy(tag, T, len);
clean(T);
}
bool Ascon128::checkTag(const void *tag, size_t len)
{
// The tag can never match if it is larger than the maximum allowed size.
if (len > 16)
return false;
// End authentication mode if there was no plaintext/ciphertext.
if (authMode)
endAuth();
// Pad the last block, add the original key, and permute the state.
((uint8_t *)(state.S))[posn] ^= 0x80;
state.S[1] ^= state.K[0];
state.S[2] ^= state.K[1];
permute(0);
// Compute the tag and convert it into big-endian.
uint64_t T[2];
T[0] = htobe64(state.S[3] ^ state.K[0]);
T[1] = htobe64(state.S[4] ^ state.K[1]);
if (len > 16)
len = 16;
bool ok = secure_compare(T, tag, len);
clean(T);
return ok;
}
/**
* \brief Clears all security-sensitive state from this cipher object.
*/
void Ascon128::clear()
{
clean(state);
#if defined(CRYPTO_LITTLE_ENDIAN)
posn = 7;
authMode = 1;
#else
posn = 0;
authMode = 1;
#endif
}
#if !defined(__AVR__) || defined(CRYPTO_DOC)
/**
* \brief Permutes the Ascon128 state.
*
* \param first The first round start permuting at, between 0 and 11.
*/
void Ascon128::permute(uint8_t first)
{
uint64_t t0, t1, t2, t3, t4;
#define x0 state.S[0]
#define x1 state.S[1]
#define x2 state.S[2]
#define x3 state.S[3]
#define x4 state.S[4]
while (first < 12) {
// Add the round constant to the state.
x2 ^= ((0x0F - first) << 4) | first;
// Substitution layer - apply the s-box using bit-slicing
// according to the algorithm recommended in the specification.
x0 ^= x4; x4 ^= x3; x2 ^= x1;
t0 = ~x0; t1 = ~x1; t2 = ~x2; t3 = ~x3; t4 = ~x4;
t0 &= x1; t1 &= x2; t2 &= x3; t3 &= x4; t4 &= x0;
x0 ^= t1; x1 ^= t2; x2 ^= t3; x3 ^= t4; x4 ^= t0;
x1 ^= x0; x0 ^= x4; x3 ^= x2; x2 = ~x2;
// Linear diffusion layer.
x0 ^= rightRotate19_64(x0) ^ rightRotate28_64(x0);
x1 ^= rightRotate61_64(x1) ^ rightRotate39_64(x1);
x2 ^= rightRotate1_64(x2) ^ rightRotate6_64(x2);
x3 ^= rightRotate10_64(x3) ^ rightRotate17_64(x3);
x4 ^= rightRotate7_64(x4) ^ rightRotate41_64(x4);
// Move onto the next round.
++first;
}
#undef x0
#undef x1
#undef x2
#undef x3
#undef x4
}
#endif // !__AVR__
/**
* \brief Ends authenticating the associated data and moves onto encryption.
*/
void Ascon128::endAuth()
{
if (authMode == 2) {
// We had some auth data, so we need to pad and permute the last block.
// There is no need to do this if there were zero bytes of auth data.
((uint8_t *)(state.S))[posn] ^= 0x80;
permute(6);
}
state.S[4] ^= 1; // Domain separation between auth data and payload data.
authMode = 0;
#if defined(CRYPTO_LITTLE_ENDIAN)
posn = 7;
#else
posn = 0;
#endif
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef CRYPTO_ASCON128_H
#define CRYPTO_ASCON128_H
#include "AuthenticatedCipher.h"
class Ascon128 : public AuthenticatedCipher
{
public:
Ascon128();
virtual ~Ascon128();
size_t keySize() const;
size_t ivSize() const;
size_t tagSize() const;
bool setKey(const uint8_t *key, size_t len);
bool setIV(const uint8_t *iv, size_t len);
void encrypt(uint8_t *output, const uint8_t *input, size_t len);
void decrypt(uint8_t *output, const uint8_t *input, size_t len);
void addAuthData(const void *data, size_t len);
void computeTag(void *tag, size_t len);
bool checkTag(const void *tag, size_t len);
void clear();
private:
struct {
uint64_t K[2];
uint64_t S[5];
} state;
uint8_t posn;
uint8_t authMode;
void permute(uint8_t first);
void endAuth();
};
#endif

View File

@@ -0,0 +1,718 @@
/*
* Copyright (C) 2018 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "Ascon128.h"
#if defined(__AVR__)
void Ascon128::permute(uint8_t first)
{
// AVR version generated by the genascon tool.
__asm__ __volatile__ (
"1:\n"
"ldd r15,Z+16\n"
"eor r15,%1\n"
"ld r14,Z\n"
"ldd r13,Z+8\n"
"ldd r12,Z+24\n"
"ldd r11,Z+32\n"
"eor r14,r11\n"
"eor r11,r12\n"
"eor r15,r13\n"
"mov r10,r14\n"
"com r10\n"
"and r10,r13\n"
"mov r9,r13\n"
"com r9\n"
"and r9,r15\n"
"mov r8,r15\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r14\n"
"eor r14,r9\n"
"eor r13,r8\n"
"eor r15,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r13,r14\n"
"eor r14,r11\n"
"eor r12,r15\n"
"com r15\n"
"st Z,r14\n"
"std Z+8,r13\n"
"std Z+16,r15\n"
"std Z+24,r12\n"
"std Z+32,r11\n"
"ldd r15,Z+1\n"
"ldd r14,Z+9\n"
"ldd r13,Z+17\n"
"ldd r12,Z+25\n"
"ldd r11,Z+33\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+1,r15\n"
"std Z+9,r14\n"
"std Z+17,r13\n"
"std Z+25,r12\n"
"std Z+33,r11\n"
"ldd r15,Z+2\n"
"ldd r14,Z+10\n"
"ldd r13,Z+18\n"
"ldd r12,Z+26\n"
"ldd r11,Z+34\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+2,r15\n"
"std Z+10,r14\n"
"std Z+18,r13\n"
"std Z+26,r12\n"
"std Z+34,r11\n"
"ldd r15,Z+3\n"
"ldd r14,Z+11\n"
"ldd r13,Z+19\n"
"ldd r12,Z+27\n"
"ldd r11,Z+35\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+3,r15\n"
"std Z+11,r14\n"
"std Z+19,r13\n"
"std Z+27,r12\n"
"std Z+35,r11\n"
"ldd r15,Z+4\n"
"ldd r14,Z+12\n"
"ldd r13,Z+20\n"
"ldd r12,Z+28\n"
"ldd r11,Z+36\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+4,r15\n"
"std Z+12,r14\n"
"std Z+20,r13\n"
"std Z+28,r12\n"
"std Z+36,r11\n"
"ldd r15,Z+5\n"
"ldd r14,Z+13\n"
"ldd r13,Z+21\n"
"ldd r12,Z+29\n"
"ldd r11,Z+37\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+5,r15\n"
"std Z+13,r14\n"
"std Z+21,r13\n"
"std Z+29,r12\n"
"std Z+37,r11\n"
"ldd r15,Z+6\n"
"ldd r14,Z+14\n"
"ldd r13,Z+22\n"
"ldd r12,Z+30\n"
"ldd r11,Z+38\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+6,r15\n"
"std Z+14,r14\n"
"std Z+22,r13\n"
"std Z+30,r12\n"
"std Z+38,r11\n"
"ldd r15,Z+7\n"
"ldd r14,Z+15\n"
"ldd r13,Z+23\n"
"ldd r12,Z+31\n"
"ldd r11,Z+39\n"
"eor r15,r11\n"
"eor r11,r12\n"
"eor r13,r14\n"
"mov r10,r15\n"
"com r10\n"
"and r10,r14\n"
"mov r9,r14\n"
"com r9\n"
"and r9,r13\n"
"mov r8,r13\n"
"com r8\n"
"and r8,r12\n"
"mov r7,r12\n"
"com r7\n"
"and r7,r11\n"
"mov r23,r11\n"
"com r23\n"
"and r23,r15\n"
"eor r15,r9\n"
"eor r14,r8\n"
"eor r13,r7\n"
"eor r12,r23\n"
"eor r11,r10\n"
"eor r14,r15\n"
"eor r15,r11\n"
"eor r12,r13\n"
"com r13\n"
"std Z+7,r15\n"
"std Z+15,r14\n"
"std Z+23,r13\n"
"std Z+31,r12\n"
"std Z+39,r11\n"
"ld r15,Z\n"
"ldd r14,Z+1\n"
"ldd r13,Z+2\n"
"ldd r12,Z+3\n"
"ldd r11,Z+4\n"
"ldd r10,Z+5\n"
"ldd r9,Z+6\n"
"ldd r8,Z+7\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"bst r22,0\n"
"ror r23\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"bld r23,7\n"
"bst r22,0\n"
"ror r23\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"bld r23,7\n"
"bst r22,0\n"
"ror r23\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"bld r23,7\n"
"eor r22,r15\n"
"eor r21,r14\n"
"eor r20,r13\n"
"eor r19,r12\n"
"eor r18,r11\n"
"eor r17,r10\n"
"eor r7,r9\n"
"eor r23,r8\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"lsl r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"adc r11,__zero_reg__\n"
"eor r11,r22\n"
"eor r10,r21\n"
"eor r9,r20\n"
"eor r8,r19\n"
"eor r15,r18\n"
"eor r14,r17\n"
"eor r13,r7\n"
"eor r12,r23\n"
"st Z,r11\n"
"std Z+1,r10\n"
"std Z+2,r9\n"
"std Z+3,r8\n"
"std Z+4,r15\n"
"std Z+5,r14\n"
"std Z+6,r13\n"
"std Z+7,r12\n"
"ldd r15,Z+8\n"
"ldd r14,Z+9\n"
"ldd r13,Z+10\n"
"ldd r12,Z+11\n"
"ldd r11,Z+12\n"
"ldd r10,Z+13\n"
"ldd r9,Z+14\n"
"ldd r8,Z+15\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"lsl r7\n"
"rol r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"adc r7,__zero_reg__\n"
"lsl r7\n"
"rol r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"adc r7,__zero_reg__\n"
"lsl r7\n"
"rol r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"adc r7,__zero_reg__\n"
"eor r7,r15\n"
"eor r23,r14\n"
"eor r22,r13\n"
"eor r21,r12\n"
"eor r20,r11\n"
"eor r19,r10\n"
"eor r18,r9\n"
"eor r17,r8\n"
"lsl r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"rol r14\n"
"rol r13\n"
"rol r12\n"
"rol r11\n"
"adc r10,__zero_reg__\n"
"eor r10,r7\n"
"eor r9,r23\n"
"eor r8,r22\n"
"eor r15,r21\n"
"eor r14,r20\n"
"eor r13,r19\n"
"eor r12,r18\n"
"eor r11,r17\n"
"std Z+8,r10\n"
"std Z+9,r9\n"
"std Z+10,r8\n"
"std Z+11,r15\n"
"std Z+12,r14\n"
"std Z+13,r13\n"
"std Z+14,r12\n"
"std Z+15,r11\n"
"ldd r15,Z+16\n"
"ldd r14,Z+17\n"
"ldd r13,Z+18\n"
"ldd r12,Z+19\n"
"ldd r11,Z+20\n"
"ldd r10,Z+21\n"
"ldd r9,Z+22\n"
"ldd r8,Z+23\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"bst r7,0\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"ror r23\n"
"ror r7\n"
"bld r17,7\n"
"eor r7,r15\n"
"eor r23,r14\n"
"eor r22,r13\n"
"eor r21,r12\n"
"eor r20,r11\n"
"eor r19,r10\n"
"eor r18,r9\n"
"eor r17,r8\n"
"lsl r14\n"
"rol r13\n"
"rol r12\n"
"rol r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"adc r14,__zero_reg__\n"
"lsl r14\n"
"rol r13\n"
"rol r12\n"
"rol r11\n"
"rol r10\n"
"rol r9\n"
"rol r8\n"
"rol r15\n"
"adc r14,__zero_reg__\n"
"eor r14,r7\n"
"eor r13,r23\n"
"eor r12,r22\n"
"eor r11,r21\n"
"eor r10,r20\n"
"eor r9,r19\n"
"eor r8,r18\n"
"eor r15,r17\n"
"std Z+16,r14\n"
"std Z+17,r13\n"
"std Z+18,r12\n"
"std Z+19,r11\n"
"std Z+20,r10\n"
"std Z+21,r9\n"
"std Z+22,r8\n"
"std Z+23,r15\n"
"ldd r15,Z+24\n"
"ldd r14,Z+25\n"
"ldd r13,Z+26\n"
"ldd r12,Z+27\n"
"ldd r11,Z+28\n"
"ldd r10,Z+29\n"
"ldd r9,Z+30\n"
"ldd r8,Z+31\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"bst r23,0\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"ror r23\n"
"bld r7,7\n"
"bst r23,0\n"
"ror r7\n"
"ror r17\n"
"ror r18\n"
"ror r19\n"
"ror r20\n"
"ror r21\n"
"ror r22\n"
"ror r23\n"
"bld r7,7\n"
"eor r23,r15\n"
"eor r22,r14\n"
"eor r21,r13\n"
"eor r20,r12\n"
"eor r19,r11\n"
"eor r18,r10\n"
"eor r17,r9\n"
"eor r7,r8\n"
"bst r13,0\n"
"ror r14\n"
"ror r15\n"
"ror r8\n"
"ror r9\n"
"ror r10\n"
"ror r11\n"
"ror r12\n"
"ror r13\n"
"bld r14,7\n"
"eor r13,r23\n"
"eor r12,r22\n"
"eor r11,r21\n"
"eor r10,r20\n"
"eor r9,r19\n"
"eor r8,r18\n"
"eor r15,r17\n"
"eor r14,r7\n"
"std Z+24,r13\n"
"std Z+25,r12\n"
"std Z+26,r11\n"
"std Z+27,r10\n"
"std Z+28,r9\n"
"std Z+29,r8\n"
"std Z+30,r15\n"
"std Z+31,r14\n"
"ldd r15,Z+32\n"
"ldd r14,Z+33\n"
"ldd r13,Z+34\n"
"ldd r12,Z+35\n"
"ldd r11,Z+36\n"
"ldd r10,Z+37\n"
"ldd r9,Z+38\n"
"ldd r8,Z+39\n"
"mov r7,r15\n"
"mov r23,r14\n"
"mov r22,r13\n"
"mov r21,r12\n"
"mov r20,r11\n"
"mov r19,r10\n"
"mov r18,r9\n"
"mov r17,r8\n"
"lsl r23\n"
"rol r22\n"
"rol r21\n"
"rol r20\n"
"rol r19\n"
"rol r18\n"
"rol r17\n"
"rol r7\n"
"adc r23,__zero_reg__\n"
"eor r23,r15\n"
"eor r22,r14\n"
"eor r21,r13\n"
"eor r20,r12\n"
"eor r19,r11\n"
"eor r18,r10\n"
"eor r17,r9\n"
"eor r7,r8\n"
"bst r10,0\n"
"ror r11\n"
"ror r12\n"
"ror r13\n"
"ror r14\n"
"ror r15\n"
"ror r8\n"
"ror r9\n"
"ror r10\n"
"bld r11,7\n"
"eor r10,r23\n"
"eor r9,r22\n"
"eor r8,r21\n"
"eor r15,r20\n"
"eor r14,r19\n"
"eor r13,r18\n"
"eor r12,r17\n"
"eor r11,r7\n"
"std Z+32,r10\n"
"std Z+33,r9\n"
"std Z+34,r8\n"
"std Z+35,r15\n"
"std Z+36,r14\n"
"std Z+37,r13\n"
"std Z+38,r12\n"
"std Z+39,r11\n"
"subi %1,0x0F\n"
"cpi %1,0x3C\n"
"breq 2f\n"
"rjmp 1b\n"
"2:\n"
:: "z"(state.S), "d"((uint8_t)(0xF0 - (first << 4) + first))
: "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "memory"
);
}
#endif // __AVR__