From 5ecb20e13934d0dc670ef8341279e8b9f40819a7 Mon Sep 17 00:00:00 2001 From: Arne Deprez Date: Mon, 28 Sep 2020 18:20:04 +0000 Subject: [PATCH] forkae --- forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.c | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.c | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.c | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.c | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.c | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.c | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.c | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/api.h | 5 +++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.c | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/api.h | 5 +++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.c | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/api.h | 5 +++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.c | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/api.h | 5 +++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.c | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.h | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/api.h | 5 +++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/encrypt.c | 26 ++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.h | 551 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-paef.h | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-saef.h | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.c | 1052 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-skinnyutil.h | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-util.h | 702 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 144 files changed, 45240 insertions(+) create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/api.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/api.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/api.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/api.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-util.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/api.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/encrypt.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-paef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-saef.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.c create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-skinnyutil.h create mode 100644 forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-util.h diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/api.h new file mode 100644 index 0000000..3818b25 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 6 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/encrypt.c new file mode 100644 index 0000000..36835c1 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_192_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_192_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.c new file mode 100644 index 0000000..c43ef98 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.c @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = { + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, + 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, + 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, + 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, + 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, + 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, + 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, + 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, + 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b, + 0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, + 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10 +}; + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + + +} forkskinny_128_256_key_schedule_t; + +static void forkskinny_128_256_init_tks(forkskinny_128_256_key_schedule_t *ks, const unsigned char key[32], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + } + else{ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + FORKSKINNY_128_256_ROUNDS_AFTER); + } + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_inv_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + //uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + + +} forkskinny_128_384_key_schedule_t; + +static void forkskinny_128_384_init_tks(forkskinny_128_384_key_schedule_t *ks, const unsigned char key[48], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = le_load_word32(key + 32); + TK[1] = le_load_word32(key + 36); + TK[2] = le_load_word32(key + 40); + TK[3] = le_load_word32(key + 44); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR3(TK[0]); + skinny128_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + } + else{ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_inv_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + //uint16_t TK1[4]; /**< First part of the tweakey */ + //uint16_t TK2[4]; /**< Second part of the tweakey */ + //uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint16_t row0[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + uint16_t row1[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + + +} forkskinny_64_192_key_schedule_t; + +static void forkskinny_64_192_init_tks(forkskinny_64_192_key_schedule_t *ks, const unsigned char key[24], uint8_t nb_rounds){ + uint16_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = be_load_word16(key); + TK[1] = be_load_word16(key + 2); + TK[2] = be_load_word16(key + 4); + TK[3] = be_load_word16(key + 6); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny64_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = be_load_word16(key + 8); + TK[1] = be_load_word16(key + 10); + TK[2] = be_load_word16(key + 12); + TK[3] = be_load_word16(key + 14); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR2(TK[0]); + skinny64_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = be_load_word16(key + 16); + TK[1] = be_load_word16(key + 18); + TK[2] = be_load_word16(key + 20); + TK[3] = be_load_word16(key + 22); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR3(TK[0]); + skinny64_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + } + else{ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + FORKSKINNY_64_192_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, &ks, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_dec/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/api.h new file mode 100644 index 0000000..3818b25 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 6 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/encrypt.c new file mode 100644 index 0000000..36835c1 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_192_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_192_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.c new file mode 100644 index 0000000..af29f77 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" +#include + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b,0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10}; + +static const uint32_t T[256] = {0x65656565, 0x4c4c4c4c, 0x6a6a6a6a, 0x42424242, 0x4b4b4b4b, 0x63636363, 0x43434343, 0x6b6b6b6b, 0x55555555, 0x75757575, 0x5a5a5a5a, 0x7a7a7a7a, 0x53535353, 0x73737373, 0x5b5b5b5b, 0x7b7b7b7b, 0x35353535, 0x8c8c8c8c, 0x3a3a3a3a, 0x81818181, 0x89898989, 0x33333333, 0x80808080, 0x3b3b3b3b, 0x95959595, 0x25252525, 0x98989898, 0x2a2a2a2a, 0x90909090, 0x23232323, 0x99999999, 0x2b2b2b2b, 0xe5e5e5e5, 0xcccccccc, 0xe8e8e8e8, 0xc1c1c1c1, 0xc9c9c9c9, 0xe0e0e0e0, 0xc0c0c0c0, 0xe9e9e9e9, 0xd5d5d5d5, 0xf5f5f5f5, 0xd8d8d8d8, 0xf8f8f8f8, 0xd0d0d0d0, 0xf0f0f0f0, 0xd9d9d9d9, 0xf9f9f9f9, 0xa5a5a5a5, 0x1c1c1c1c, 0xa8a8a8a8, 0x12121212, 0x1b1b1b1b, 0xa0a0a0a0, 0x13131313, 0xa9a9a9a9, 0x05050505, 0xb5b5b5b5, 0x0a0a0a0a, 0xb8b8b8b8, 0x03030303, 0xb0b0b0b0, 0x0b0b0b0b, 0xb9b9b9b9, 0x32323232, 0x88888888, 0x3c3c3c3c, 0x85858585, 0x8d8d8d8d, 0x34343434, 0x84848484, 0x3d3d3d3d, 0x91919191, 0x22222222, 0x9c9c9c9c, 0x2c2c2c2c, 0x94949494, 0x24242424, 0x9d9d9d9d, 0x2d2d2d2d, 0x62626262, 0x4a4a4a4a, 0x6c6c6c6c, 0x45454545, 0x4d4d4d4d, 0x64646464, 0x44444444, 0x6d6d6d6d, 0x52525252, 0x72727272, 0x5c5c5c5c, 0x7c7c7c7c, 0x54545454, 0x74747474, 0x5d5d5d5d, 0x7d7d7d7d, 0xa1a1a1a1, 0x1a1a1a1a, 0xacacacac, 0x15151515, 0x1d1d1d1d, 0xa4a4a4a4, 0x14141414, 0xadadadad, 0x02020202, 0xb1b1b1b1, 0x0c0c0c0c, 0xbcbcbcbc, 0x04040404, 0xb4b4b4b4, 0x0d0d0d0d, 0xbdbdbdbd, 0xe1e1e1e1, 0xc8c8c8c8, 0xecececec, 0xc5c5c5c5, 0xcdcdcdcd, 0xe4e4e4e4, 0xc4c4c4c4, 0xedededed, 0xd1d1d1d1, 0xf1f1f1f1, 0xdcdcdcdc, 0xfcfcfcfc, 0xd4d4d4d4, 0xf4f4f4f4, 0xdddddddd, 0xfdfdfdfd, 0x36363636, 0x8e8e8e8e, 0x38383838, 0x82828282, 0x8b8b8b8b, 0x30303030, 0x83838383, 0x39393939, 0x96969696, 0x26262626, 0x9a9a9a9a, 0x28282828, 0x93939393, 0x20202020, 0x9b9b9b9b, 0x29292929, 0x66666666, 0x4e4e4e4e, 0x68686868, 0x41414141, 0x49494949, 0x60606060, 0x40404040, 0x69696969, 0x56565656, 0x76767676, 0x58585858, 0x78787878, 0x50505050, 0x70707070, 0x59595959, 0x79797979, 0xa6a6a6a6, 0x1e1e1e1e, 0xaaaaaaaa, 0x11111111, 0x19191919, 0xa3a3a3a3, 0x10101010, 0xabababab, 0x06060606, 0xb6b6b6b6, 0x08080808, 0xbabababa, 0x00000000, 0xb3b3b3b3, 0x09090909, 0xbbbbbbbb, 0xe6e6e6e6, 0xcececece, 0xeaeaeaea, 0xc2c2c2c2, 0xcbcbcbcb, 0xe3e3e3e3, 0xc3c3c3c3, 0xebebebeb, 0xd6d6d6d6, 0xf6f6f6f6, 0xdadadada, 0xfafafafa, 0xd3d3d3d3, 0xf3f3f3f3, 0xdbdbdbdb, 0xfbfbfbfb, 0x31313131, 0x8a8a8a8a, 0x3e3e3e3e, 0x86868686, 0x8f8f8f8f, 0x37373737, 0x87878787, 0x3f3f3f3f, 0x92929292, 0x21212121, 0x9e9e9e9e, 0x2e2e2e2e, 0x97979797, 0x27272727, 0x9f9f9f9f, 0x2f2f2f2f, 0x61616161, 0x48484848, 0x6e6e6e6e, 0x46464646, 0x4f4f4f4f, 0x67676767, 0x47474747, 0x6f6f6f6f, 0x51515151, 0x71717171, 0x5e5e5e5e, 0x7e7e7e7e, 0x57575757, 0x77777777, 0x5f5f5f5f, 0x7f7f7f7f, 0xa2a2a2a2, 0x18181818, 0xaeaeaeae, 0x16161616, 0x1f1f1f1f, 0xa7a7a7a7, 0x17171717, 0xafafafaf, 0x01010101, 0xb2b2b2b2, 0x0e0e0e0e, 0xbebebebe, 0x07070707, 0xb7b7b7b7, 0x0f0f0f0f, 0xbfbfbfbf, 0xe2e2e2e2, 0xcacacaca, 0xeeeeeeee, 0xc6c6c6c6, 0xcfcfcfcf, 0xe7e7e7e7, 0xc7c7c7c7, 0xefefefef, 0xd2d2d2d2, 0xf2f2f2f2, 0xdededede, 0xfefefefe, 0xd7d7d7d7, 0xf7f7f7f7, 0xdfdfdfdf, 0xffffffff}; +static const uint32_t T_inv[256] = {0xacacacac, 0xe8e8e8e8, 0x68686868, 0x3c3c3c3c, 0x6c6c6c6c, 0x38383838, 0xa8a8a8a8, 0xecececec, 0xaaaaaaaa, 0xaeaeaeae, 0x3a3a3a3a, 0x3e3e3e3e, 0x6a6a6a6a, 0x6e6e6e6e, 0xeaeaeaea, 0xeeeeeeee, 0xa6a6a6a6, 0xa3a3a3a3, 0x33333333, 0x36363636, 0x66666666, 0x63636363, 0xe3e3e3e3, 0xe6e6e6e6, 0xe1e1e1e1, 0xa4a4a4a4, 0x61616161, 0x34343434, 0x31313131, 0x64646464, 0xa1a1a1a1, 0xe4e4e4e4, 0x8d8d8d8d, 0xc9c9c9c9, 0x49494949, 0x1d1d1d1d, 0x4d4d4d4d, 0x19191919, 0x89898989, 0xcdcdcdcd, 0x8b8b8b8b, 0x8f8f8f8f, 0x1b1b1b1b, 0x1f1f1f1f, 0x4b4b4b4b, 0x4f4f4f4f, 0xcbcbcbcb, 0xcfcfcfcf, 0x85858585, 0xc0c0c0c0, 0x40404040, 0x15151515, 0x45454545, 0x10101010, 0x80808080, 0xc5c5c5c5, 0x82828282, 0x87878787, 0x12121212, 0x17171717, 0x42424242, 0x47474747, 0xc2c2c2c2, 0xc7c7c7c7, 0x96969696, 0x93939393, 0x03030303, 0x06060606, 0x56565656, 0x53535353, 0xd3d3d3d3, 0xd6d6d6d6, 0xd1d1d1d1, 0x94949494, 0x51515151, 0x04040404, 0x01010101, 0x54545454, 0x91919191, 0xd4d4d4d4, 0x9c9c9c9c, 0xd8d8d8d8, 0x58585858, 0x0c0c0c0c, 0x5c5c5c5c, 0x08080808, 0x98989898, 0xdcdcdcdc, 0x9a9a9a9a, 0x9e9e9e9e, 0x0a0a0a0a, 0x0e0e0e0e, 0x5a5a5a5a, 0x5e5e5e5e, 0xdadadada, 0xdededede, 0x95959595, 0xd0d0d0d0, 0x50505050, 0x05050505, 0x55555555, 0x00000000, 0x90909090, 0xd5d5d5d5, 0x92929292, 0x97979797, 0x02020202, 0x07070707, 0x52525252, 0x57575757, 0xd2d2d2d2, 0xd7d7d7d7, 0x9d9d9d9d, 0xd9d9d9d9, 0x59595959, 0x0d0d0d0d, 0x5d5d5d5d, 0x09090909, 0x99999999, 0xdddddddd, 0x9b9b9b9b, 0x9f9f9f9f, 0x0b0b0b0b, 0x0f0f0f0f, 0x5b5b5b5b, 0x5f5f5f5f, 0xdbdbdbdb, 0xdfdfdfdf, 0x16161616, 0x13131313, 0x83838383, 0x86868686, 0x46464646, 0x43434343, 0xc3c3c3c3, 0xc6c6c6c6, 0x41414141, 0x14141414, 0xc1c1c1c1, 0x84848484, 0x11111111, 0x44444444, 0x81818181, 0xc4c4c4c4, 0x1c1c1c1c, 0x48484848, 0xc8c8c8c8, 0x8c8c8c8c, 0x4c4c4c4c, 0x18181818, 0x88888888, 0xcccccccc, 0x1a1a1a1a, 0x1e1e1e1e, 0x8a8a8a8a, 0x8e8e8e8e, 0x4a4a4a4a, 0x4e4e4e4e, 0xcacacaca, 0xcececece, 0x35353535, 0x60606060, 0xe0e0e0e0, 0xa5a5a5a5, 0x65656565, 0x30303030, 0xa0a0a0a0, 0xe5e5e5e5, 0x32323232, 0x37373737, 0xa2a2a2a2, 0xa7a7a7a7, 0x62626262, 0x67676767, 0xe2e2e2e2, 0xe7e7e7e7, 0x3d3d3d3d, 0x69696969, 0xe9e9e9e9, 0xadadadad, 0x6d6d6d6d, 0x39393939, 0xa9a9a9a9, 0xedededed, 0x3b3b3b3b, 0x3f3f3f3f, 0xabababab, 0xafafafaf, 0x6b6b6b6b, 0x6f6f6f6f, 0xebebebeb, 0xefefefef, 0x26262626, 0x23232323, 0xb3b3b3b3, 0xb6b6b6b6, 0x76767676, 0x73737373, 0xf3f3f3f3, 0xf6f6f6f6, 0x71717171, 0x24242424, 0xf1f1f1f1, 0xb4b4b4b4, 0x21212121, 0x74747474, 0xb1b1b1b1, 0xf4f4f4f4, 0x2c2c2c2c, 0x78787878, 0xf8f8f8f8, 0xbcbcbcbc, 0x7c7c7c7c, 0x28282828, 0xb8b8b8b8, 0xfcfcfcfc, 0x2a2a2a2a, 0x2e2e2e2e, 0xbabababa, 0xbebebebe, 0x7a7a7a7a, 0x7e7e7e7e, 0xfafafafa, 0xfefefefe, 0x25252525, 0x70707070, 0xf0f0f0f0, 0xb5b5b5b5, 0x75757575, 0x20202020, 0xb0b0b0b0, 0xf5f5f5f5, 0x22222222, 0x27272727, 0xb2b2b2b2, 0xb7b7b7b7, 0x72727272, 0x77777777, 0xf2f2f2f2, 0xf7f7f7f7, 0x2d2d2d2d, 0x79797979, 0xf9f9f9f9, 0xbdbdbdbd, 0x7d7d7d7d, 0x29292929, 0xb9b9b9b9, 0xfdfdfdfd, 0x2b2b2b2b, 0x2f2f2f2f, 0xbbbbbbbb, 0xbfbfbfbf, 0x7b7b7b7b, 0x7f7f7f7f, 0xfbfbfbfb, 0xffffffff}; + +static const uint32_t AC_column0[87] = {0x1000101, 0x3000303, 0x7000707, 0xf000f0f, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x7000707, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x9000909, 0x3000303, 0x7000707, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x5000505, 0xb000b0b, 0x7000707, 0xe000e0e, 0xc000c0c, 0x8000808, 0x0, 0x1000101, 0x3000303, 0x6000606, 0xd000d0d, 0xb000b0b, 0x7000707, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x4000404, 0x9000909, 0x3000303, 0x6000606, 0xc000c0c, 0x8000808, 0x1000101, 0x2000202, 0x5000505, 0xa000a0a, 0x5000505, 0xb000b0b, 0x6000606, 0xc000c0c, 0x8000808, 0x0, 0x0, 0x1000101, 0x2000202, 0x5000505, 0xb000b0b, 0x7000707, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x8000808, 0x1000101, 0x3000303, 0x7000707, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x6000606, 0xd000d0d, 0xb000b0b, 0x6000606, 0xc000c0c, 0x9000909, 0x2000202, 0x4000404, 0x9000909, 0x2000202, 0x5000505, 0xa000a0a, 0x4000404, 0x9000909, 0x2000202, 0x4000404, 0x8000808, 0x0}; +static const uint32_t AC_column1[87] = {0x0, 0x0, 0x0, 0x0, 0x10000, 0x30000, 0x70000, 0x70000, 0x70000, 0x70000, 0x60000, 0x50000, 0x30000, 0x70000, 0x70000, 0x70000, 0x60000, 0x40000, 0x10000, 0x30000, 0x70000, 0x70000, 0x60000, 0x50000, 0x20000, 0x50000, 0x30000, 0x70000, 0x60000, 0x40000, 0x0, 0x0, 0x10000, 0x30000, 0x60000, 0x50000, 0x30000, 0x70000, 0x60000, 0x50000, 0x20000, 0x40000, 0x10000, 0x30000, 0x60000, 0x40000, 0x0, 0x10000, 0x20000, 0x50000, 0x20000, 0x50000, 0x30000, 0x60000, 0x40000, 0x0, 0x0, 0x0, 0x10000, 0x20000, 0x50000, 0x30000, 0x70000, 0x70000, 0x60000, 0x40000, 0x0, 0x10000, 0x30000, 0x70000, 0x60000, 0x50000, 0x30000, 0x60000, 0x50000, 0x30000, 0x60000, 0x40000, 0x10000, 0x20000, 0x40000, 0x10000, 0x20000, 0x50000, 0x20000, 0x40000, 0x10000}; + + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +#define load_column_8(dest, src) \ + do { \ + dest[0] = (src[12]) << 24 | (src[8]) << 16 | (src[4]) << 8 | (src[0]); \ + dest[1] = (src[13]) << 24 | (src[9]) << 16 | (src[5]) << 8 | (src[1]); \ + dest[2] = (src[14]) << 24 | (src[10]) << 16 | (src[6]) << 8 | (src[2]); \ + dest[3] = (src[15]) << 24 | (src[11]) << 16 | (src[7]) << 8 | (src[3]); \ + } while(0) + +#define store_column_8(dest, src) \ + do { \ + dest[0] = (uint8_t) (src[0]); dest[1] = (uint8_t) (src[1]); dest[2] = (uint8_t) (src[2]); dest[3] = (uint8_t) (src[3]); \ + dest[4] = (uint8_t) (src[0]>>8); dest[5] = (uint8_t) (src[1]>>8); dest[6] = (uint8_t) (src[2]>>8); dest[7] = (uint8_t) (src[3]>>8); \ + dest[8] = (uint8_t) (src[0]>>16);dest[9] = (uint8_t) (src[1]>>16);dest[10]= (uint8_t) (src[2]>>16);dest[11]= (uint8_t)(src[3]>>16); \ + dest[12]= (uint8_t) (src[0]>>24);dest[13]= (uint8_t) (src[1]>>24);dest[14]= (uint8_t) (src[2]>>24);dest[15]= (uint8_t)(src[3]>>24); \ + } while(0) + +#define rows_to_columns_32(columns, row0, row1, row2, row3) \ + do { \ + columns[0] = (row3 & 0xFF) << 24|(row2 & 0xFF) << 16|(row1 & 0xFF) << 8 | (row0 & 0xFF);\ + columns[1] = (row3 & 0xFF00) << 16|(row2 & 0xFF00) << 8 |(row1 & 0xFF00) | (row0>>8 & 0xFF);\ + columns[2] = (row3 & 0xFF0000) << 8 |(row2 & 0xFF0000) |(row1 & 0xFF0000) >> 8 | (row0>>16 & 0xFF);\ + columns[3] = (row3 & 0xFF000000) |(row2 & 0xFF000000) >> 8 |(row1 & 0xFF000000) >> 16| (row0>>24 & 0xFF);\ + } while(0) + +#define columns_to_rows_32(rows, column0, column1, column2, column3) rows_to_columns_32(rows, column0, column1, column2, column3) + +#define TK_to_column_256(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1]; \ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_256(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); +} + + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_left, state.S); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + +static void forkskinny_128_256_inv_round_first(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_256_inv_round(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + // temp = 0x020000; + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_256_inv_round_final(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_256_inv_round_first(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER*2)-1); + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_256_inv_round_first(&state, FORKSKINNY_128_256_ROUNDS_BEFORE-1); + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, round); + } + store_column_8(output_right,fstate.S); + +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +#define TK_to_column_384(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1];\ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_384(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + /* Permute TK1, TK2, and TK3 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_permute_tk(state->TK3); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); + skinny128_LFSR3(state->TK3[0]); + skinny128_LFSR3(state->TK3[1]); +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_left, state.S); + + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + + +static void forkskinny_128_384_inv_round_first(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_384_inv_round(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_384_inv_round_final(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_permute_tk(state.TK3); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + skinny128_LFSR3(state.TK3[0]); + skinny128_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_384_inv_round_first(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1); + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_LFSR3(state.TK3[0]); + skinny128_inv_LFSR3(state.TK3[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + skinny128_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + memcpy(fstate.TK3, state.TK3, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_384_inv_round_first(&state, FORKSKINNY_128_384_ROUNDS_BEFORE - 1); + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, round); + } + store_column_8(output_right, fstate.S); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + uint16_t TK1[4]; /**< First part of the tweakey */ + uint16_t TK2[4]; /**< Second part of the tweakey */ + uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_permute_tk(state->TK1); + skinny64_permute_tk(state->TK2); + skinny64_permute_tk(state->TK3); + skinny64_LFSR2(state->TK2[0]); + skinny64_LFSR2(state->TK2[1]); + skinny64_LFSR3(state->TK3[0]); + skinny64_LFSR3(state->TK3[1]); +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_inv_LFSR2(state->TK2[0]); + skinny64_inv_LFSR2(state->TK2[1]); + skinny64_inv_LFSR3(state->TK3[0]); + skinny64_inv_LFSR3(state->TK3[1]); + skinny64_inv_permute_tk(state->TK1); + skinny64_inv_permute_tk(state->TK2); + skinny64_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + skinny64_permute_tk(state.TK1); + skinny64_permute_tk(state.TK2); + skinny64_permute_tk(state.TK3); + skinny64_LFSR2(state.TK2[0]); + skinny64_LFSR2(state.TK2[1]); + skinny64_LFSR3(state.TK3[0]); + skinny64_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_AFTER; ++round) { + skinny64_inv_LFSR2(state.TK2[0]); + skinny64_inv_LFSR2(state.TK2[1]); + skinny64_inv_LFSR3(state.TK3[0]); + skinny64_inv_LFSR3(state.TK3[1]); + skinny64_inv_permute_tk(state.TK1); + skinny64_inv_permute_tk(state.TK2); + skinny64_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} + diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t192n48v1/opt32_table/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/api.h new file mode 100644 index 0000000..6c701b5 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 14 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/encrypt.c new file mode 100644 index 0000000..51f85dd --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_256_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_256_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.c new file mode 100644 index 0000000..c43ef98 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.c @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = { + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, + 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, + 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, + 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, + 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, + 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, + 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, + 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, + 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b, + 0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, + 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10 +}; + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + + +} forkskinny_128_256_key_schedule_t; + +static void forkskinny_128_256_init_tks(forkskinny_128_256_key_schedule_t *ks, const unsigned char key[32], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + } + else{ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + FORKSKINNY_128_256_ROUNDS_AFTER); + } + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_inv_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + //uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + + +} forkskinny_128_384_key_schedule_t; + +static void forkskinny_128_384_init_tks(forkskinny_128_384_key_schedule_t *ks, const unsigned char key[48], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = le_load_word32(key + 32); + TK[1] = le_load_word32(key + 36); + TK[2] = le_load_word32(key + 40); + TK[3] = le_load_word32(key + 44); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR3(TK[0]); + skinny128_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + } + else{ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_inv_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + //uint16_t TK1[4]; /**< First part of the tweakey */ + //uint16_t TK2[4]; /**< Second part of the tweakey */ + //uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint16_t row0[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + uint16_t row1[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + + +} forkskinny_64_192_key_schedule_t; + +static void forkskinny_64_192_init_tks(forkskinny_64_192_key_schedule_t *ks, const unsigned char key[24], uint8_t nb_rounds){ + uint16_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = be_load_word16(key); + TK[1] = be_load_word16(key + 2); + TK[2] = be_load_word16(key + 4); + TK[3] = be_load_word16(key + 6); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny64_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = be_load_word16(key + 8); + TK[1] = be_load_word16(key + 10); + TK[2] = be_load_word16(key + 12); + TK[3] = be_load_word16(key + 14); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR2(TK[0]); + skinny64_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = be_load_word16(key + 16); + TK[1] = be_load_word16(key + 18); + TK[2] = be_load_word16(key + 20); + TK[3] = be_load_word16(key + 22); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR3(TK[0]); + skinny64_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + } + else{ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + FORKSKINNY_64_192_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, &ks, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_dec/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/api.h new file mode 100644 index 0000000..6c701b5 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 14 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/encrypt.c new file mode 100644 index 0000000..51f85dd --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_256_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_256_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.c new file mode 100644 index 0000000..af29f77 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" +#include + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b,0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10}; + +static const uint32_t T[256] = {0x65656565, 0x4c4c4c4c, 0x6a6a6a6a, 0x42424242, 0x4b4b4b4b, 0x63636363, 0x43434343, 0x6b6b6b6b, 0x55555555, 0x75757575, 0x5a5a5a5a, 0x7a7a7a7a, 0x53535353, 0x73737373, 0x5b5b5b5b, 0x7b7b7b7b, 0x35353535, 0x8c8c8c8c, 0x3a3a3a3a, 0x81818181, 0x89898989, 0x33333333, 0x80808080, 0x3b3b3b3b, 0x95959595, 0x25252525, 0x98989898, 0x2a2a2a2a, 0x90909090, 0x23232323, 0x99999999, 0x2b2b2b2b, 0xe5e5e5e5, 0xcccccccc, 0xe8e8e8e8, 0xc1c1c1c1, 0xc9c9c9c9, 0xe0e0e0e0, 0xc0c0c0c0, 0xe9e9e9e9, 0xd5d5d5d5, 0xf5f5f5f5, 0xd8d8d8d8, 0xf8f8f8f8, 0xd0d0d0d0, 0xf0f0f0f0, 0xd9d9d9d9, 0xf9f9f9f9, 0xa5a5a5a5, 0x1c1c1c1c, 0xa8a8a8a8, 0x12121212, 0x1b1b1b1b, 0xa0a0a0a0, 0x13131313, 0xa9a9a9a9, 0x05050505, 0xb5b5b5b5, 0x0a0a0a0a, 0xb8b8b8b8, 0x03030303, 0xb0b0b0b0, 0x0b0b0b0b, 0xb9b9b9b9, 0x32323232, 0x88888888, 0x3c3c3c3c, 0x85858585, 0x8d8d8d8d, 0x34343434, 0x84848484, 0x3d3d3d3d, 0x91919191, 0x22222222, 0x9c9c9c9c, 0x2c2c2c2c, 0x94949494, 0x24242424, 0x9d9d9d9d, 0x2d2d2d2d, 0x62626262, 0x4a4a4a4a, 0x6c6c6c6c, 0x45454545, 0x4d4d4d4d, 0x64646464, 0x44444444, 0x6d6d6d6d, 0x52525252, 0x72727272, 0x5c5c5c5c, 0x7c7c7c7c, 0x54545454, 0x74747474, 0x5d5d5d5d, 0x7d7d7d7d, 0xa1a1a1a1, 0x1a1a1a1a, 0xacacacac, 0x15151515, 0x1d1d1d1d, 0xa4a4a4a4, 0x14141414, 0xadadadad, 0x02020202, 0xb1b1b1b1, 0x0c0c0c0c, 0xbcbcbcbc, 0x04040404, 0xb4b4b4b4, 0x0d0d0d0d, 0xbdbdbdbd, 0xe1e1e1e1, 0xc8c8c8c8, 0xecececec, 0xc5c5c5c5, 0xcdcdcdcd, 0xe4e4e4e4, 0xc4c4c4c4, 0xedededed, 0xd1d1d1d1, 0xf1f1f1f1, 0xdcdcdcdc, 0xfcfcfcfc, 0xd4d4d4d4, 0xf4f4f4f4, 0xdddddddd, 0xfdfdfdfd, 0x36363636, 0x8e8e8e8e, 0x38383838, 0x82828282, 0x8b8b8b8b, 0x30303030, 0x83838383, 0x39393939, 0x96969696, 0x26262626, 0x9a9a9a9a, 0x28282828, 0x93939393, 0x20202020, 0x9b9b9b9b, 0x29292929, 0x66666666, 0x4e4e4e4e, 0x68686868, 0x41414141, 0x49494949, 0x60606060, 0x40404040, 0x69696969, 0x56565656, 0x76767676, 0x58585858, 0x78787878, 0x50505050, 0x70707070, 0x59595959, 0x79797979, 0xa6a6a6a6, 0x1e1e1e1e, 0xaaaaaaaa, 0x11111111, 0x19191919, 0xa3a3a3a3, 0x10101010, 0xabababab, 0x06060606, 0xb6b6b6b6, 0x08080808, 0xbabababa, 0x00000000, 0xb3b3b3b3, 0x09090909, 0xbbbbbbbb, 0xe6e6e6e6, 0xcececece, 0xeaeaeaea, 0xc2c2c2c2, 0xcbcbcbcb, 0xe3e3e3e3, 0xc3c3c3c3, 0xebebebeb, 0xd6d6d6d6, 0xf6f6f6f6, 0xdadadada, 0xfafafafa, 0xd3d3d3d3, 0xf3f3f3f3, 0xdbdbdbdb, 0xfbfbfbfb, 0x31313131, 0x8a8a8a8a, 0x3e3e3e3e, 0x86868686, 0x8f8f8f8f, 0x37373737, 0x87878787, 0x3f3f3f3f, 0x92929292, 0x21212121, 0x9e9e9e9e, 0x2e2e2e2e, 0x97979797, 0x27272727, 0x9f9f9f9f, 0x2f2f2f2f, 0x61616161, 0x48484848, 0x6e6e6e6e, 0x46464646, 0x4f4f4f4f, 0x67676767, 0x47474747, 0x6f6f6f6f, 0x51515151, 0x71717171, 0x5e5e5e5e, 0x7e7e7e7e, 0x57575757, 0x77777777, 0x5f5f5f5f, 0x7f7f7f7f, 0xa2a2a2a2, 0x18181818, 0xaeaeaeae, 0x16161616, 0x1f1f1f1f, 0xa7a7a7a7, 0x17171717, 0xafafafaf, 0x01010101, 0xb2b2b2b2, 0x0e0e0e0e, 0xbebebebe, 0x07070707, 0xb7b7b7b7, 0x0f0f0f0f, 0xbfbfbfbf, 0xe2e2e2e2, 0xcacacaca, 0xeeeeeeee, 0xc6c6c6c6, 0xcfcfcfcf, 0xe7e7e7e7, 0xc7c7c7c7, 0xefefefef, 0xd2d2d2d2, 0xf2f2f2f2, 0xdededede, 0xfefefefe, 0xd7d7d7d7, 0xf7f7f7f7, 0xdfdfdfdf, 0xffffffff}; +static const uint32_t T_inv[256] = {0xacacacac, 0xe8e8e8e8, 0x68686868, 0x3c3c3c3c, 0x6c6c6c6c, 0x38383838, 0xa8a8a8a8, 0xecececec, 0xaaaaaaaa, 0xaeaeaeae, 0x3a3a3a3a, 0x3e3e3e3e, 0x6a6a6a6a, 0x6e6e6e6e, 0xeaeaeaea, 0xeeeeeeee, 0xa6a6a6a6, 0xa3a3a3a3, 0x33333333, 0x36363636, 0x66666666, 0x63636363, 0xe3e3e3e3, 0xe6e6e6e6, 0xe1e1e1e1, 0xa4a4a4a4, 0x61616161, 0x34343434, 0x31313131, 0x64646464, 0xa1a1a1a1, 0xe4e4e4e4, 0x8d8d8d8d, 0xc9c9c9c9, 0x49494949, 0x1d1d1d1d, 0x4d4d4d4d, 0x19191919, 0x89898989, 0xcdcdcdcd, 0x8b8b8b8b, 0x8f8f8f8f, 0x1b1b1b1b, 0x1f1f1f1f, 0x4b4b4b4b, 0x4f4f4f4f, 0xcbcbcbcb, 0xcfcfcfcf, 0x85858585, 0xc0c0c0c0, 0x40404040, 0x15151515, 0x45454545, 0x10101010, 0x80808080, 0xc5c5c5c5, 0x82828282, 0x87878787, 0x12121212, 0x17171717, 0x42424242, 0x47474747, 0xc2c2c2c2, 0xc7c7c7c7, 0x96969696, 0x93939393, 0x03030303, 0x06060606, 0x56565656, 0x53535353, 0xd3d3d3d3, 0xd6d6d6d6, 0xd1d1d1d1, 0x94949494, 0x51515151, 0x04040404, 0x01010101, 0x54545454, 0x91919191, 0xd4d4d4d4, 0x9c9c9c9c, 0xd8d8d8d8, 0x58585858, 0x0c0c0c0c, 0x5c5c5c5c, 0x08080808, 0x98989898, 0xdcdcdcdc, 0x9a9a9a9a, 0x9e9e9e9e, 0x0a0a0a0a, 0x0e0e0e0e, 0x5a5a5a5a, 0x5e5e5e5e, 0xdadadada, 0xdededede, 0x95959595, 0xd0d0d0d0, 0x50505050, 0x05050505, 0x55555555, 0x00000000, 0x90909090, 0xd5d5d5d5, 0x92929292, 0x97979797, 0x02020202, 0x07070707, 0x52525252, 0x57575757, 0xd2d2d2d2, 0xd7d7d7d7, 0x9d9d9d9d, 0xd9d9d9d9, 0x59595959, 0x0d0d0d0d, 0x5d5d5d5d, 0x09090909, 0x99999999, 0xdddddddd, 0x9b9b9b9b, 0x9f9f9f9f, 0x0b0b0b0b, 0x0f0f0f0f, 0x5b5b5b5b, 0x5f5f5f5f, 0xdbdbdbdb, 0xdfdfdfdf, 0x16161616, 0x13131313, 0x83838383, 0x86868686, 0x46464646, 0x43434343, 0xc3c3c3c3, 0xc6c6c6c6, 0x41414141, 0x14141414, 0xc1c1c1c1, 0x84848484, 0x11111111, 0x44444444, 0x81818181, 0xc4c4c4c4, 0x1c1c1c1c, 0x48484848, 0xc8c8c8c8, 0x8c8c8c8c, 0x4c4c4c4c, 0x18181818, 0x88888888, 0xcccccccc, 0x1a1a1a1a, 0x1e1e1e1e, 0x8a8a8a8a, 0x8e8e8e8e, 0x4a4a4a4a, 0x4e4e4e4e, 0xcacacaca, 0xcececece, 0x35353535, 0x60606060, 0xe0e0e0e0, 0xa5a5a5a5, 0x65656565, 0x30303030, 0xa0a0a0a0, 0xe5e5e5e5, 0x32323232, 0x37373737, 0xa2a2a2a2, 0xa7a7a7a7, 0x62626262, 0x67676767, 0xe2e2e2e2, 0xe7e7e7e7, 0x3d3d3d3d, 0x69696969, 0xe9e9e9e9, 0xadadadad, 0x6d6d6d6d, 0x39393939, 0xa9a9a9a9, 0xedededed, 0x3b3b3b3b, 0x3f3f3f3f, 0xabababab, 0xafafafaf, 0x6b6b6b6b, 0x6f6f6f6f, 0xebebebeb, 0xefefefef, 0x26262626, 0x23232323, 0xb3b3b3b3, 0xb6b6b6b6, 0x76767676, 0x73737373, 0xf3f3f3f3, 0xf6f6f6f6, 0x71717171, 0x24242424, 0xf1f1f1f1, 0xb4b4b4b4, 0x21212121, 0x74747474, 0xb1b1b1b1, 0xf4f4f4f4, 0x2c2c2c2c, 0x78787878, 0xf8f8f8f8, 0xbcbcbcbc, 0x7c7c7c7c, 0x28282828, 0xb8b8b8b8, 0xfcfcfcfc, 0x2a2a2a2a, 0x2e2e2e2e, 0xbabababa, 0xbebebebe, 0x7a7a7a7a, 0x7e7e7e7e, 0xfafafafa, 0xfefefefe, 0x25252525, 0x70707070, 0xf0f0f0f0, 0xb5b5b5b5, 0x75757575, 0x20202020, 0xb0b0b0b0, 0xf5f5f5f5, 0x22222222, 0x27272727, 0xb2b2b2b2, 0xb7b7b7b7, 0x72727272, 0x77777777, 0xf2f2f2f2, 0xf7f7f7f7, 0x2d2d2d2d, 0x79797979, 0xf9f9f9f9, 0xbdbdbdbd, 0x7d7d7d7d, 0x29292929, 0xb9b9b9b9, 0xfdfdfdfd, 0x2b2b2b2b, 0x2f2f2f2f, 0xbbbbbbbb, 0xbfbfbfbf, 0x7b7b7b7b, 0x7f7f7f7f, 0xfbfbfbfb, 0xffffffff}; + +static const uint32_t AC_column0[87] = {0x1000101, 0x3000303, 0x7000707, 0xf000f0f, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x7000707, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x9000909, 0x3000303, 0x7000707, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x5000505, 0xb000b0b, 0x7000707, 0xe000e0e, 0xc000c0c, 0x8000808, 0x0, 0x1000101, 0x3000303, 0x6000606, 0xd000d0d, 0xb000b0b, 0x7000707, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x4000404, 0x9000909, 0x3000303, 0x6000606, 0xc000c0c, 0x8000808, 0x1000101, 0x2000202, 0x5000505, 0xa000a0a, 0x5000505, 0xb000b0b, 0x6000606, 0xc000c0c, 0x8000808, 0x0, 0x0, 0x1000101, 0x2000202, 0x5000505, 0xb000b0b, 0x7000707, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x8000808, 0x1000101, 0x3000303, 0x7000707, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x6000606, 0xd000d0d, 0xb000b0b, 0x6000606, 0xc000c0c, 0x9000909, 0x2000202, 0x4000404, 0x9000909, 0x2000202, 0x5000505, 0xa000a0a, 0x4000404, 0x9000909, 0x2000202, 0x4000404, 0x8000808, 0x0}; +static const uint32_t AC_column1[87] = {0x0, 0x0, 0x0, 0x0, 0x10000, 0x30000, 0x70000, 0x70000, 0x70000, 0x70000, 0x60000, 0x50000, 0x30000, 0x70000, 0x70000, 0x70000, 0x60000, 0x40000, 0x10000, 0x30000, 0x70000, 0x70000, 0x60000, 0x50000, 0x20000, 0x50000, 0x30000, 0x70000, 0x60000, 0x40000, 0x0, 0x0, 0x10000, 0x30000, 0x60000, 0x50000, 0x30000, 0x70000, 0x60000, 0x50000, 0x20000, 0x40000, 0x10000, 0x30000, 0x60000, 0x40000, 0x0, 0x10000, 0x20000, 0x50000, 0x20000, 0x50000, 0x30000, 0x60000, 0x40000, 0x0, 0x0, 0x0, 0x10000, 0x20000, 0x50000, 0x30000, 0x70000, 0x70000, 0x60000, 0x40000, 0x0, 0x10000, 0x30000, 0x70000, 0x60000, 0x50000, 0x30000, 0x60000, 0x50000, 0x30000, 0x60000, 0x40000, 0x10000, 0x20000, 0x40000, 0x10000, 0x20000, 0x50000, 0x20000, 0x40000, 0x10000}; + + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +#define load_column_8(dest, src) \ + do { \ + dest[0] = (src[12]) << 24 | (src[8]) << 16 | (src[4]) << 8 | (src[0]); \ + dest[1] = (src[13]) << 24 | (src[9]) << 16 | (src[5]) << 8 | (src[1]); \ + dest[2] = (src[14]) << 24 | (src[10]) << 16 | (src[6]) << 8 | (src[2]); \ + dest[3] = (src[15]) << 24 | (src[11]) << 16 | (src[7]) << 8 | (src[3]); \ + } while(0) + +#define store_column_8(dest, src) \ + do { \ + dest[0] = (uint8_t) (src[0]); dest[1] = (uint8_t) (src[1]); dest[2] = (uint8_t) (src[2]); dest[3] = (uint8_t) (src[3]); \ + dest[4] = (uint8_t) (src[0]>>8); dest[5] = (uint8_t) (src[1]>>8); dest[6] = (uint8_t) (src[2]>>8); dest[7] = (uint8_t) (src[3]>>8); \ + dest[8] = (uint8_t) (src[0]>>16);dest[9] = (uint8_t) (src[1]>>16);dest[10]= (uint8_t) (src[2]>>16);dest[11]= (uint8_t)(src[3]>>16); \ + dest[12]= (uint8_t) (src[0]>>24);dest[13]= (uint8_t) (src[1]>>24);dest[14]= (uint8_t) (src[2]>>24);dest[15]= (uint8_t)(src[3]>>24); \ + } while(0) + +#define rows_to_columns_32(columns, row0, row1, row2, row3) \ + do { \ + columns[0] = (row3 & 0xFF) << 24|(row2 & 0xFF) << 16|(row1 & 0xFF) << 8 | (row0 & 0xFF);\ + columns[1] = (row3 & 0xFF00) << 16|(row2 & 0xFF00) << 8 |(row1 & 0xFF00) | (row0>>8 & 0xFF);\ + columns[2] = (row3 & 0xFF0000) << 8 |(row2 & 0xFF0000) |(row1 & 0xFF0000) >> 8 | (row0>>16 & 0xFF);\ + columns[3] = (row3 & 0xFF000000) |(row2 & 0xFF000000) >> 8 |(row1 & 0xFF000000) >> 16| (row0>>24 & 0xFF);\ + } while(0) + +#define columns_to_rows_32(rows, column0, column1, column2, column3) rows_to_columns_32(rows, column0, column1, column2, column3) + +#define TK_to_column_256(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1]; \ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_256(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); +} + + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_left, state.S); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + +static void forkskinny_128_256_inv_round_first(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_256_inv_round(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + // temp = 0x020000; + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_256_inv_round_final(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_256_inv_round_first(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER*2)-1); + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_256_inv_round_first(&state, FORKSKINNY_128_256_ROUNDS_BEFORE-1); + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, round); + } + store_column_8(output_right,fstate.S); + +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +#define TK_to_column_384(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1];\ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_384(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + /* Permute TK1, TK2, and TK3 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_permute_tk(state->TK3); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); + skinny128_LFSR3(state->TK3[0]); + skinny128_LFSR3(state->TK3[1]); +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_left, state.S); + + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + + +static void forkskinny_128_384_inv_round_first(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_384_inv_round(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_384_inv_round_final(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_permute_tk(state.TK3); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + skinny128_LFSR3(state.TK3[0]); + skinny128_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_384_inv_round_first(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1); + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_LFSR3(state.TK3[0]); + skinny128_inv_LFSR3(state.TK3[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + skinny128_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + memcpy(fstate.TK3, state.TK3, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_384_inv_round_first(&state, FORKSKINNY_128_384_ROUNDS_BEFORE - 1); + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, round); + } + store_column_8(output_right, fstate.S); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + uint16_t TK1[4]; /**< First part of the tweakey */ + uint16_t TK2[4]; /**< Second part of the tweakey */ + uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_permute_tk(state->TK1); + skinny64_permute_tk(state->TK2); + skinny64_permute_tk(state->TK3); + skinny64_LFSR2(state->TK2[0]); + skinny64_LFSR2(state->TK2[1]); + skinny64_LFSR3(state->TK3[0]); + skinny64_LFSR3(state->TK3[1]); +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_inv_LFSR2(state->TK2[0]); + skinny64_inv_LFSR2(state->TK2[1]); + skinny64_inv_LFSR3(state->TK3[0]); + skinny64_inv_LFSR3(state->TK3[1]); + skinny64_inv_permute_tk(state->TK1); + skinny64_inv_permute_tk(state->TK2); + skinny64_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + skinny64_permute_tk(state.TK1); + skinny64_permute_tk(state.TK2); + skinny64_permute_tk(state.TK3); + skinny64_LFSR2(state.TK2[0]); + skinny64_LFSR2(state.TK2[1]); + skinny64_LFSR3(state.TK3[0]); + skinny64_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_AFTER; ++round) { + skinny64_inv_LFSR2(state.TK2[0]); + skinny64_inv_LFSR2(state.TK2[1]); + skinny64_inv_LFSR3(state.TK3[0]); + skinny64_inv_LFSR3(state.TK3[1]); + skinny64_inv_permute_tk(state.TK1); + skinny64_inv_permute_tk(state.TK2); + skinny64_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} + diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t256n112v1/opt32_table/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/api.h new file mode 100644 index 0000000..500c2c7 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 13 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/encrypt.c new file mode 100644 index 0000000..162645f --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_288_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_288_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.c new file mode 100644 index 0000000..c43ef98 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.c @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = { + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, + 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, + 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, + 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, + 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, + 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, + 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, + 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, + 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b, + 0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, + 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10 +}; + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + + +} forkskinny_128_256_key_schedule_t; + +static void forkskinny_128_256_init_tks(forkskinny_128_256_key_schedule_t *ks, const unsigned char key[32], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + } + else{ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + FORKSKINNY_128_256_ROUNDS_AFTER); + } + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_inv_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + //uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + + +} forkskinny_128_384_key_schedule_t; + +static void forkskinny_128_384_init_tks(forkskinny_128_384_key_schedule_t *ks, const unsigned char key[48], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = le_load_word32(key + 32); + TK[1] = le_load_word32(key + 36); + TK[2] = le_load_word32(key + 40); + TK[3] = le_load_word32(key + 44); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR3(TK[0]); + skinny128_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + } + else{ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_inv_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + //uint16_t TK1[4]; /**< First part of the tweakey */ + //uint16_t TK2[4]; /**< Second part of the tweakey */ + //uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint16_t row0[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + uint16_t row1[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + + +} forkskinny_64_192_key_schedule_t; + +static void forkskinny_64_192_init_tks(forkskinny_64_192_key_schedule_t *ks, const unsigned char key[24], uint8_t nb_rounds){ + uint16_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = be_load_word16(key); + TK[1] = be_load_word16(key + 2); + TK[2] = be_load_word16(key + 4); + TK[3] = be_load_word16(key + 6); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny64_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = be_load_word16(key + 8); + TK[1] = be_load_word16(key + 10); + TK[2] = be_load_word16(key + 12); + TK[3] = be_load_word16(key + 14); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR2(TK[0]); + skinny64_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = be_load_word16(key + 16); + TK[1] = be_load_word16(key + 18); + TK[2] = be_load_word16(key + 20); + TK[3] = be_load_word16(key + 22); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR3(TK[0]); + skinny64_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + } + else{ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + FORKSKINNY_64_192_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, &ks, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_dec/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/api.h new file mode 100644 index 0000000..500c2c7 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 13 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/encrypt.c new file mode 100644 index 0000000..162645f --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_288_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_128_288_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.c new file mode 100644 index 0000000..af29f77 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" +#include + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b,0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10}; + +static const uint32_t T[256] = {0x65656565, 0x4c4c4c4c, 0x6a6a6a6a, 0x42424242, 0x4b4b4b4b, 0x63636363, 0x43434343, 0x6b6b6b6b, 0x55555555, 0x75757575, 0x5a5a5a5a, 0x7a7a7a7a, 0x53535353, 0x73737373, 0x5b5b5b5b, 0x7b7b7b7b, 0x35353535, 0x8c8c8c8c, 0x3a3a3a3a, 0x81818181, 0x89898989, 0x33333333, 0x80808080, 0x3b3b3b3b, 0x95959595, 0x25252525, 0x98989898, 0x2a2a2a2a, 0x90909090, 0x23232323, 0x99999999, 0x2b2b2b2b, 0xe5e5e5e5, 0xcccccccc, 0xe8e8e8e8, 0xc1c1c1c1, 0xc9c9c9c9, 0xe0e0e0e0, 0xc0c0c0c0, 0xe9e9e9e9, 0xd5d5d5d5, 0xf5f5f5f5, 0xd8d8d8d8, 0xf8f8f8f8, 0xd0d0d0d0, 0xf0f0f0f0, 0xd9d9d9d9, 0xf9f9f9f9, 0xa5a5a5a5, 0x1c1c1c1c, 0xa8a8a8a8, 0x12121212, 0x1b1b1b1b, 0xa0a0a0a0, 0x13131313, 0xa9a9a9a9, 0x05050505, 0xb5b5b5b5, 0x0a0a0a0a, 0xb8b8b8b8, 0x03030303, 0xb0b0b0b0, 0x0b0b0b0b, 0xb9b9b9b9, 0x32323232, 0x88888888, 0x3c3c3c3c, 0x85858585, 0x8d8d8d8d, 0x34343434, 0x84848484, 0x3d3d3d3d, 0x91919191, 0x22222222, 0x9c9c9c9c, 0x2c2c2c2c, 0x94949494, 0x24242424, 0x9d9d9d9d, 0x2d2d2d2d, 0x62626262, 0x4a4a4a4a, 0x6c6c6c6c, 0x45454545, 0x4d4d4d4d, 0x64646464, 0x44444444, 0x6d6d6d6d, 0x52525252, 0x72727272, 0x5c5c5c5c, 0x7c7c7c7c, 0x54545454, 0x74747474, 0x5d5d5d5d, 0x7d7d7d7d, 0xa1a1a1a1, 0x1a1a1a1a, 0xacacacac, 0x15151515, 0x1d1d1d1d, 0xa4a4a4a4, 0x14141414, 0xadadadad, 0x02020202, 0xb1b1b1b1, 0x0c0c0c0c, 0xbcbcbcbc, 0x04040404, 0xb4b4b4b4, 0x0d0d0d0d, 0xbdbdbdbd, 0xe1e1e1e1, 0xc8c8c8c8, 0xecececec, 0xc5c5c5c5, 0xcdcdcdcd, 0xe4e4e4e4, 0xc4c4c4c4, 0xedededed, 0xd1d1d1d1, 0xf1f1f1f1, 0xdcdcdcdc, 0xfcfcfcfc, 0xd4d4d4d4, 0xf4f4f4f4, 0xdddddddd, 0xfdfdfdfd, 0x36363636, 0x8e8e8e8e, 0x38383838, 0x82828282, 0x8b8b8b8b, 0x30303030, 0x83838383, 0x39393939, 0x96969696, 0x26262626, 0x9a9a9a9a, 0x28282828, 0x93939393, 0x20202020, 0x9b9b9b9b, 0x29292929, 0x66666666, 0x4e4e4e4e, 0x68686868, 0x41414141, 0x49494949, 0x60606060, 0x40404040, 0x69696969, 0x56565656, 0x76767676, 0x58585858, 0x78787878, 0x50505050, 0x70707070, 0x59595959, 0x79797979, 0xa6a6a6a6, 0x1e1e1e1e, 0xaaaaaaaa, 0x11111111, 0x19191919, 0xa3a3a3a3, 0x10101010, 0xabababab, 0x06060606, 0xb6b6b6b6, 0x08080808, 0xbabababa, 0x00000000, 0xb3b3b3b3, 0x09090909, 0xbbbbbbbb, 0xe6e6e6e6, 0xcececece, 0xeaeaeaea, 0xc2c2c2c2, 0xcbcbcbcb, 0xe3e3e3e3, 0xc3c3c3c3, 0xebebebeb, 0xd6d6d6d6, 0xf6f6f6f6, 0xdadadada, 0xfafafafa, 0xd3d3d3d3, 0xf3f3f3f3, 0xdbdbdbdb, 0xfbfbfbfb, 0x31313131, 0x8a8a8a8a, 0x3e3e3e3e, 0x86868686, 0x8f8f8f8f, 0x37373737, 0x87878787, 0x3f3f3f3f, 0x92929292, 0x21212121, 0x9e9e9e9e, 0x2e2e2e2e, 0x97979797, 0x27272727, 0x9f9f9f9f, 0x2f2f2f2f, 0x61616161, 0x48484848, 0x6e6e6e6e, 0x46464646, 0x4f4f4f4f, 0x67676767, 0x47474747, 0x6f6f6f6f, 0x51515151, 0x71717171, 0x5e5e5e5e, 0x7e7e7e7e, 0x57575757, 0x77777777, 0x5f5f5f5f, 0x7f7f7f7f, 0xa2a2a2a2, 0x18181818, 0xaeaeaeae, 0x16161616, 0x1f1f1f1f, 0xa7a7a7a7, 0x17171717, 0xafafafaf, 0x01010101, 0xb2b2b2b2, 0x0e0e0e0e, 0xbebebebe, 0x07070707, 0xb7b7b7b7, 0x0f0f0f0f, 0xbfbfbfbf, 0xe2e2e2e2, 0xcacacaca, 0xeeeeeeee, 0xc6c6c6c6, 0xcfcfcfcf, 0xe7e7e7e7, 0xc7c7c7c7, 0xefefefef, 0xd2d2d2d2, 0xf2f2f2f2, 0xdededede, 0xfefefefe, 0xd7d7d7d7, 0xf7f7f7f7, 0xdfdfdfdf, 0xffffffff}; +static const uint32_t T_inv[256] = {0xacacacac, 0xe8e8e8e8, 0x68686868, 0x3c3c3c3c, 0x6c6c6c6c, 0x38383838, 0xa8a8a8a8, 0xecececec, 0xaaaaaaaa, 0xaeaeaeae, 0x3a3a3a3a, 0x3e3e3e3e, 0x6a6a6a6a, 0x6e6e6e6e, 0xeaeaeaea, 0xeeeeeeee, 0xa6a6a6a6, 0xa3a3a3a3, 0x33333333, 0x36363636, 0x66666666, 0x63636363, 0xe3e3e3e3, 0xe6e6e6e6, 0xe1e1e1e1, 0xa4a4a4a4, 0x61616161, 0x34343434, 0x31313131, 0x64646464, 0xa1a1a1a1, 0xe4e4e4e4, 0x8d8d8d8d, 0xc9c9c9c9, 0x49494949, 0x1d1d1d1d, 0x4d4d4d4d, 0x19191919, 0x89898989, 0xcdcdcdcd, 0x8b8b8b8b, 0x8f8f8f8f, 0x1b1b1b1b, 0x1f1f1f1f, 0x4b4b4b4b, 0x4f4f4f4f, 0xcbcbcbcb, 0xcfcfcfcf, 0x85858585, 0xc0c0c0c0, 0x40404040, 0x15151515, 0x45454545, 0x10101010, 0x80808080, 0xc5c5c5c5, 0x82828282, 0x87878787, 0x12121212, 0x17171717, 0x42424242, 0x47474747, 0xc2c2c2c2, 0xc7c7c7c7, 0x96969696, 0x93939393, 0x03030303, 0x06060606, 0x56565656, 0x53535353, 0xd3d3d3d3, 0xd6d6d6d6, 0xd1d1d1d1, 0x94949494, 0x51515151, 0x04040404, 0x01010101, 0x54545454, 0x91919191, 0xd4d4d4d4, 0x9c9c9c9c, 0xd8d8d8d8, 0x58585858, 0x0c0c0c0c, 0x5c5c5c5c, 0x08080808, 0x98989898, 0xdcdcdcdc, 0x9a9a9a9a, 0x9e9e9e9e, 0x0a0a0a0a, 0x0e0e0e0e, 0x5a5a5a5a, 0x5e5e5e5e, 0xdadadada, 0xdededede, 0x95959595, 0xd0d0d0d0, 0x50505050, 0x05050505, 0x55555555, 0x00000000, 0x90909090, 0xd5d5d5d5, 0x92929292, 0x97979797, 0x02020202, 0x07070707, 0x52525252, 0x57575757, 0xd2d2d2d2, 0xd7d7d7d7, 0x9d9d9d9d, 0xd9d9d9d9, 0x59595959, 0x0d0d0d0d, 0x5d5d5d5d, 0x09090909, 0x99999999, 0xdddddddd, 0x9b9b9b9b, 0x9f9f9f9f, 0x0b0b0b0b, 0x0f0f0f0f, 0x5b5b5b5b, 0x5f5f5f5f, 0xdbdbdbdb, 0xdfdfdfdf, 0x16161616, 0x13131313, 0x83838383, 0x86868686, 0x46464646, 0x43434343, 0xc3c3c3c3, 0xc6c6c6c6, 0x41414141, 0x14141414, 0xc1c1c1c1, 0x84848484, 0x11111111, 0x44444444, 0x81818181, 0xc4c4c4c4, 0x1c1c1c1c, 0x48484848, 0xc8c8c8c8, 0x8c8c8c8c, 0x4c4c4c4c, 0x18181818, 0x88888888, 0xcccccccc, 0x1a1a1a1a, 0x1e1e1e1e, 0x8a8a8a8a, 0x8e8e8e8e, 0x4a4a4a4a, 0x4e4e4e4e, 0xcacacaca, 0xcececece, 0x35353535, 0x60606060, 0xe0e0e0e0, 0xa5a5a5a5, 0x65656565, 0x30303030, 0xa0a0a0a0, 0xe5e5e5e5, 0x32323232, 0x37373737, 0xa2a2a2a2, 0xa7a7a7a7, 0x62626262, 0x67676767, 0xe2e2e2e2, 0xe7e7e7e7, 0x3d3d3d3d, 0x69696969, 0xe9e9e9e9, 0xadadadad, 0x6d6d6d6d, 0x39393939, 0xa9a9a9a9, 0xedededed, 0x3b3b3b3b, 0x3f3f3f3f, 0xabababab, 0xafafafaf, 0x6b6b6b6b, 0x6f6f6f6f, 0xebebebeb, 0xefefefef, 0x26262626, 0x23232323, 0xb3b3b3b3, 0xb6b6b6b6, 0x76767676, 0x73737373, 0xf3f3f3f3, 0xf6f6f6f6, 0x71717171, 0x24242424, 0xf1f1f1f1, 0xb4b4b4b4, 0x21212121, 0x74747474, 0xb1b1b1b1, 0xf4f4f4f4, 0x2c2c2c2c, 0x78787878, 0xf8f8f8f8, 0xbcbcbcbc, 0x7c7c7c7c, 0x28282828, 0xb8b8b8b8, 0xfcfcfcfc, 0x2a2a2a2a, 0x2e2e2e2e, 0xbabababa, 0xbebebebe, 0x7a7a7a7a, 0x7e7e7e7e, 0xfafafafa, 0xfefefefe, 0x25252525, 0x70707070, 0xf0f0f0f0, 0xb5b5b5b5, 0x75757575, 0x20202020, 0xb0b0b0b0, 0xf5f5f5f5, 0x22222222, 0x27272727, 0xb2b2b2b2, 0xb7b7b7b7, 0x72727272, 0x77777777, 0xf2f2f2f2, 0xf7f7f7f7, 0x2d2d2d2d, 0x79797979, 0xf9f9f9f9, 0xbdbdbdbd, 0x7d7d7d7d, 0x29292929, 0xb9b9b9b9, 0xfdfdfdfd, 0x2b2b2b2b, 0x2f2f2f2f, 0xbbbbbbbb, 0xbfbfbfbf, 0x7b7b7b7b, 0x7f7f7f7f, 0xfbfbfbfb, 0xffffffff}; + +static const uint32_t AC_column0[87] = {0x1000101, 0x3000303, 0x7000707, 0xf000f0f, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x7000707, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x9000909, 0x3000303, 0x7000707, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x5000505, 0xb000b0b, 0x7000707, 0xe000e0e, 0xc000c0c, 0x8000808, 0x0, 0x1000101, 0x3000303, 0x6000606, 0xd000d0d, 0xb000b0b, 0x7000707, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x4000404, 0x9000909, 0x3000303, 0x6000606, 0xc000c0c, 0x8000808, 0x1000101, 0x2000202, 0x5000505, 0xa000a0a, 0x5000505, 0xb000b0b, 0x6000606, 0xc000c0c, 0x8000808, 0x0, 0x0, 0x1000101, 0x2000202, 0x5000505, 0xb000b0b, 0x7000707, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x8000808, 0x1000101, 0x3000303, 0x7000707, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x6000606, 0xd000d0d, 0xb000b0b, 0x6000606, 0xc000c0c, 0x9000909, 0x2000202, 0x4000404, 0x9000909, 0x2000202, 0x5000505, 0xa000a0a, 0x4000404, 0x9000909, 0x2000202, 0x4000404, 0x8000808, 0x0}; +static const uint32_t AC_column1[87] = {0x0, 0x0, 0x0, 0x0, 0x10000, 0x30000, 0x70000, 0x70000, 0x70000, 0x70000, 0x60000, 0x50000, 0x30000, 0x70000, 0x70000, 0x70000, 0x60000, 0x40000, 0x10000, 0x30000, 0x70000, 0x70000, 0x60000, 0x50000, 0x20000, 0x50000, 0x30000, 0x70000, 0x60000, 0x40000, 0x0, 0x0, 0x10000, 0x30000, 0x60000, 0x50000, 0x30000, 0x70000, 0x60000, 0x50000, 0x20000, 0x40000, 0x10000, 0x30000, 0x60000, 0x40000, 0x0, 0x10000, 0x20000, 0x50000, 0x20000, 0x50000, 0x30000, 0x60000, 0x40000, 0x0, 0x0, 0x0, 0x10000, 0x20000, 0x50000, 0x30000, 0x70000, 0x70000, 0x60000, 0x40000, 0x0, 0x10000, 0x30000, 0x70000, 0x60000, 0x50000, 0x30000, 0x60000, 0x50000, 0x30000, 0x60000, 0x40000, 0x10000, 0x20000, 0x40000, 0x10000, 0x20000, 0x50000, 0x20000, 0x40000, 0x10000}; + + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +#define load_column_8(dest, src) \ + do { \ + dest[0] = (src[12]) << 24 | (src[8]) << 16 | (src[4]) << 8 | (src[0]); \ + dest[1] = (src[13]) << 24 | (src[9]) << 16 | (src[5]) << 8 | (src[1]); \ + dest[2] = (src[14]) << 24 | (src[10]) << 16 | (src[6]) << 8 | (src[2]); \ + dest[3] = (src[15]) << 24 | (src[11]) << 16 | (src[7]) << 8 | (src[3]); \ + } while(0) + +#define store_column_8(dest, src) \ + do { \ + dest[0] = (uint8_t) (src[0]); dest[1] = (uint8_t) (src[1]); dest[2] = (uint8_t) (src[2]); dest[3] = (uint8_t) (src[3]); \ + dest[4] = (uint8_t) (src[0]>>8); dest[5] = (uint8_t) (src[1]>>8); dest[6] = (uint8_t) (src[2]>>8); dest[7] = (uint8_t) (src[3]>>8); \ + dest[8] = (uint8_t) (src[0]>>16);dest[9] = (uint8_t) (src[1]>>16);dest[10]= (uint8_t) (src[2]>>16);dest[11]= (uint8_t)(src[3]>>16); \ + dest[12]= (uint8_t) (src[0]>>24);dest[13]= (uint8_t) (src[1]>>24);dest[14]= (uint8_t) (src[2]>>24);dest[15]= (uint8_t)(src[3]>>24); \ + } while(0) + +#define rows_to_columns_32(columns, row0, row1, row2, row3) \ + do { \ + columns[0] = (row3 & 0xFF) << 24|(row2 & 0xFF) << 16|(row1 & 0xFF) << 8 | (row0 & 0xFF);\ + columns[1] = (row3 & 0xFF00) << 16|(row2 & 0xFF00) << 8 |(row1 & 0xFF00) | (row0>>8 & 0xFF);\ + columns[2] = (row3 & 0xFF0000) << 8 |(row2 & 0xFF0000) |(row1 & 0xFF0000) >> 8 | (row0>>16 & 0xFF);\ + columns[3] = (row3 & 0xFF000000) |(row2 & 0xFF000000) >> 8 |(row1 & 0xFF000000) >> 16| (row0>>24 & 0xFF);\ + } while(0) + +#define columns_to_rows_32(rows, column0, column1, column2, column3) rows_to_columns_32(rows, column0, column1, column2, column3) + +#define TK_to_column_256(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1]; \ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_256(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); +} + + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_left, state.S); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + +static void forkskinny_128_256_inv_round_first(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_256_inv_round(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + // temp = 0x020000; + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_256_inv_round_final(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_256_inv_round_first(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER*2)-1); + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_256_inv_round_first(&state, FORKSKINNY_128_256_ROUNDS_BEFORE-1); + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, round); + } + store_column_8(output_right,fstate.S); + +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +#define TK_to_column_384(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1];\ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_384(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + /* Permute TK1, TK2, and TK3 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_permute_tk(state->TK3); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); + skinny128_LFSR3(state->TK3[0]); + skinny128_LFSR3(state->TK3[1]); +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_left, state.S); + + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + + +static void forkskinny_128_384_inv_round_first(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_384_inv_round(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_384_inv_round_final(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_permute_tk(state.TK3); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + skinny128_LFSR3(state.TK3[0]); + skinny128_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_384_inv_round_first(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1); + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_LFSR3(state.TK3[0]); + skinny128_inv_LFSR3(state.TK3[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + skinny128_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + memcpy(fstate.TK3, state.TK3, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_384_inv_round_first(&state, FORKSKINNY_128_384_ROUNDS_BEFORE - 1); + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, round); + } + store_column_8(output_right, fstate.S); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + uint16_t TK1[4]; /**< First part of the tweakey */ + uint16_t TK2[4]; /**< Second part of the tweakey */ + uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_permute_tk(state->TK1); + skinny64_permute_tk(state->TK2); + skinny64_permute_tk(state->TK3); + skinny64_LFSR2(state->TK2[0]); + skinny64_LFSR2(state->TK2[1]); + skinny64_LFSR3(state->TK3[0]); + skinny64_LFSR3(state->TK3[1]); +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_inv_LFSR2(state->TK2[0]); + skinny64_inv_LFSR2(state->TK2[1]); + skinny64_inv_LFSR3(state->TK3[0]); + skinny64_inv_LFSR3(state->TK3[1]); + skinny64_inv_permute_tk(state->TK1); + skinny64_inv_permute_tk(state->TK2); + skinny64_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + skinny64_permute_tk(state.TK1); + skinny64_permute_tk(state.TK2); + skinny64_permute_tk(state.TK3); + skinny64_LFSR2(state.TK2[0]); + skinny64_LFSR2(state.TK2[1]); + skinny64_LFSR3(state.TK3[0]); + skinny64_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_AFTER; ++round) { + skinny64_inv_LFSR2(state.TK2[0]); + skinny64_inv_LFSR2(state.TK2[1]); + skinny64_inv_LFSR3(state.TK3[0]); + skinny64_inv_LFSR3(state.TK3[1]); + skinny64_inv_permute_tk(state.TK1); + skinny64_inv_permute_tk(state.TK2); + skinny64_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} + diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb128t288n104v1/opt32_table/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/api.h new file mode 100644 index 0000000..f04cc58 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 6 +#define CRYPTO_ABYTES 8 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/encrypt.c new file mode 100644 index 0000000..bdc2837 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_64_192_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_64_192_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.c new file mode 100644 index 0000000..c43ef98 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.c @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = { + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, + 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, + 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, + 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, + 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, + 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, + 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, + 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, + 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b, + 0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, + 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10 +}; + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + + +} forkskinny_128_256_key_schedule_t; + +static void forkskinny_128_256_init_tks(forkskinny_128_256_key_schedule_t *ks, const unsigned char key[32], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + } + else{ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + FORKSKINNY_128_256_ROUNDS_AFTER); + } + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_inv_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + //uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + + +} forkskinny_128_384_key_schedule_t; + +static void forkskinny_128_384_init_tks(forkskinny_128_384_key_schedule_t *ks, const unsigned char key[48], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = le_load_word32(key + 32); + TK[1] = le_load_word32(key + 36); + TK[2] = le_load_word32(key + 40); + TK[3] = le_load_word32(key + 44); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR3(TK[0]); + skinny128_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + } + else{ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_inv_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + //uint16_t TK1[4]; /**< First part of the tweakey */ + //uint16_t TK2[4]; /**< Second part of the tweakey */ + //uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint16_t row0[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + uint16_t row1[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + + +} forkskinny_64_192_key_schedule_t; + +static void forkskinny_64_192_init_tks(forkskinny_64_192_key_schedule_t *ks, const unsigned char key[24], uint8_t nb_rounds){ + uint16_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = be_load_word16(key); + TK[1] = be_load_word16(key + 2); + TK[2] = be_load_word16(key + 4); + TK[3] = be_load_word16(key + 6); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny64_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = be_load_word16(key + 8); + TK[1] = be_load_word16(key + 10); + TK[2] = be_load_word16(key + 12); + TK[3] = be_load_word16(key + 14); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR2(TK[0]); + skinny64_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = be_load_word16(key + 16); + TK[1] = be_load_word16(key + 18); + TK[2] = be_load_word16(key + 20); + TK[3] = be_load_word16(key + 22); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR3(TK[0]); + skinny64_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + } + else{ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + FORKSKINNY_64_192_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, &ks, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_dec/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/api.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/api.h new file mode 100644 index 0000000..f04cc58 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 6 +#define CRYPTO_ABYTES 8 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/encrypt.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/encrypt.c new file mode 100644 index 0000000..bdc2837 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_64_192_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_paef_64_192_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.c b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.c new file mode 100644 index 0000000..af29f77 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" +#include + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b,0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10}; + +static const uint32_t T[256] = {0x65656565, 0x4c4c4c4c, 0x6a6a6a6a, 0x42424242, 0x4b4b4b4b, 0x63636363, 0x43434343, 0x6b6b6b6b, 0x55555555, 0x75757575, 0x5a5a5a5a, 0x7a7a7a7a, 0x53535353, 0x73737373, 0x5b5b5b5b, 0x7b7b7b7b, 0x35353535, 0x8c8c8c8c, 0x3a3a3a3a, 0x81818181, 0x89898989, 0x33333333, 0x80808080, 0x3b3b3b3b, 0x95959595, 0x25252525, 0x98989898, 0x2a2a2a2a, 0x90909090, 0x23232323, 0x99999999, 0x2b2b2b2b, 0xe5e5e5e5, 0xcccccccc, 0xe8e8e8e8, 0xc1c1c1c1, 0xc9c9c9c9, 0xe0e0e0e0, 0xc0c0c0c0, 0xe9e9e9e9, 0xd5d5d5d5, 0xf5f5f5f5, 0xd8d8d8d8, 0xf8f8f8f8, 0xd0d0d0d0, 0xf0f0f0f0, 0xd9d9d9d9, 0xf9f9f9f9, 0xa5a5a5a5, 0x1c1c1c1c, 0xa8a8a8a8, 0x12121212, 0x1b1b1b1b, 0xa0a0a0a0, 0x13131313, 0xa9a9a9a9, 0x05050505, 0xb5b5b5b5, 0x0a0a0a0a, 0xb8b8b8b8, 0x03030303, 0xb0b0b0b0, 0x0b0b0b0b, 0xb9b9b9b9, 0x32323232, 0x88888888, 0x3c3c3c3c, 0x85858585, 0x8d8d8d8d, 0x34343434, 0x84848484, 0x3d3d3d3d, 0x91919191, 0x22222222, 0x9c9c9c9c, 0x2c2c2c2c, 0x94949494, 0x24242424, 0x9d9d9d9d, 0x2d2d2d2d, 0x62626262, 0x4a4a4a4a, 0x6c6c6c6c, 0x45454545, 0x4d4d4d4d, 0x64646464, 0x44444444, 0x6d6d6d6d, 0x52525252, 0x72727272, 0x5c5c5c5c, 0x7c7c7c7c, 0x54545454, 0x74747474, 0x5d5d5d5d, 0x7d7d7d7d, 0xa1a1a1a1, 0x1a1a1a1a, 0xacacacac, 0x15151515, 0x1d1d1d1d, 0xa4a4a4a4, 0x14141414, 0xadadadad, 0x02020202, 0xb1b1b1b1, 0x0c0c0c0c, 0xbcbcbcbc, 0x04040404, 0xb4b4b4b4, 0x0d0d0d0d, 0xbdbdbdbd, 0xe1e1e1e1, 0xc8c8c8c8, 0xecececec, 0xc5c5c5c5, 0xcdcdcdcd, 0xe4e4e4e4, 0xc4c4c4c4, 0xedededed, 0xd1d1d1d1, 0xf1f1f1f1, 0xdcdcdcdc, 0xfcfcfcfc, 0xd4d4d4d4, 0xf4f4f4f4, 0xdddddddd, 0xfdfdfdfd, 0x36363636, 0x8e8e8e8e, 0x38383838, 0x82828282, 0x8b8b8b8b, 0x30303030, 0x83838383, 0x39393939, 0x96969696, 0x26262626, 0x9a9a9a9a, 0x28282828, 0x93939393, 0x20202020, 0x9b9b9b9b, 0x29292929, 0x66666666, 0x4e4e4e4e, 0x68686868, 0x41414141, 0x49494949, 0x60606060, 0x40404040, 0x69696969, 0x56565656, 0x76767676, 0x58585858, 0x78787878, 0x50505050, 0x70707070, 0x59595959, 0x79797979, 0xa6a6a6a6, 0x1e1e1e1e, 0xaaaaaaaa, 0x11111111, 0x19191919, 0xa3a3a3a3, 0x10101010, 0xabababab, 0x06060606, 0xb6b6b6b6, 0x08080808, 0xbabababa, 0x00000000, 0xb3b3b3b3, 0x09090909, 0xbbbbbbbb, 0xe6e6e6e6, 0xcececece, 0xeaeaeaea, 0xc2c2c2c2, 0xcbcbcbcb, 0xe3e3e3e3, 0xc3c3c3c3, 0xebebebeb, 0xd6d6d6d6, 0xf6f6f6f6, 0xdadadada, 0xfafafafa, 0xd3d3d3d3, 0xf3f3f3f3, 0xdbdbdbdb, 0xfbfbfbfb, 0x31313131, 0x8a8a8a8a, 0x3e3e3e3e, 0x86868686, 0x8f8f8f8f, 0x37373737, 0x87878787, 0x3f3f3f3f, 0x92929292, 0x21212121, 0x9e9e9e9e, 0x2e2e2e2e, 0x97979797, 0x27272727, 0x9f9f9f9f, 0x2f2f2f2f, 0x61616161, 0x48484848, 0x6e6e6e6e, 0x46464646, 0x4f4f4f4f, 0x67676767, 0x47474747, 0x6f6f6f6f, 0x51515151, 0x71717171, 0x5e5e5e5e, 0x7e7e7e7e, 0x57575757, 0x77777777, 0x5f5f5f5f, 0x7f7f7f7f, 0xa2a2a2a2, 0x18181818, 0xaeaeaeae, 0x16161616, 0x1f1f1f1f, 0xa7a7a7a7, 0x17171717, 0xafafafaf, 0x01010101, 0xb2b2b2b2, 0x0e0e0e0e, 0xbebebebe, 0x07070707, 0xb7b7b7b7, 0x0f0f0f0f, 0xbfbfbfbf, 0xe2e2e2e2, 0xcacacaca, 0xeeeeeeee, 0xc6c6c6c6, 0xcfcfcfcf, 0xe7e7e7e7, 0xc7c7c7c7, 0xefefefef, 0xd2d2d2d2, 0xf2f2f2f2, 0xdededede, 0xfefefefe, 0xd7d7d7d7, 0xf7f7f7f7, 0xdfdfdfdf, 0xffffffff}; +static const uint32_t T_inv[256] = {0xacacacac, 0xe8e8e8e8, 0x68686868, 0x3c3c3c3c, 0x6c6c6c6c, 0x38383838, 0xa8a8a8a8, 0xecececec, 0xaaaaaaaa, 0xaeaeaeae, 0x3a3a3a3a, 0x3e3e3e3e, 0x6a6a6a6a, 0x6e6e6e6e, 0xeaeaeaea, 0xeeeeeeee, 0xa6a6a6a6, 0xa3a3a3a3, 0x33333333, 0x36363636, 0x66666666, 0x63636363, 0xe3e3e3e3, 0xe6e6e6e6, 0xe1e1e1e1, 0xa4a4a4a4, 0x61616161, 0x34343434, 0x31313131, 0x64646464, 0xa1a1a1a1, 0xe4e4e4e4, 0x8d8d8d8d, 0xc9c9c9c9, 0x49494949, 0x1d1d1d1d, 0x4d4d4d4d, 0x19191919, 0x89898989, 0xcdcdcdcd, 0x8b8b8b8b, 0x8f8f8f8f, 0x1b1b1b1b, 0x1f1f1f1f, 0x4b4b4b4b, 0x4f4f4f4f, 0xcbcbcbcb, 0xcfcfcfcf, 0x85858585, 0xc0c0c0c0, 0x40404040, 0x15151515, 0x45454545, 0x10101010, 0x80808080, 0xc5c5c5c5, 0x82828282, 0x87878787, 0x12121212, 0x17171717, 0x42424242, 0x47474747, 0xc2c2c2c2, 0xc7c7c7c7, 0x96969696, 0x93939393, 0x03030303, 0x06060606, 0x56565656, 0x53535353, 0xd3d3d3d3, 0xd6d6d6d6, 0xd1d1d1d1, 0x94949494, 0x51515151, 0x04040404, 0x01010101, 0x54545454, 0x91919191, 0xd4d4d4d4, 0x9c9c9c9c, 0xd8d8d8d8, 0x58585858, 0x0c0c0c0c, 0x5c5c5c5c, 0x08080808, 0x98989898, 0xdcdcdcdc, 0x9a9a9a9a, 0x9e9e9e9e, 0x0a0a0a0a, 0x0e0e0e0e, 0x5a5a5a5a, 0x5e5e5e5e, 0xdadadada, 0xdededede, 0x95959595, 0xd0d0d0d0, 0x50505050, 0x05050505, 0x55555555, 0x00000000, 0x90909090, 0xd5d5d5d5, 0x92929292, 0x97979797, 0x02020202, 0x07070707, 0x52525252, 0x57575757, 0xd2d2d2d2, 0xd7d7d7d7, 0x9d9d9d9d, 0xd9d9d9d9, 0x59595959, 0x0d0d0d0d, 0x5d5d5d5d, 0x09090909, 0x99999999, 0xdddddddd, 0x9b9b9b9b, 0x9f9f9f9f, 0x0b0b0b0b, 0x0f0f0f0f, 0x5b5b5b5b, 0x5f5f5f5f, 0xdbdbdbdb, 0xdfdfdfdf, 0x16161616, 0x13131313, 0x83838383, 0x86868686, 0x46464646, 0x43434343, 0xc3c3c3c3, 0xc6c6c6c6, 0x41414141, 0x14141414, 0xc1c1c1c1, 0x84848484, 0x11111111, 0x44444444, 0x81818181, 0xc4c4c4c4, 0x1c1c1c1c, 0x48484848, 0xc8c8c8c8, 0x8c8c8c8c, 0x4c4c4c4c, 0x18181818, 0x88888888, 0xcccccccc, 0x1a1a1a1a, 0x1e1e1e1e, 0x8a8a8a8a, 0x8e8e8e8e, 0x4a4a4a4a, 0x4e4e4e4e, 0xcacacaca, 0xcececece, 0x35353535, 0x60606060, 0xe0e0e0e0, 0xa5a5a5a5, 0x65656565, 0x30303030, 0xa0a0a0a0, 0xe5e5e5e5, 0x32323232, 0x37373737, 0xa2a2a2a2, 0xa7a7a7a7, 0x62626262, 0x67676767, 0xe2e2e2e2, 0xe7e7e7e7, 0x3d3d3d3d, 0x69696969, 0xe9e9e9e9, 0xadadadad, 0x6d6d6d6d, 0x39393939, 0xa9a9a9a9, 0xedededed, 0x3b3b3b3b, 0x3f3f3f3f, 0xabababab, 0xafafafaf, 0x6b6b6b6b, 0x6f6f6f6f, 0xebebebeb, 0xefefefef, 0x26262626, 0x23232323, 0xb3b3b3b3, 0xb6b6b6b6, 0x76767676, 0x73737373, 0xf3f3f3f3, 0xf6f6f6f6, 0x71717171, 0x24242424, 0xf1f1f1f1, 0xb4b4b4b4, 0x21212121, 0x74747474, 0xb1b1b1b1, 0xf4f4f4f4, 0x2c2c2c2c, 0x78787878, 0xf8f8f8f8, 0xbcbcbcbc, 0x7c7c7c7c, 0x28282828, 0xb8b8b8b8, 0xfcfcfcfc, 0x2a2a2a2a, 0x2e2e2e2e, 0xbabababa, 0xbebebebe, 0x7a7a7a7a, 0x7e7e7e7e, 0xfafafafa, 0xfefefefe, 0x25252525, 0x70707070, 0xf0f0f0f0, 0xb5b5b5b5, 0x75757575, 0x20202020, 0xb0b0b0b0, 0xf5f5f5f5, 0x22222222, 0x27272727, 0xb2b2b2b2, 0xb7b7b7b7, 0x72727272, 0x77777777, 0xf2f2f2f2, 0xf7f7f7f7, 0x2d2d2d2d, 0x79797979, 0xf9f9f9f9, 0xbdbdbdbd, 0x7d7d7d7d, 0x29292929, 0xb9b9b9b9, 0xfdfdfdfd, 0x2b2b2b2b, 0x2f2f2f2f, 0xbbbbbbbb, 0xbfbfbfbf, 0x7b7b7b7b, 0x7f7f7f7f, 0xfbfbfbfb, 0xffffffff}; + +static const uint32_t AC_column0[87] = {0x1000101, 0x3000303, 0x7000707, 0xf000f0f, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x7000707, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x9000909, 0x3000303, 0x7000707, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x5000505, 0xb000b0b, 0x7000707, 0xe000e0e, 0xc000c0c, 0x8000808, 0x0, 0x1000101, 0x3000303, 0x6000606, 0xd000d0d, 0xb000b0b, 0x7000707, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x4000404, 0x9000909, 0x3000303, 0x6000606, 0xc000c0c, 0x8000808, 0x1000101, 0x2000202, 0x5000505, 0xa000a0a, 0x5000505, 0xb000b0b, 0x6000606, 0xc000c0c, 0x8000808, 0x0, 0x0, 0x1000101, 0x2000202, 0x5000505, 0xb000b0b, 0x7000707, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x8000808, 0x1000101, 0x3000303, 0x7000707, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x6000606, 0xd000d0d, 0xb000b0b, 0x6000606, 0xc000c0c, 0x9000909, 0x2000202, 0x4000404, 0x9000909, 0x2000202, 0x5000505, 0xa000a0a, 0x4000404, 0x9000909, 0x2000202, 0x4000404, 0x8000808, 0x0}; +static const uint32_t AC_column1[87] = {0x0, 0x0, 0x0, 0x0, 0x10000, 0x30000, 0x70000, 0x70000, 0x70000, 0x70000, 0x60000, 0x50000, 0x30000, 0x70000, 0x70000, 0x70000, 0x60000, 0x40000, 0x10000, 0x30000, 0x70000, 0x70000, 0x60000, 0x50000, 0x20000, 0x50000, 0x30000, 0x70000, 0x60000, 0x40000, 0x0, 0x0, 0x10000, 0x30000, 0x60000, 0x50000, 0x30000, 0x70000, 0x60000, 0x50000, 0x20000, 0x40000, 0x10000, 0x30000, 0x60000, 0x40000, 0x0, 0x10000, 0x20000, 0x50000, 0x20000, 0x50000, 0x30000, 0x60000, 0x40000, 0x0, 0x0, 0x0, 0x10000, 0x20000, 0x50000, 0x30000, 0x70000, 0x70000, 0x60000, 0x40000, 0x0, 0x10000, 0x30000, 0x70000, 0x60000, 0x50000, 0x30000, 0x60000, 0x50000, 0x30000, 0x60000, 0x40000, 0x10000, 0x20000, 0x40000, 0x10000, 0x20000, 0x50000, 0x20000, 0x40000, 0x10000}; + + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +#define load_column_8(dest, src) \ + do { \ + dest[0] = (src[12]) << 24 | (src[8]) << 16 | (src[4]) << 8 | (src[0]); \ + dest[1] = (src[13]) << 24 | (src[9]) << 16 | (src[5]) << 8 | (src[1]); \ + dest[2] = (src[14]) << 24 | (src[10]) << 16 | (src[6]) << 8 | (src[2]); \ + dest[3] = (src[15]) << 24 | (src[11]) << 16 | (src[7]) << 8 | (src[3]); \ + } while(0) + +#define store_column_8(dest, src) \ + do { \ + dest[0] = (uint8_t) (src[0]); dest[1] = (uint8_t) (src[1]); dest[2] = (uint8_t) (src[2]); dest[3] = (uint8_t) (src[3]); \ + dest[4] = (uint8_t) (src[0]>>8); dest[5] = (uint8_t) (src[1]>>8); dest[6] = (uint8_t) (src[2]>>8); dest[7] = (uint8_t) (src[3]>>8); \ + dest[8] = (uint8_t) (src[0]>>16);dest[9] = (uint8_t) (src[1]>>16);dest[10]= (uint8_t) (src[2]>>16);dest[11]= (uint8_t)(src[3]>>16); \ + dest[12]= (uint8_t) (src[0]>>24);dest[13]= (uint8_t) (src[1]>>24);dest[14]= (uint8_t) (src[2]>>24);dest[15]= (uint8_t)(src[3]>>24); \ + } while(0) + +#define rows_to_columns_32(columns, row0, row1, row2, row3) \ + do { \ + columns[0] = (row3 & 0xFF) << 24|(row2 & 0xFF) << 16|(row1 & 0xFF) << 8 | (row0 & 0xFF);\ + columns[1] = (row3 & 0xFF00) << 16|(row2 & 0xFF00) << 8 |(row1 & 0xFF00) | (row0>>8 & 0xFF);\ + columns[2] = (row3 & 0xFF0000) << 8 |(row2 & 0xFF0000) |(row1 & 0xFF0000) >> 8 | (row0>>16 & 0xFF);\ + columns[3] = (row3 & 0xFF000000) |(row2 & 0xFF000000) >> 8 |(row1 & 0xFF000000) >> 16| (row0>>24 & 0xFF);\ + } while(0) + +#define columns_to_rows_32(rows, column0, column1, column2, column3) rows_to_columns_32(rows, column0, column1, column2, column3) + +#define TK_to_column_256(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1]; \ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_256(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); +} + + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_left, state.S); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + +static void forkskinny_128_256_inv_round_first(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_256_inv_round(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + // temp = 0x020000; + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_256_inv_round_final(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_256_inv_round_first(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER*2)-1); + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_256_inv_round_first(&state, FORKSKINNY_128_256_ROUNDS_BEFORE-1); + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, round); + } + store_column_8(output_right,fstate.S); + +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +#define TK_to_column_384(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1];\ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_384(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + /* Permute TK1, TK2, and TK3 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_permute_tk(state->TK3); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); + skinny128_LFSR3(state->TK3[0]); + skinny128_LFSR3(state->TK3[1]); +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_left, state.S); + + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + + +static void forkskinny_128_384_inv_round_first(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_384_inv_round(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_384_inv_round_final(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_permute_tk(state.TK3); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + skinny128_LFSR3(state.TK3[0]); + skinny128_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_384_inv_round_first(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1); + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_LFSR3(state.TK3[0]); + skinny128_inv_LFSR3(state.TK3[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + skinny128_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + memcpy(fstate.TK3, state.TK3, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_384_inv_round_first(&state, FORKSKINNY_128_384_ROUNDS_BEFORE - 1); + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, round); + } + store_column_8(output_right, fstate.S); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + uint16_t TK1[4]; /**< First part of the tweakey */ + uint16_t TK2[4]; /**< Second part of the tweakey */ + uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_permute_tk(state->TK1); + skinny64_permute_tk(state->TK2); + skinny64_permute_tk(state->TK3); + skinny64_LFSR2(state->TK2[0]); + skinny64_LFSR2(state->TK2[1]); + skinny64_LFSR3(state->TK3[0]); + skinny64_LFSR3(state->TK3[1]); +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_inv_LFSR2(state->TK2[0]); + skinny64_inv_LFSR2(state->TK2[1]); + skinny64_inv_LFSR3(state->TK3[0]); + skinny64_inv_LFSR3(state->TK3[1]); + skinny64_inv_permute_tk(state->TK1); + skinny64_inv_permute_tk(state->TK2); + skinny64_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + skinny64_permute_tk(state.TK1); + skinny64_permute_tk(state.TK2); + skinny64_permute_tk(state.TK3); + skinny64_LFSR2(state.TK2[0]); + skinny64_LFSR2(state.TK2[1]); + skinny64_LFSR3(state.TK3[0]); + skinny64_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_AFTER; ++round) { + skinny64_inv_LFSR2(state.TK2[0]); + skinny64_inv_LFSR2(state.TK2[1]); + skinny64_inv_LFSR3(state.TK3[0]); + skinny64_inv_LFSR3(state.TK3[1]); + skinny64_inv_permute_tk(state.TK1); + skinny64_inv_permute_tk(state.TK2); + skinny64_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} + diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-util.h b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/paefforkskinnyb64t192n48v1/opt32_table/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/api.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/api.h new file mode 100644 index 0000000..40ffe7c --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 7 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/encrypt.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/encrypt.c new file mode 100644 index 0000000..0b25f7e --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_192_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_192_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.c new file mode 100644 index 0000000..c43ef98 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.c @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = { + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, + 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, + 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, + 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, + 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, + 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, + 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, + 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, + 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b, + 0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, + 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10 +}; + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + + +} forkskinny_128_256_key_schedule_t; + +static void forkskinny_128_256_init_tks(forkskinny_128_256_key_schedule_t *ks, const unsigned char key[32], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + } + else{ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + FORKSKINNY_128_256_ROUNDS_AFTER); + } + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_inv_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + //uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + + +} forkskinny_128_384_key_schedule_t; + +static void forkskinny_128_384_init_tks(forkskinny_128_384_key_schedule_t *ks, const unsigned char key[48], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = le_load_word32(key + 32); + TK[1] = le_load_word32(key + 36); + TK[2] = le_load_word32(key + 40); + TK[3] = le_load_word32(key + 44); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR3(TK[0]); + skinny128_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + } + else{ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_inv_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + //uint16_t TK1[4]; /**< First part of the tweakey */ + //uint16_t TK2[4]; /**< Second part of the tweakey */ + //uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint16_t row0[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + uint16_t row1[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + + +} forkskinny_64_192_key_schedule_t; + +static void forkskinny_64_192_init_tks(forkskinny_64_192_key_schedule_t *ks, const unsigned char key[24], uint8_t nb_rounds){ + uint16_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = be_load_word16(key); + TK[1] = be_load_word16(key + 2); + TK[2] = be_load_word16(key + 4); + TK[3] = be_load_word16(key + 6); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny64_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = be_load_word16(key + 8); + TK[1] = be_load_word16(key + 10); + TK[2] = be_load_word16(key + 12); + TK[3] = be_load_word16(key + 14); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR2(TK[0]); + skinny64_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = be_load_word16(key + 16); + TK[1] = be_load_word16(key + 18); + TK[2] = be_load_word16(key + 20); + TK[3] = be_load_word16(key + 22); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR3(TK[0]); + skinny64_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + } + else{ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + FORKSKINNY_64_192_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, &ks, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-util.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_dec/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/api.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/api.h new file mode 100644 index 0000000..40ffe7c --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 7 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/encrypt.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/encrypt.c new file mode 100644 index 0000000..0b25f7e --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_192_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_192_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.c new file mode 100644 index 0000000..af29f77 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" +#include + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b,0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10}; + +static const uint32_t T[256] = {0x65656565, 0x4c4c4c4c, 0x6a6a6a6a, 0x42424242, 0x4b4b4b4b, 0x63636363, 0x43434343, 0x6b6b6b6b, 0x55555555, 0x75757575, 0x5a5a5a5a, 0x7a7a7a7a, 0x53535353, 0x73737373, 0x5b5b5b5b, 0x7b7b7b7b, 0x35353535, 0x8c8c8c8c, 0x3a3a3a3a, 0x81818181, 0x89898989, 0x33333333, 0x80808080, 0x3b3b3b3b, 0x95959595, 0x25252525, 0x98989898, 0x2a2a2a2a, 0x90909090, 0x23232323, 0x99999999, 0x2b2b2b2b, 0xe5e5e5e5, 0xcccccccc, 0xe8e8e8e8, 0xc1c1c1c1, 0xc9c9c9c9, 0xe0e0e0e0, 0xc0c0c0c0, 0xe9e9e9e9, 0xd5d5d5d5, 0xf5f5f5f5, 0xd8d8d8d8, 0xf8f8f8f8, 0xd0d0d0d0, 0xf0f0f0f0, 0xd9d9d9d9, 0xf9f9f9f9, 0xa5a5a5a5, 0x1c1c1c1c, 0xa8a8a8a8, 0x12121212, 0x1b1b1b1b, 0xa0a0a0a0, 0x13131313, 0xa9a9a9a9, 0x05050505, 0xb5b5b5b5, 0x0a0a0a0a, 0xb8b8b8b8, 0x03030303, 0xb0b0b0b0, 0x0b0b0b0b, 0xb9b9b9b9, 0x32323232, 0x88888888, 0x3c3c3c3c, 0x85858585, 0x8d8d8d8d, 0x34343434, 0x84848484, 0x3d3d3d3d, 0x91919191, 0x22222222, 0x9c9c9c9c, 0x2c2c2c2c, 0x94949494, 0x24242424, 0x9d9d9d9d, 0x2d2d2d2d, 0x62626262, 0x4a4a4a4a, 0x6c6c6c6c, 0x45454545, 0x4d4d4d4d, 0x64646464, 0x44444444, 0x6d6d6d6d, 0x52525252, 0x72727272, 0x5c5c5c5c, 0x7c7c7c7c, 0x54545454, 0x74747474, 0x5d5d5d5d, 0x7d7d7d7d, 0xa1a1a1a1, 0x1a1a1a1a, 0xacacacac, 0x15151515, 0x1d1d1d1d, 0xa4a4a4a4, 0x14141414, 0xadadadad, 0x02020202, 0xb1b1b1b1, 0x0c0c0c0c, 0xbcbcbcbc, 0x04040404, 0xb4b4b4b4, 0x0d0d0d0d, 0xbdbdbdbd, 0xe1e1e1e1, 0xc8c8c8c8, 0xecececec, 0xc5c5c5c5, 0xcdcdcdcd, 0xe4e4e4e4, 0xc4c4c4c4, 0xedededed, 0xd1d1d1d1, 0xf1f1f1f1, 0xdcdcdcdc, 0xfcfcfcfc, 0xd4d4d4d4, 0xf4f4f4f4, 0xdddddddd, 0xfdfdfdfd, 0x36363636, 0x8e8e8e8e, 0x38383838, 0x82828282, 0x8b8b8b8b, 0x30303030, 0x83838383, 0x39393939, 0x96969696, 0x26262626, 0x9a9a9a9a, 0x28282828, 0x93939393, 0x20202020, 0x9b9b9b9b, 0x29292929, 0x66666666, 0x4e4e4e4e, 0x68686868, 0x41414141, 0x49494949, 0x60606060, 0x40404040, 0x69696969, 0x56565656, 0x76767676, 0x58585858, 0x78787878, 0x50505050, 0x70707070, 0x59595959, 0x79797979, 0xa6a6a6a6, 0x1e1e1e1e, 0xaaaaaaaa, 0x11111111, 0x19191919, 0xa3a3a3a3, 0x10101010, 0xabababab, 0x06060606, 0xb6b6b6b6, 0x08080808, 0xbabababa, 0x00000000, 0xb3b3b3b3, 0x09090909, 0xbbbbbbbb, 0xe6e6e6e6, 0xcececece, 0xeaeaeaea, 0xc2c2c2c2, 0xcbcbcbcb, 0xe3e3e3e3, 0xc3c3c3c3, 0xebebebeb, 0xd6d6d6d6, 0xf6f6f6f6, 0xdadadada, 0xfafafafa, 0xd3d3d3d3, 0xf3f3f3f3, 0xdbdbdbdb, 0xfbfbfbfb, 0x31313131, 0x8a8a8a8a, 0x3e3e3e3e, 0x86868686, 0x8f8f8f8f, 0x37373737, 0x87878787, 0x3f3f3f3f, 0x92929292, 0x21212121, 0x9e9e9e9e, 0x2e2e2e2e, 0x97979797, 0x27272727, 0x9f9f9f9f, 0x2f2f2f2f, 0x61616161, 0x48484848, 0x6e6e6e6e, 0x46464646, 0x4f4f4f4f, 0x67676767, 0x47474747, 0x6f6f6f6f, 0x51515151, 0x71717171, 0x5e5e5e5e, 0x7e7e7e7e, 0x57575757, 0x77777777, 0x5f5f5f5f, 0x7f7f7f7f, 0xa2a2a2a2, 0x18181818, 0xaeaeaeae, 0x16161616, 0x1f1f1f1f, 0xa7a7a7a7, 0x17171717, 0xafafafaf, 0x01010101, 0xb2b2b2b2, 0x0e0e0e0e, 0xbebebebe, 0x07070707, 0xb7b7b7b7, 0x0f0f0f0f, 0xbfbfbfbf, 0xe2e2e2e2, 0xcacacaca, 0xeeeeeeee, 0xc6c6c6c6, 0xcfcfcfcf, 0xe7e7e7e7, 0xc7c7c7c7, 0xefefefef, 0xd2d2d2d2, 0xf2f2f2f2, 0xdededede, 0xfefefefe, 0xd7d7d7d7, 0xf7f7f7f7, 0xdfdfdfdf, 0xffffffff}; +static const uint32_t T_inv[256] = {0xacacacac, 0xe8e8e8e8, 0x68686868, 0x3c3c3c3c, 0x6c6c6c6c, 0x38383838, 0xa8a8a8a8, 0xecececec, 0xaaaaaaaa, 0xaeaeaeae, 0x3a3a3a3a, 0x3e3e3e3e, 0x6a6a6a6a, 0x6e6e6e6e, 0xeaeaeaea, 0xeeeeeeee, 0xa6a6a6a6, 0xa3a3a3a3, 0x33333333, 0x36363636, 0x66666666, 0x63636363, 0xe3e3e3e3, 0xe6e6e6e6, 0xe1e1e1e1, 0xa4a4a4a4, 0x61616161, 0x34343434, 0x31313131, 0x64646464, 0xa1a1a1a1, 0xe4e4e4e4, 0x8d8d8d8d, 0xc9c9c9c9, 0x49494949, 0x1d1d1d1d, 0x4d4d4d4d, 0x19191919, 0x89898989, 0xcdcdcdcd, 0x8b8b8b8b, 0x8f8f8f8f, 0x1b1b1b1b, 0x1f1f1f1f, 0x4b4b4b4b, 0x4f4f4f4f, 0xcbcbcbcb, 0xcfcfcfcf, 0x85858585, 0xc0c0c0c0, 0x40404040, 0x15151515, 0x45454545, 0x10101010, 0x80808080, 0xc5c5c5c5, 0x82828282, 0x87878787, 0x12121212, 0x17171717, 0x42424242, 0x47474747, 0xc2c2c2c2, 0xc7c7c7c7, 0x96969696, 0x93939393, 0x03030303, 0x06060606, 0x56565656, 0x53535353, 0xd3d3d3d3, 0xd6d6d6d6, 0xd1d1d1d1, 0x94949494, 0x51515151, 0x04040404, 0x01010101, 0x54545454, 0x91919191, 0xd4d4d4d4, 0x9c9c9c9c, 0xd8d8d8d8, 0x58585858, 0x0c0c0c0c, 0x5c5c5c5c, 0x08080808, 0x98989898, 0xdcdcdcdc, 0x9a9a9a9a, 0x9e9e9e9e, 0x0a0a0a0a, 0x0e0e0e0e, 0x5a5a5a5a, 0x5e5e5e5e, 0xdadadada, 0xdededede, 0x95959595, 0xd0d0d0d0, 0x50505050, 0x05050505, 0x55555555, 0x00000000, 0x90909090, 0xd5d5d5d5, 0x92929292, 0x97979797, 0x02020202, 0x07070707, 0x52525252, 0x57575757, 0xd2d2d2d2, 0xd7d7d7d7, 0x9d9d9d9d, 0xd9d9d9d9, 0x59595959, 0x0d0d0d0d, 0x5d5d5d5d, 0x09090909, 0x99999999, 0xdddddddd, 0x9b9b9b9b, 0x9f9f9f9f, 0x0b0b0b0b, 0x0f0f0f0f, 0x5b5b5b5b, 0x5f5f5f5f, 0xdbdbdbdb, 0xdfdfdfdf, 0x16161616, 0x13131313, 0x83838383, 0x86868686, 0x46464646, 0x43434343, 0xc3c3c3c3, 0xc6c6c6c6, 0x41414141, 0x14141414, 0xc1c1c1c1, 0x84848484, 0x11111111, 0x44444444, 0x81818181, 0xc4c4c4c4, 0x1c1c1c1c, 0x48484848, 0xc8c8c8c8, 0x8c8c8c8c, 0x4c4c4c4c, 0x18181818, 0x88888888, 0xcccccccc, 0x1a1a1a1a, 0x1e1e1e1e, 0x8a8a8a8a, 0x8e8e8e8e, 0x4a4a4a4a, 0x4e4e4e4e, 0xcacacaca, 0xcececece, 0x35353535, 0x60606060, 0xe0e0e0e0, 0xa5a5a5a5, 0x65656565, 0x30303030, 0xa0a0a0a0, 0xe5e5e5e5, 0x32323232, 0x37373737, 0xa2a2a2a2, 0xa7a7a7a7, 0x62626262, 0x67676767, 0xe2e2e2e2, 0xe7e7e7e7, 0x3d3d3d3d, 0x69696969, 0xe9e9e9e9, 0xadadadad, 0x6d6d6d6d, 0x39393939, 0xa9a9a9a9, 0xedededed, 0x3b3b3b3b, 0x3f3f3f3f, 0xabababab, 0xafafafaf, 0x6b6b6b6b, 0x6f6f6f6f, 0xebebebeb, 0xefefefef, 0x26262626, 0x23232323, 0xb3b3b3b3, 0xb6b6b6b6, 0x76767676, 0x73737373, 0xf3f3f3f3, 0xf6f6f6f6, 0x71717171, 0x24242424, 0xf1f1f1f1, 0xb4b4b4b4, 0x21212121, 0x74747474, 0xb1b1b1b1, 0xf4f4f4f4, 0x2c2c2c2c, 0x78787878, 0xf8f8f8f8, 0xbcbcbcbc, 0x7c7c7c7c, 0x28282828, 0xb8b8b8b8, 0xfcfcfcfc, 0x2a2a2a2a, 0x2e2e2e2e, 0xbabababa, 0xbebebebe, 0x7a7a7a7a, 0x7e7e7e7e, 0xfafafafa, 0xfefefefe, 0x25252525, 0x70707070, 0xf0f0f0f0, 0xb5b5b5b5, 0x75757575, 0x20202020, 0xb0b0b0b0, 0xf5f5f5f5, 0x22222222, 0x27272727, 0xb2b2b2b2, 0xb7b7b7b7, 0x72727272, 0x77777777, 0xf2f2f2f2, 0xf7f7f7f7, 0x2d2d2d2d, 0x79797979, 0xf9f9f9f9, 0xbdbdbdbd, 0x7d7d7d7d, 0x29292929, 0xb9b9b9b9, 0xfdfdfdfd, 0x2b2b2b2b, 0x2f2f2f2f, 0xbbbbbbbb, 0xbfbfbfbf, 0x7b7b7b7b, 0x7f7f7f7f, 0xfbfbfbfb, 0xffffffff}; + +static const uint32_t AC_column0[87] = {0x1000101, 0x3000303, 0x7000707, 0xf000f0f, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x7000707, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x9000909, 0x3000303, 0x7000707, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x5000505, 0xb000b0b, 0x7000707, 0xe000e0e, 0xc000c0c, 0x8000808, 0x0, 0x1000101, 0x3000303, 0x6000606, 0xd000d0d, 0xb000b0b, 0x7000707, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x4000404, 0x9000909, 0x3000303, 0x6000606, 0xc000c0c, 0x8000808, 0x1000101, 0x2000202, 0x5000505, 0xa000a0a, 0x5000505, 0xb000b0b, 0x6000606, 0xc000c0c, 0x8000808, 0x0, 0x0, 0x1000101, 0x2000202, 0x5000505, 0xb000b0b, 0x7000707, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x8000808, 0x1000101, 0x3000303, 0x7000707, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x6000606, 0xd000d0d, 0xb000b0b, 0x6000606, 0xc000c0c, 0x9000909, 0x2000202, 0x4000404, 0x9000909, 0x2000202, 0x5000505, 0xa000a0a, 0x4000404, 0x9000909, 0x2000202, 0x4000404, 0x8000808, 0x0}; +static const uint32_t AC_column1[87] = {0x0, 0x0, 0x0, 0x0, 0x10000, 0x30000, 0x70000, 0x70000, 0x70000, 0x70000, 0x60000, 0x50000, 0x30000, 0x70000, 0x70000, 0x70000, 0x60000, 0x40000, 0x10000, 0x30000, 0x70000, 0x70000, 0x60000, 0x50000, 0x20000, 0x50000, 0x30000, 0x70000, 0x60000, 0x40000, 0x0, 0x0, 0x10000, 0x30000, 0x60000, 0x50000, 0x30000, 0x70000, 0x60000, 0x50000, 0x20000, 0x40000, 0x10000, 0x30000, 0x60000, 0x40000, 0x0, 0x10000, 0x20000, 0x50000, 0x20000, 0x50000, 0x30000, 0x60000, 0x40000, 0x0, 0x0, 0x0, 0x10000, 0x20000, 0x50000, 0x30000, 0x70000, 0x70000, 0x60000, 0x40000, 0x0, 0x10000, 0x30000, 0x70000, 0x60000, 0x50000, 0x30000, 0x60000, 0x50000, 0x30000, 0x60000, 0x40000, 0x10000, 0x20000, 0x40000, 0x10000, 0x20000, 0x50000, 0x20000, 0x40000, 0x10000}; + + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +#define load_column_8(dest, src) \ + do { \ + dest[0] = (src[12]) << 24 | (src[8]) << 16 | (src[4]) << 8 | (src[0]); \ + dest[1] = (src[13]) << 24 | (src[9]) << 16 | (src[5]) << 8 | (src[1]); \ + dest[2] = (src[14]) << 24 | (src[10]) << 16 | (src[6]) << 8 | (src[2]); \ + dest[3] = (src[15]) << 24 | (src[11]) << 16 | (src[7]) << 8 | (src[3]); \ + } while(0) + +#define store_column_8(dest, src) \ + do { \ + dest[0] = (uint8_t) (src[0]); dest[1] = (uint8_t) (src[1]); dest[2] = (uint8_t) (src[2]); dest[3] = (uint8_t) (src[3]); \ + dest[4] = (uint8_t) (src[0]>>8); dest[5] = (uint8_t) (src[1]>>8); dest[6] = (uint8_t) (src[2]>>8); dest[7] = (uint8_t) (src[3]>>8); \ + dest[8] = (uint8_t) (src[0]>>16);dest[9] = (uint8_t) (src[1]>>16);dest[10]= (uint8_t) (src[2]>>16);dest[11]= (uint8_t)(src[3]>>16); \ + dest[12]= (uint8_t) (src[0]>>24);dest[13]= (uint8_t) (src[1]>>24);dest[14]= (uint8_t) (src[2]>>24);dest[15]= (uint8_t)(src[3]>>24); \ + } while(0) + +#define rows_to_columns_32(columns, row0, row1, row2, row3) \ + do { \ + columns[0] = (row3 & 0xFF) << 24|(row2 & 0xFF) << 16|(row1 & 0xFF) << 8 | (row0 & 0xFF);\ + columns[1] = (row3 & 0xFF00) << 16|(row2 & 0xFF00) << 8 |(row1 & 0xFF00) | (row0>>8 & 0xFF);\ + columns[2] = (row3 & 0xFF0000) << 8 |(row2 & 0xFF0000) |(row1 & 0xFF0000) >> 8 | (row0>>16 & 0xFF);\ + columns[3] = (row3 & 0xFF000000) |(row2 & 0xFF000000) >> 8 |(row1 & 0xFF000000) >> 16| (row0>>24 & 0xFF);\ + } while(0) + +#define columns_to_rows_32(rows, column0, column1, column2, column3) rows_to_columns_32(rows, column0, column1, column2, column3) + +#define TK_to_column_256(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1]; \ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_256(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); +} + + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_left, state.S); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + +static void forkskinny_128_256_inv_round_first(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_256_inv_round(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + // temp = 0x020000; + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_256_inv_round_final(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_256_inv_round_first(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER*2)-1); + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_256_inv_round_first(&state, FORKSKINNY_128_256_ROUNDS_BEFORE-1); + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, round); + } + store_column_8(output_right,fstate.S); + +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +#define TK_to_column_384(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1];\ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_384(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + /* Permute TK1, TK2, and TK3 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_permute_tk(state->TK3); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); + skinny128_LFSR3(state->TK3[0]); + skinny128_LFSR3(state->TK3[1]); +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_left, state.S); + + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + + +static void forkskinny_128_384_inv_round_first(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_384_inv_round(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_384_inv_round_final(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_permute_tk(state.TK3); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + skinny128_LFSR3(state.TK3[0]); + skinny128_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_384_inv_round_first(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1); + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_LFSR3(state.TK3[0]); + skinny128_inv_LFSR3(state.TK3[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + skinny128_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + memcpy(fstate.TK3, state.TK3, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_384_inv_round_first(&state, FORKSKINNY_128_384_ROUNDS_BEFORE - 1); + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, round); + } + store_column_8(output_right, fstate.S); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + uint16_t TK1[4]; /**< First part of the tweakey */ + uint16_t TK2[4]; /**< Second part of the tweakey */ + uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_permute_tk(state->TK1); + skinny64_permute_tk(state->TK2); + skinny64_permute_tk(state->TK3); + skinny64_LFSR2(state->TK2[0]); + skinny64_LFSR2(state->TK2[1]); + skinny64_LFSR3(state->TK3[0]); + skinny64_LFSR3(state->TK3[1]); +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_inv_LFSR2(state->TK2[0]); + skinny64_inv_LFSR2(state->TK2[1]); + skinny64_inv_LFSR3(state->TK3[0]); + skinny64_inv_LFSR3(state->TK3[1]); + skinny64_inv_permute_tk(state->TK1); + skinny64_inv_permute_tk(state->TK2); + skinny64_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + skinny64_permute_tk(state.TK1); + skinny64_permute_tk(state.TK2); + skinny64_permute_tk(state.TK3); + skinny64_LFSR2(state.TK2[0]); + skinny64_LFSR2(state.TK2[1]); + skinny64_LFSR3(state.TK3[0]); + skinny64_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_AFTER; ++round) { + skinny64_inv_LFSR2(state.TK2[0]); + skinny64_inv_LFSR2(state.TK2[1]); + skinny64_inv_LFSR3(state.TK3[0]); + skinny64_inv_LFSR3(state.TK3[1]); + skinny64_inv_permute_tk(state.TK1); + skinny64_inv_permute_tk(state.TK2); + skinny64_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} + diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-util.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t192n56v1/opt32_table/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/api.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/api.h new file mode 100644 index 0000000..86e276c --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 15 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/encrypt.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/encrypt.c new file mode 100644 index 0000000..1faa2d3 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_256_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_256_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.c new file mode 100644 index 0000000..c43ef98 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.c @@ -0,0 +1,1004 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = { + 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, + 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, + 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, + 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, + 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, + 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, + 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, + 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, + 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b, + 0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, + 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10 +}; + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER)]; + + +} forkskinny_128_256_key_schedule_t; + +static void forkskinny_128_256_init_tks(forkskinny_128_256_key_schedule_t *ks, const unsigned char key[32], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + } + else{ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + FORKSKINNY_128_256_ROUNDS_AFTER); + } + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-256 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_inv_round + (forkskinny_128_256_state_t *state, forkskinny_128_256_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + forkskinny_128_256_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_256_init_tks(&ks, key, FORKSKINNY_128_256_ROUNDS_BEFORE + 2*FORKSKINNY_128_256_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_256_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + //uint32_t TK1[4]; /**< First part of the tweakey */ + //uint32_t TK2[4]; /**< Second part of the tweakey */ + //uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint32_t row0[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + uint32_t row1[(FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER)]; + + +} forkskinny_128_384_key_schedule_t; + +static void forkskinny_128_384_init_tks(forkskinny_128_384_key_schedule_t *ks, const unsigned char key[48], uint8_t nb_rounds){ + uint32_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = le_load_word32(key); + TK[1] = le_load_word32(key + 4); + TK[2] = le_load_word32(key + 8); + TK[3] = le_load_word32(key + 12); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny128_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = le_load_word32(key + 16); + TK[1] = le_load_word32(key + 20); + TK[2] = le_load_word32(key + 24); + TK[3] = le_load_word32(key + 28); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR2(TK[0]); + skinny128_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = le_load_word32(key + 32); + TK[1] = le_load_word32(key + 36); + TK[2] = le_load_word32(key + 40); + TK[3] = le_load_word32(key + 44); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny128_permute_tk(TK); + skinny128_LFSR3(TK[0]); + skinny128_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny128_sbox(s0); + skinny128_sbox(s1); + skinny128_sbox(s2); + skinny128_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Shift the cells in the rows right, which moves the cell + * values up closer to the MSB. That is, we do a left rotate + * on the word to rotate the cells in the word right */ + s1 = leftRotate8(s1); + s2 = leftRotate16(s2); + s3 = leftRotate24(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + } + else{ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x08040201U; /* Branching constant */ + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, &ks, round); + } + le_store_word32(output_right, state.S[0]); + le_store_word32(output_right + 4, state.S[1]); + le_store_word32(output_right + 8, state.S[2]); + le_store_word32(output_right + 12, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-128-384 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_inv_round + (forkskinny_128_384_state_t *state, forkskinny_128_384_key_schedule_t *ks, unsigned round) +{ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + s1 = rightRotate8(s1); + s2 = rightRotate16(s2); + s3 = rightRotate24(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ (rc & 0x0F) ^ 0x00020000; + s1 ^= ks->row1[round] ^ (rc >> 4); + s2 ^= 0x02; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + forkskinny_128_384_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_128_384_init_tks(&ks, key, FORKSKINNY_128_384_ROUNDS_BEFORE + 2*FORKSKINNY_128_384_ROUNDS_AFTER); + + /* Unpack the input */ + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_128_384_inv_round(&state, &ks, round - 1); + } + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, &ks, round); + } + le_store_word32(output_right, fstate.S[0]); + le_store_word32(output_right + 4, fstate.S[1]); + le_store_word32(output_right + 8, fstate.S[2]); + le_store_word32(output_right + 12, fstate.S[3]); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + //uint16_t TK1[4]; /**< First part of the tweakey */ + //uint16_t TK2[4]; /**< Second part of the tweakey */ + //uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +typedef struct +{ + /** Words of the full key schedule */ + uint16_t row0[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + uint16_t row1[(FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER)]; + + +} forkskinny_64_192_key_schedule_t; + +static void forkskinny_64_192_init_tks(forkskinny_64_192_key_schedule_t *ks, const unsigned char key[24], uint8_t nb_rounds){ + uint16_t TK[4]; + unsigned round; + + /* Load first Tweakey */ + TK[0] = be_load_word16(key); + TK[1] = be_load_word16(key + 2); + TK[2] = be_load_word16(key + 4); + TK[3] = be_load_word16(key + 6); + /* Initiate key schedule with permutations of TK1 */ + for(round = 0; roundrow0[round] = TK[0]; + ks->row1[round] = TK[1]; + + skinny64_permute_tk(TK); + } + + /* Load second Tweakey */ + TK[0] = be_load_word16(key + 8); + TK[1] = be_load_word16(key + 10); + TK[2] = be_load_word16(key + 12); + TK[3] = be_load_word16(key + 14); + /* Process second Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR2(TK[0]); + skinny64_LFSR2(TK[1]); + } + + /* Load third Tweakey */ + TK[0] = be_load_word16(key + 16); + TK[1] = be_load_word16(key + 18); + TK[2] = be_load_word16(key + 20); + TK[3] = be_load_word16(key + 22); + /* Process third Tweakey and add it to the key schedule */ + for(round = 0; roundrow0[round] ^= TK[0]; + ks->row1[round] ^= TK[1]; + + skinny64_permute_tk(TK); + skinny64_LFSR3(TK[0]); + skinny64_LFSR3(TK[1]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + if (output_left && output_right){ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + } + else{ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + FORKSKINNY_64_192_ROUNDS_AFTER); + } + + /* Unpack the input */ + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, &ks, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, forkskinny_64_192_key_schedule_t *ks, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= ks->row0[round] ^ ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= ks->row1[round] ^ ((rc & 0x70) << 8); + s2 ^= 0x2000; + + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + forkskinny_64_192_key_schedule_t ks; + unsigned round; + + /* Iterate key schedule */ + forkskinny_64_192_init_tks(&ks, key, FORKSKINNY_64_192_ROUNDS_BEFORE + 2*FORKSKINNY_64_192_ROUNDS_AFTER); + + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, &ks, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, &ks, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-util.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_dec/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.c new file mode 100644 index 0000000..84fc53a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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 "aead-common.h" + +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = (accum - 1) >> 8; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} + +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned size, int precheck) +{ + /* Set "accum" to -1 if the tags match, or 0 if they don't match */ + int accum = 0; + while (size > 0) { + accum |= (*tag1++ ^ *tag2++); + --size; + } + accum = ((accum - 1) >> 8) & precheck; + + /* Destroy the plaintext if the tag match failed */ + while (plaintext_len > 0) { + *plaintext++ &= accum; + --plaintext_len; + } + + /* If "accum" is 0, return -1, otherwise return 0 */ + return ~accum; +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.h new file mode 100644 index 0000000..2be95eb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/aead-common.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_AEAD_COMMON_H +#define LWCRYPTO_AEAD_COMMON_H + +#include + +/** + * \file aead-common.h + * \brief Definitions that are common across AEAD schemes. + * + * AEAD stands for "Authenticated Encryption with Associated Data". + * It is a standard API pattern for securely encrypting and + * authenticating packets of data. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts and authenticates a packet with an AEAD scheme. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + */ +typedef int (*aead_cipher_encrypt_t) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with an AEAD scheme. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - normally not used by AEAD schemes. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet. + * \param k Points to the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + */ +typedef int (*aead_cipher_decrypt_t) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Hashes a block of input data. + * + * \param out Buffer to receive the hash output. + * \param in Points to the input data to be hashed. + * \param inlen Length of the input data in bytes. + * + * \return Returns zero on success or -1 if there was an error in the + * parameters. + */ +typedef int (*aead_hash_t) + (unsigned char *out, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Initializes the state for a hashing operation. + * + * \param state Hash state to be initialized. + */ +typedef void (*aead_hash_init_t)(void *state); + +/** + * \brief Updates a hash state with more input data. + * + * \param state Hash state to be updated. + * \param in Points to the input data to be incorporated into the state. + * \param inlen Length of the input data to be incorporated into the state. + */ +typedef void (*aead_hash_update_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Returns the final hash value from a hashing operation. + * + * \param Hash state to be finalized. + * \param out Points to the output buffer to receive the hash value. + */ +typedef void (*aead_hash_finalize_t)(void *state, unsigned char *out); + +/** + * \brief Aborbs more input data into an XOF state. + * + * \param state XOF state to be updated. + * \param in Points to the input data to be absorbed into the state. + * \param inlen Length of the input data to be absorbed into the state. + * + * \sa ascon_xof_init(), ascon_xof_squeeze() + */ +typedef void (*aead_xof_absorb_t) + (void *state, const unsigned char *in, unsigned long long inlen); + +/** + * \brief Squeezes output data from an XOF state. + * + * \param state XOF state to squeeze the output data from. + * \param out Points to the output buffer to receive the squeezed data. + * \param outlen Number of bytes of data to squeeze out of the state. + */ +typedef void (*aead_xof_squeeze_t) + (void *state, unsigned char *out, unsigned long long outlen); + +/** + * \brief No special AEAD features. + */ +#define AEAD_FLAG_NONE 0x0000 + +/** + * \brief The natural byte order of the AEAD cipher is little-endian. + * + * If this flag is not present, then the natural byte order of the + * AEAD cipher should be assumed to be big-endian. + * + * The natural byte order may be useful when formatting packet sequence + * numbers as nonces. The application needs to know whether the sequence + * number should be packed into the leading or trailing bytes of the nonce. + */ +#define AEAD_FLAG_LITTLE_ENDIAN 0x0001 + +/** + * \brief Meta-information about an AEAD cipher. + */ +typedef struct +{ + const char *name; /**< Name of the cipher */ + unsigned key_len; /**< Length of the key in bytes */ + unsigned nonce_len; /**< Length of the nonce in bytes */ + unsigned tag_len; /**< Length of the tag in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_cipher_encrypt_t encrypt; /**< AEAD encryption function */ + aead_cipher_decrypt_t decrypt; /**< AEAD decryption function */ + +} aead_cipher_t; + +/** + * \brief Meta-information about a hash algorithm that is related to an AEAD. + * + * Regular hash algorithms should provide the "hash", "init", "update", + * and "finalize" functions. Extensible Output Functions (XOF's) should + * proivde the "hash", "init", "absorb", and "squeeze" functions. + */ +typedef struct +{ + const char *name; /**< Name of the hash algorithm */ + size_t state_size; /**< Size of the incremental state structure */ + unsigned hash_len; /**< Length of the hash in bytes */ + unsigned flags; /**< Flags for extra features */ + aead_hash_t hash; /**< All in one hashing function */ + aead_hash_init_t init; /**< Incremental hash/XOF init function */ + aead_hash_update_t update; /**< Incremental hash update function */ + aead_hash_finalize_t finalize; /**< Incremental hash finalize function */ + aead_xof_absorb_t absorb; /**< Incremental XOF absorb function */ + aead_xof_squeeze_t squeeze; /**< Incremental XOF squeeze function */ + +} aead_hash_algorithm_t; + +/** + * \brief Check an authentication tag in constant time. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + */ +int aead_check_tag + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len); + +/** + * \brief Check an authentication tag in constant time with a previous check. + * + * \param plaintext Points to the plaintext data. + * \param plaintext_len Length of the plaintext in bytes. + * \param tag1 First tag to compare. + * \param tag2 Second tag to compare. + * \param tag_len Length of the tags in bytes. + * \param precheck Set to -1 if previous check succeeded or 0 if it failed. + * + * \return Returns -1 if the tag check failed or 0 if the check succeeded. + * + * If the tag check fails, then the \a plaintext will also be zeroed to + * prevent it from being used accidentally by the application when the + * ciphertext was invalid. + * + * This version can be used to incorporate other information about the + * correctness of the plaintext into the final result. + */ +int aead_check_tag_precheck + (unsigned char *plaintext, unsigned long long plaintext_len, + const unsigned char *tag1, const unsigned char *tag2, + unsigned tag_len, int precheck); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/api.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/api.h new file mode 100644 index 0000000..86e276c --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/api.h @@ -0,0 +1,5 @@ +#define CRYPTO_KEYBYTES 16 +#define CRYPTO_NSECBYTES 0 +#define CRYPTO_NPUBBYTES 15 +#define CRYPTO_ABYTES 16 +#define CRYPTO_NOOVERLAP 1 diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/encrypt.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/encrypt.c new file mode 100644 index 0000000..1faa2d3 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/encrypt.c @@ -0,0 +1,26 @@ + +#include "forkae.h" + +int crypto_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_256_aead_encrypt + (c, clen, m, mlen, a, adlen, nsec, npub, k); +} + +int crypto_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + return forkae_saef_128_256_aead_decrypt + (m, mlen, nsec, c, clen, ad, adlen, npub, k); +} diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.c new file mode 100644 index 0000000..4a9671a --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2020 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 "forkae.h" +#include "internal-forkskinny.h" +#include "internal-util.h" +#include + +aead_cipher_t const forkae_paef_64_192_cipher = { + "PAEF-ForkSkinny-64-192", + FORKAE_PAEF_64_192_KEY_SIZE, + FORKAE_PAEF_64_192_NONCE_SIZE, + FORKAE_PAEF_64_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_64_192_aead_encrypt, + forkae_paef_64_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_192_cipher = { + "PAEF-ForkSkinny-128-192", + FORKAE_PAEF_128_192_KEY_SIZE, + FORKAE_PAEF_128_192_NONCE_SIZE, + FORKAE_PAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_192_aead_encrypt, + forkae_paef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_256_cipher = { + "PAEF-ForkSkinny-128-256", + FORKAE_PAEF_128_256_KEY_SIZE, + FORKAE_PAEF_128_256_NONCE_SIZE, + FORKAE_PAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_256_aead_encrypt, + forkae_paef_128_256_aead_decrypt +}; + +aead_cipher_t const forkae_paef_128_288_cipher = { + "PAEF-ForkSkinny-128-288", + FORKAE_PAEF_128_288_KEY_SIZE, + FORKAE_PAEF_128_288_NONCE_SIZE, + FORKAE_PAEF_128_288_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_paef_128_288_aead_encrypt, + forkae_paef_128_288_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_192_cipher = { + "SAEF-ForkSkinny-128-192", + FORKAE_SAEF_128_192_KEY_SIZE, + FORKAE_SAEF_128_192_NONCE_SIZE, + FORKAE_SAEF_128_192_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_192_aead_encrypt, + forkae_saef_128_192_aead_decrypt +}; + +aead_cipher_t const forkae_saef_128_256_cipher = { + "SAEF-ForkSkinny-128-256", + FORKAE_SAEF_128_256_KEY_SIZE, + FORKAE_SAEF_128_256_NONCE_SIZE, + FORKAE_SAEF_128_256_TAG_SIZE, + AEAD_FLAG_NONE, + forkae_saef_128_256_aead_encrypt, + forkae_saef_128_256_aead_decrypt +}; + +/* PAEF-ForkSkinny-64-192 */ +#define FORKAE_ALG_NAME forkae_paef_64_192 +#define FORKAE_BLOCK_SIZE 8 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_64_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_64_192 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_paef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_192_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_paef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_256_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 2 +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-paef.h" + +/* PAEF-ForkSkinny-128-288 */ +#define FORKAE_ALG_NAME forkae_paef_128_288 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_PAEF_128_288_NONCE_SIZE +#define FORKAE_COUNTER_SIZE 7 +#define FORKAE_TWEAKEY_SIZE 48 +#define FORKAE_BLOCK_FUNC forkskinny_128_384 +#include "internal-forkae-paef.h" + +/* SAEF-ForkSkinny-128-192 */ +#define FORKAE_ALG_NAME forkae_saef_128_192 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_192_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 24 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" + +/* SAEF-ForkSkinny-128-256 */ +#define FORKAE_ALG_NAME forkae_saef_128_256 +#define FORKAE_BLOCK_SIZE 16 +#define FORKAE_NONCE_SIZE FORKAE_SAEF_128_256_NONCE_SIZE +#define FORKAE_TWEAKEY_SIZE 32 +#define FORKAE_TWEAKEY_REDUCED_SIZE 32 +#define FORKAE_BLOCK_FUNC forkskinny_128_256 +#include "internal-forkae-saef.h" diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.h new file mode 100644 index 0000000..3e27b50 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/forkae.h @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2020 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 LWCRYPTO_FORKAE_H +#define LWCRYPTO_FORKAE_H + +#include "aead-common.h" + +/** + * \file forkae.h + * \brief ForkAE authenticated encryption algorithm family. + * + * ForkAE is a family of authenticated encryption algorithms based on a + * modified version of the SKINNY tweakable block cipher. The modifications + * introduce "forking" where each input block produces two output blocks + * for use in encryption and authentication. There are six members in + * the ForkAE family: + * + * \li PAEF-ForkSkinny-64-192 has a 128-bit key, a 48-bit nonce, and a + * 64-bit authentication tag. The associated data and plaintext are + * limited to 216 bytes. + * \li PAEF-ForkSkinny-128-192 has a 128-bit key, a 48-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-256 has a 128-bit key, a 112-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 217 bytes. + * \li PAEF-ForkSkinny-128-288 has a 128-bit key, a 104-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext are + * limited to 257 bytes. This is the primary member of the family. + * \li SAEF-ForkSkinny-128-192 has a 128-bit key, a 56-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * \li SAEF-ForkSkinny-128-256 has a 128-bit key, a 120-bit nonce, and a + * 128-bit authentication tag. The associated data and plaintext may be + * unlimited in size. + * + * The PAEF variants support parallel encryption and decryption for + * higher throughput. The SAEF variants encrypt or decrypt blocks + * sequentially. + * + * ForkAE is designed to be efficient on small packet sizes so most of + * the PAEF algorithms have a limit of 64k or 128k on the amount of + * payload in a single packet. Obviously the input can be split into + * separate packets for larger amounts of data. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Size of the key for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_TAG_SIZE 8 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-64-192. + */ +#define FORKAE_PAEF_64_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-192. + */ +#define FORKAE_PAEF_128_192_NONCE_SIZE 6 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-256. + */ +#define FORKAE_PAEF_128_256_NONCE_SIZE 14 + +/** + * \brief Size of the key for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_TAG_SIZE 16 + +/** + * \brief Size of the nonce for PAEF-ForkSkinny-128-288. + */ +#define FORKAE_PAEF_128_288_NONCE_SIZE 13 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-192. + */ +#define FORKAE_SAEF_128_192_NONCE_SIZE 7 + +/** + * \brief Size of the key for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_KEY_SIZE 16 + +/** + * \brief Size of the authentication tag for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_TAG_SIZE 16 + +/** + * \brief Size of the nonce for SAEF-ForkSkinny-128-256. + */ +#define FORKAE_SAEF_128_256_NONCE_SIZE 15 + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-64-192 cipher. + */ +extern aead_cipher_t const forkae_paef_64_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_paef_128_192_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_paef_128_256_cipher; + +/** + * \brief Meta-information block for the PAEF-ForkSkinny-128-288 cipher. + */ +extern aead_cipher_t const forkae_paef_128_288_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-192 cipher. + */ +extern aead_cipher_t const forkae_saef_128_192_cipher; + +/** + * \brief Meta-information block for the SAEF-ForkSkinny-128-256 cipher. + */ +extern aead_cipher_t const forkae_saef_128_256_cipher; + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 8 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_64_192_aead_decrypt() + */ +int forkae_paef_64_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-64-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 8 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_64_192_aead_encrypt() + */ +int forkae_paef_64_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_192_aead_decrypt() + */ +int forkae_paef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 6 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_192_aead_encrypt() + */ +int forkae_paef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_256_aead_decrypt() + */ +int forkae_paef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 14 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_256_aead_encrypt() + */ +int forkae_paef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_paef_128_288_aead_decrypt() + */ +int forkae_paef_128_288_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with PAEF-ForkSkinny-128-288. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 13 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_paef_128_288_aead_encrypt() + */ +int forkae_paef_128_288_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_192_aead_decrypt() + */ +int forkae_saef_128_192_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-192. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 7 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_192_aead_encrypt() + */ +int forkae_saef_128_192_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Encrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param c Buffer to receive the output. + * \param clen On exit, set to the length of the output which includes + * the ciphertext and the 16 byte authentication tag. + * \param m Buffer that contains the plaintext message to encrypt. + * \param mlen Length of the plaintext message in bytes. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param nsec Secret nonce - not used by this algorithm. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to encrypt the packet. + * + * \return 0 on success, or a negative value if there was an error in + * the parameters. + * + * \sa forkae_saef_128_256_aead_decrypt() + */ +int forkae_saef_128_256_aead_encrypt + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k); + +/** + * \brief Decrypts and authenticates a packet with SAEF-ForkSkinny-128-256. + * + * \param m Buffer to receive the plaintext message on output. + * \param mlen Receives the length of the plaintext message on output. + * \param nsec Secret nonce - not used by this algorithm. + * \param c Buffer that contains the ciphertext and authentication + * tag to decrypt. + * \param clen Length of the input data in bytes, which includes the + * ciphertext and the 16 byte authentication tag. + * \param ad Buffer that contains associated data to authenticate + * along with the packet but which does not need to be encrypted. + * \param adlen Length of the associated data in bytes. + * \param npub Points to the public nonce for the packet which must + * be 15 bytes in length. + * \param k Points to the 16 bytes of the key to use to decrypt the packet. + * + * \return 0 on success, -1 if the authentication tag was incorrect, + * or some other negative number if there was an error in the parameters. + * + * \sa forkae_saef_128_256_aead_encrypt() + */ +int forkae_saef_128_256_aead_decrypt + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-paef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-paef.h new file mode 100644 index 0000000..6f57b2b --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-paef.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE PAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_paef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_COUNTER_SIZE Size of the counter value for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Limit on the amount of data we can process based on the counter size */ +#define FORKAE_PAEF_DATA_LIMIT \ + ((unsigned long long)((1ULL << (FORKAE_COUNTER_SIZE * 8)) * \ + (FORKAE_BLOCK_SIZE / 8)) - FORKAE_BLOCK_SIZE) + +/* Processes the associated data in PAEF mode */ +STATIC_INLINE void FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter) + (unsigned char tweakey[FORKAE_TWEAKEY_SIZE], + unsigned long long counter, unsigned char domain) +{ + unsigned posn; + counter |= (((unsigned long long)domain) << (FORKAE_COUNTER_SIZE * 8 - 3)); + for (posn = 0; posn < FORKAE_COUNTER_SIZE; ++posn) { + tweakey[16 + FORKAE_NONCE_SIZE + FORKAE_COUNTER_SIZE - 1 - posn] = + (unsigned char)counter; + counter >>= 8; + } +} + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned long long counter; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || mlen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + counter = 1; + while (mlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, m); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, m, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + unsigned long long counter; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Validate the size of the associated data and plaintext as there + * is a limit on the size of the PAEF counter field */ + if (adlen > FORKAE_PAEF_DATA_LIMIT || clen > FORKAE_PAEF_DATA_LIMIT) + return -2; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + + /* Tag value starts at zero. We will XOR this with all of the + * intermediate tag values that are calculated for each block */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + counter = 1; + while (adlen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 0); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + ++counter; + } + if (adlen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 1); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, ad); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + memcpy(block, ad, temp); + block[temp] = 0x80; + memset(block + temp + 1, 0, sizeof(block) - temp - 1); + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 3); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, block, block); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + counter = 1; + while (clen > FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 4); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, c); + lw_xor_block(tag, block, FORKAE_BLOCK_SIZE); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + ++counter; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 5); + lw_xor_block_2_src(m, c, tag, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, m); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, sizeof(tag)); + } else { + unsigned temp = (unsigned)clen; + unsigned char block2[FORKAE_BLOCK_SIZE]; + int check; + FORKAE_CONCAT(FORKAE_ALG_NAME,_set_counter)(tweakey, counter, 7); + lw_xor_block_2_src(block2, tag, c, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, block2, block, block2); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (block2 + temp, FORKAE_BLOCK_SIZE - temp); + memcpy(m, block2, temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE PAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT +#undef FORKAE_PAEF_DATA_LIMIT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-saef.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-saef.h new file mode 100644 index 0000000..768bba4 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkae-saef.h @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2020 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. + */ + +/* We expect a number of macros to be defined before this file + * is included to configure the underlying ForkAE SAEF variant. + * + * FORKAE_ALG_NAME Name of the FORKAE algorithm; e.g. forkae_saef_128_256 + * FORKAE_BLOCK_SIZE Size of the block for the cipher (8 or 16 bytes). + * FORKAE_NONCE_SIZE Size of the nonce for the cipher in bytes. + * FORKAE_TWEAKEY_SIZE Size of the tweakey for the underlying forked cipher. + * FORKAE_REDUCED_TWEAKEY_SIZE Size of the reduced tweakey without padding. + * FORKAE_BLOCK_FUNC Name of the block function; e.g. forkskinny_128_256 + */ +#if defined(FORKAE_ALG_NAME) + +#define FORKAE_CONCAT_INNER(name,suffix) name##suffix +#define FORKAE_CONCAT(name,suffix) FORKAE_CONCAT_INNER(name,suffix) + +/* Check that the last block is padded correctly; -1 if ok, 0 if not */ +STATIC_INLINE int FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (const unsigned char *block, unsigned len) +{ + int check = block[0] ^ 0x80; + while (len > 1) { + --len; + check |= block[len]; + } + return (check - 1) >> 8; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_encrypt) + (unsigned char *c, unsigned long long *clen, + const unsigned char *m, unsigned long long mlen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *nsec, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + (void)nsec; + + /* Set the length of the returned ciphertext */ + *clen = mlen + FORKAE_BLOCK_SIZE; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || mlen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (mlen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || mlen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then generate the tag and we are done */ + if (!mlen) { + memcpy(c, tag, sizeof(tag)); + return 0; + } + + /* Encrypt all plaintext blocks except the last */ + while (mlen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + mlen -= FORKAE_BLOCK_SIZE; + } + + /* Encrypt the last block and generate the final authentication tag */ + if (mlen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, m, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)mlen; + memcpy(block, tag, FORKAE_BLOCK_SIZE); + lw_xor_block(block, m, temp); + block[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, c, block, block); + lw_xor_block(c, tag, FORKAE_BLOCK_SIZE); + memcpy(c + FORKAE_BLOCK_SIZE, block, temp); + } + return 0; +} + +int FORKAE_CONCAT(FORKAE_ALG_NAME,_aead_decrypt) + (unsigned char *m, unsigned long long *mlen, + unsigned char *nsec, + const unsigned char *c, unsigned long long clen, + const unsigned char *ad, unsigned long long adlen, + const unsigned char *npub, + const unsigned char *k) +{ + unsigned char tweakey[FORKAE_TWEAKEY_SIZE]; + unsigned char tag[FORKAE_BLOCK_SIZE]; + unsigned char block[FORKAE_BLOCK_SIZE]; + unsigned char *mtemp = m; + (void)nsec; + + /* Validate the ciphertext length and set the return "mlen" value */ + if (clen < FORKAE_BLOCK_SIZE) + return -1; + clen -= FORKAE_BLOCK_SIZE; + *mlen = clen; + + /* Format the initial tweakey with the key and nonce */ + memcpy(tweakey, k, 16); + memcpy(tweakey + 16, npub, FORKAE_NONCE_SIZE); + memset(tweakey + 16 + FORKAE_NONCE_SIZE, 0, + FORKAE_TWEAKEY_SIZE - 16 - FORKAE_NONCE_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] = 0x08; + + /* Tag value starts at zero */ + memset(tag, 0, sizeof(tag)); + + /* Process the associated data */ + if (adlen > 0 || clen == 0) { + while (adlen > FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + ad += FORKAE_BLOCK_SIZE; + adlen -= FORKAE_BLOCK_SIZE; + } + if (clen == 0) + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x02; + if (adlen == FORKAE_BLOCK_SIZE) { + lw_xor_block(tag, ad, FORKAE_BLOCK_SIZE); + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } else if (adlen != 0 || clen == 0) { + unsigned temp = (unsigned)adlen; + lw_xor_block(tag, ad, temp); + tag[temp] ^= 0x80; + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_encrypt)(tweakey, 0, tag, tag); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + } + } + + /* If there is no message payload, then check the tag and we are done */ + if (!clen) + return aead_check_tag(m, clen, tag, c, sizeof(tag)); + + /* Decrypt all ciphertext blocks except the last */ + while (clen > FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x01; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + memcpy(tag, block, FORKAE_BLOCK_SIZE); + memset(tweakey + 16, 0, FORKAE_TWEAKEY_SIZE - 16); + c += FORKAE_BLOCK_SIZE; + m += FORKAE_BLOCK_SIZE; + clen -= FORKAE_BLOCK_SIZE; + } + + /* Decrypt the last block and check the final authentication tag */ + if (clen == FORKAE_BLOCK_SIZE) { + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x04; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt)(tweakey, m, block, block); + lw_xor_block(m, tag, FORKAE_BLOCK_SIZE); + return aead_check_tag + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, FORKAE_BLOCK_SIZE); + } else { + unsigned temp = (unsigned)clen; + unsigned char mblock[FORKAE_BLOCK_SIZE]; + int check; + lw_xor_block_2_src(block, c, tag, FORKAE_BLOCK_SIZE); + tweakey[FORKAE_TWEAKEY_REDUCED_SIZE - 1] ^= 0x05; + FORKAE_CONCAT(FORKAE_BLOCK_FUNC,_decrypt) + (tweakey, mblock, block, block); + lw_xor_block(mblock, tag, FORKAE_BLOCK_SIZE); + memcpy(m, mblock, temp); + check = FORKAE_CONCAT(FORKAE_ALG_NAME,_is_padding) + (mblock + temp, FORKAE_BLOCK_SIZE - temp); + return aead_check_tag_precheck + (mtemp, *mlen, block, c + FORKAE_BLOCK_SIZE, temp, check); + } +} + +#endif /* FORKAE_ALG_NAME */ + +/* Now undefine everything so that we can include this file again for + * another variant on the ForkAE SAEF algorithm */ +#undef FORKAE_ALG_NAME +#undef FORKAE_BLOCK_SIZE +#undef FORKAE_NONCE_SIZE +#undef FORKAE_COUNTER_SIZE +#undef FORKAE_TWEAKEY_SIZE +#undef FORKAE_TWEAKEY_REDUCED_SIZE +#undef FORKAE_BLOCK_FUNC +#undef FORKAE_CONCAT_INNER +#undef FORKAE_CONCAT diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.c b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.c new file mode 100644 index 0000000..af29f77 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.c @@ -0,0 +1,1052 @@ +/* + * Copyright (C) 2020 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 "internal-forkskinny.h" +#include "internal-skinnyutil.h" +#include + +/** + * \brief 7-bit round constants for all ForkSkinny block ciphers. + */ +static unsigned char const RC[87] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7e, 0x7d, 0x7b, 0x77, 0x6f, 0x5f, 0x3e, 0x7c, 0x79, 0x73, 0x67, 0x4f, 0x1e, 0x3d, 0x7a, 0x75, 0x6b, 0x57, 0x2e, 0x5c, 0x38, 0x70, 0x61, 0x43, 0x06, 0x0d, 0x1b, 0x37, 0x6e, 0x5d, 0x3a, 0x74, 0x69, 0x53, 0x26, 0x4c, 0x18, 0x31, 0x62, 0x45, 0x0a, 0x15, 0x2b, 0x56, 0x2c, 0x58, 0x30, 0x60, 0x41, 0x02, 0x05, 0x0b, 0x17, 0x2f, 0x5e, 0x3c, 0x78, 0x71, 0x63, 0x47, 0x0e, 0x1d, 0x3b, 0x76, 0x6d, 0x5b,0x36, 0x6c, 0x59, 0x32, 0x64, 0x49, 0x12, 0x25, 0x4a, 0x14, 0x29, 0x52, 0x24, 0x48, 0x10}; + +static const uint32_t T[256] = {0x65656565, 0x4c4c4c4c, 0x6a6a6a6a, 0x42424242, 0x4b4b4b4b, 0x63636363, 0x43434343, 0x6b6b6b6b, 0x55555555, 0x75757575, 0x5a5a5a5a, 0x7a7a7a7a, 0x53535353, 0x73737373, 0x5b5b5b5b, 0x7b7b7b7b, 0x35353535, 0x8c8c8c8c, 0x3a3a3a3a, 0x81818181, 0x89898989, 0x33333333, 0x80808080, 0x3b3b3b3b, 0x95959595, 0x25252525, 0x98989898, 0x2a2a2a2a, 0x90909090, 0x23232323, 0x99999999, 0x2b2b2b2b, 0xe5e5e5e5, 0xcccccccc, 0xe8e8e8e8, 0xc1c1c1c1, 0xc9c9c9c9, 0xe0e0e0e0, 0xc0c0c0c0, 0xe9e9e9e9, 0xd5d5d5d5, 0xf5f5f5f5, 0xd8d8d8d8, 0xf8f8f8f8, 0xd0d0d0d0, 0xf0f0f0f0, 0xd9d9d9d9, 0xf9f9f9f9, 0xa5a5a5a5, 0x1c1c1c1c, 0xa8a8a8a8, 0x12121212, 0x1b1b1b1b, 0xa0a0a0a0, 0x13131313, 0xa9a9a9a9, 0x05050505, 0xb5b5b5b5, 0x0a0a0a0a, 0xb8b8b8b8, 0x03030303, 0xb0b0b0b0, 0x0b0b0b0b, 0xb9b9b9b9, 0x32323232, 0x88888888, 0x3c3c3c3c, 0x85858585, 0x8d8d8d8d, 0x34343434, 0x84848484, 0x3d3d3d3d, 0x91919191, 0x22222222, 0x9c9c9c9c, 0x2c2c2c2c, 0x94949494, 0x24242424, 0x9d9d9d9d, 0x2d2d2d2d, 0x62626262, 0x4a4a4a4a, 0x6c6c6c6c, 0x45454545, 0x4d4d4d4d, 0x64646464, 0x44444444, 0x6d6d6d6d, 0x52525252, 0x72727272, 0x5c5c5c5c, 0x7c7c7c7c, 0x54545454, 0x74747474, 0x5d5d5d5d, 0x7d7d7d7d, 0xa1a1a1a1, 0x1a1a1a1a, 0xacacacac, 0x15151515, 0x1d1d1d1d, 0xa4a4a4a4, 0x14141414, 0xadadadad, 0x02020202, 0xb1b1b1b1, 0x0c0c0c0c, 0xbcbcbcbc, 0x04040404, 0xb4b4b4b4, 0x0d0d0d0d, 0xbdbdbdbd, 0xe1e1e1e1, 0xc8c8c8c8, 0xecececec, 0xc5c5c5c5, 0xcdcdcdcd, 0xe4e4e4e4, 0xc4c4c4c4, 0xedededed, 0xd1d1d1d1, 0xf1f1f1f1, 0xdcdcdcdc, 0xfcfcfcfc, 0xd4d4d4d4, 0xf4f4f4f4, 0xdddddddd, 0xfdfdfdfd, 0x36363636, 0x8e8e8e8e, 0x38383838, 0x82828282, 0x8b8b8b8b, 0x30303030, 0x83838383, 0x39393939, 0x96969696, 0x26262626, 0x9a9a9a9a, 0x28282828, 0x93939393, 0x20202020, 0x9b9b9b9b, 0x29292929, 0x66666666, 0x4e4e4e4e, 0x68686868, 0x41414141, 0x49494949, 0x60606060, 0x40404040, 0x69696969, 0x56565656, 0x76767676, 0x58585858, 0x78787878, 0x50505050, 0x70707070, 0x59595959, 0x79797979, 0xa6a6a6a6, 0x1e1e1e1e, 0xaaaaaaaa, 0x11111111, 0x19191919, 0xa3a3a3a3, 0x10101010, 0xabababab, 0x06060606, 0xb6b6b6b6, 0x08080808, 0xbabababa, 0x00000000, 0xb3b3b3b3, 0x09090909, 0xbbbbbbbb, 0xe6e6e6e6, 0xcececece, 0xeaeaeaea, 0xc2c2c2c2, 0xcbcbcbcb, 0xe3e3e3e3, 0xc3c3c3c3, 0xebebebeb, 0xd6d6d6d6, 0xf6f6f6f6, 0xdadadada, 0xfafafafa, 0xd3d3d3d3, 0xf3f3f3f3, 0xdbdbdbdb, 0xfbfbfbfb, 0x31313131, 0x8a8a8a8a, 0x3e3e3e3e, 0x86868686, 0x8f8f8f8f, 0x37373737, 0x87878787, 0x3f3f3f3f, 0x92929292, 0x21212121, 0x9e9e9e9e, 0x2e2e2e2e, 0x97979797, 0x27272727, 0x9f9f9f9f, 0x2f2f2f2f, 0x61616161, 0x48484848, 0x6e6e6e6e, 0x46464646, 0x4f4f4f4f, 0x67676767, 0x47474747, 0x6f6f6f6f, 0x51515151, 0x71717171, 0x5e5e5e5e, 0x7e7e7e7e, 0x57575757, 0x77777777, 0x5f5f5f5f, 0x7f7f7f7f, 0xa2a2a2a2, 0x18181818, 0xaeaeaeae, 0x16161616, 0x1f1f1f1f, 0xa7a7a7a7, 0x17171717, 0xafafafaf, 0x01010101, 0xb2b2b2b2, 0x0e0e0e0e, 0xbebebebe, 0x07070707, 0xb7b7b7b7, 0x0f0f0f0f, 0xbfbfbfbf, 0xe2e2e2e2, 0xcacacaca, 0xeeeeeeee, 0xc6c6c6c6, 0xcfcfcfcf, 0xe7e7e7e7, 0xc7c7c7c7, 0xefefefef, 0xd2d2d2d2, 0xf2f2f2f2, 0xdededede, 0xfefefefe, 0xd7d7d7d7, 0xf7f7f7f7, 0xdfdfdfdf, 0xffffffff}; +static const uint32_t T_inv[256] = {0xacacacac, 0xe8e8e8e8, 0x68686868, 0x3c3c3c3c, 0x6c6c6c6c, 0x38383838, 0xa8a8a8a8, 0xecececec, 0xaaaaaaaa, 0xaeaeaeae, 0x3a3a3a3a, 0x3e3e3e3e, 0x6a6a6a6a, 0x6e6e6e6e, 0xeaeaeaea, 0xeeeeeeee, 0xa6a6a6a6, 0xa3a3a3a3, 0x33333333, 0x36363636, 0x66666666, 0x63636363, 0xe3e3e3e3, 0xe6e6e6e6, 0xe1e1e1e1, 0xa4a4a4a4, 0x61616161, 0x34343434, 0x31313131, 0x64646464, 0xa1a1a1a1, 0xe4e4e4e4, 0x8d8d8d8d, 0xc9c9c9c9, 0x49494949, 0x1d1d1d1d, 0x4d4d4d4d, 0x19191919, 0x89898989, 0xcdcdcdcd, 0x8b8b8b8b, 0x8f8f8f8f, 0x1b1b1b1b, 0x1f1f1f1f, 0x4b4b4b4b, 0x4f4f4f4f, 0xcbcbcbcb, 0xcfcfcfcf, 0x85858585, 0xc0c0c0c0, 0x40404040, 0x15151515, 0x45454545, 0x10101010, 0x80808080, 0xc5c5c5c5, 0x82828282, 0x87878787, 0x12121212, 0x17171717, 0x42424242, 0x47474747, 0xc2c2c2c2, 0xc7c7c7c7, 0x96969696, 0x93939393, 0x03030303, 0x06060606, 0x56565656, 0x53535353, 0xd3d3d3d3, 0xd6d6d6d6, 0xd1d1d1d1, 0x94949494, 0x51515151, 0x04040404, 0x01010101, 0x54545454, 0x91919191, 0xd4d4d4d4, 0x9c9c9c9c, 0xd8d8d8d8, 0x58585858, 0x0c0c0c0c, 0x5c5c5c5c, 0x08080808, 0x98989898, 0xdcdcdcdc, 0x9a9a9a9a, 0x9e9e9e9e, 0x0a0a0a0a, 0x0e0e0e0e, 0x5a5a5a5a, 0x5e5e5e5e, 0xdadadada, 0xdededede, 0x95959595, 0xd0d0d0d0, 0x50505050, 0x05050505, 0x55555555, 0x00000000, 0x90909090, 0xd5d5d5d5, 0x92929292, 0x97979797, 0x02020202, 0x07070707, 0x52525252, 0x57575757, 0xd2d2d2d2, 0xd7d7d7d7, 0x9d9d9d9d, 0xd9d9d9d9, 0x59595959, 0x0d0d0d0d, 0x5d5d5d5d, 0x09090909, 0x99999999, 0xdddddddd, 0x9b9b9b9b, 0x9f9f9f9f, 0x0b0b0b0b, 0x0f0f0f0f, 0x5b5b5b5b, 0x5f5f5f5f, 0xdbdbdbdb, 0xdfdfdfdf, 0x16161616, 0x13131313, 0x83838383, 0x86868686, 0x46464646, 0x43434343, 0xc3c3c3c3, 0xc6c6c6c6, 0x41414141, 0x14141414, 0xc1c1c1c1, 0x84848484, 0x11111111, 0x44444444, 0x81818181, 0xc4c4c4c4, 0x1c1c1c1c, 0x48484848, 0xc8c8c8c8, 0x8c8c8c8c, 0x4c4c4c4c, 0x18181818, 0x88888888, 0xcccccccc, 0x1a1a1a1a, 0x1e1e1e1e, 0x8a8a8a8a, 0x8e8e8e8e, 0x4a4a4a4a, 0x4e4e4e4e, 0xcacacaca, 0xcececece, 0x35353535, 0x60606060, 0xe0e0e0e0, 0xa5a5a5a5, 0x65656565, 0x30303030, 0xa0a0a0a0, 0xe5e5e5e5, 0x32323232, 0x37373737, 0xa2a2a2a2, 0xa7a7a7a7, 0x62626262, 0x67676767, 0xe2e2e2e2, 0xe7e7e7e7, 0x3d3d3d3d, 0x69696969, 0xe9e9e9e9, 0xadadadad, 0x6d6d6d6d, 0x39393939, 0xa9a9a9a9, 0xedededed, 0x3b3b3b3b, 0x3f3f3f3f, 0xabababab, 0xafafafaf, 0x6b6b6b6b, 0x6f6f6f6f, 0xebebebeb, 0xefefefef, 0x26262626, 0x23232323, 0xb3b3b3b3, 0xb6b6b6b6, 0x76767676, 0x73737373, 0xf3f3f3f3, 0xf6f6f6f6, 0x71717171, 0x24242424, 0xf1f1f1f1, 0xb4b4b4b4, 0x21212121, 0x74747474, 0xb1b1b1b1, 0xf4f4f4f4, 0x2c2c2c2c, 0x78787878, 0xf8f8f8f8, 0xbcbcbcbc, 0x7c7c7c7c, 0x28282828, 0xb8b8b8b8, 0xfcfcfcfc, 0x2a2a2a2a, 0x2e2e2e2e, 0xbabababa, 0xbebebebe, 0x7a7a7a7a, 0x7e7e7e7e, 0xfafafafa, 0xfefefefe, 0x25252525, 0x70707070, 0xf0f0f0f0, 0xb5b5b5b5, 0x75757575, 0x20202020, 0xb0b0b0b0, 0xf5f5f5f5, 0x22222222, 0x27272727, 0xb2b2b2b2, 0xb7b7b7b7, 0x72727272, 0x77777777, 0xf2f2f2f2, 0xf7f7f7f7, 0x2d2d2d2d, 0x79797979, 0xf9f9f9f9, 0xbdbdbdbd, 0x7d7d7d7d, 0x29292929, 0xb9b9b9b9, 0xfdfdfdfd, 0x2b2b2b2b, 0x2f2f2f2f, 0xbbbbbbbb, 0xbfbfbfbf, 0x7b7b7b7b, 0x7f7f7f7f, 0xfbfbfbfb, 0xffffffff}; + +static const uint32_t AC_column0[87] = {0x1000101, 0x3000303, 0x7000707, 0xf000f0f, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x7000707, 0xf000f0f, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x9000909, 0x3000303, 0x7000707, 0xf000f0f, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x5000505, 0xb000b0b, 0x7000707, 0xe000e0e, 0xc000c0c, 0x8000808, 0x0, 0x1000101, 0x3000303, 0x6000606, 0xd000d0d, 0xb000b0b, 0x7000707, 0xe000e0e, 0xd000d0d, 0xa000a0a, 0x4000404, 0x9000909, 0x3000303, 0x6000606, 0xc000c0c, 0x8000808, 0x1000101, 0x2000202, 0x5000505, 0xa000a0a, 0x5000505, 0xb000b0b, 0x6000606, 0xc000c0c, 0x8000808, 0x0, 0x0, 0x1000101, 0x2000202, 0x5000505, 0xb000b0b, 0x7000707, 0xf000f0f, 0xe000e0e, 0xc000c0c, 0x8000808, 0x1000101, 0x3000303, 0x7000707, 0xe000e0e, 0xd000d0d, 0xb000b0b, 0x6000606, 0xd000d0d, 0xb000b0b, 0x6000606, 0xc000c0c, 0x9000909, 0x2000202, 0x4000404, 0x9000909, 0x2000202, 0x5000505, 0xa000a0a, 0x4000404, 0x9000909, 0x2000202, 0x4000404, 0x8000808, 0x0}; +static const uint32_t AC_column1[87] = {0x0, 0x0, 0x0, 0x0, 0x10000, 0x30000, 0x70000, 0x70000, 0x70000, 0x70000, 0x60000, 0x50000, 0x30000, 0x70000, 0x70000, 0x70000, 0x60000, 0x40000, 0x10000, 0x30000, 0x70000, 0x70000, 0x60000, 0x50000, 0x20000, 0x50000, 0x30000, 0x70000, 0x60000, 0x40000, 0x0, 0x0, 0x10000, 0x30000, 0x60000, 0x50000, 0x30000, 0x70000, 0x60000, 0x50000, 0x20000, 0x40000, 0x10000, 0x30000, 0x60000, 0x40000, 0x0, 0x10000, 0x20000, 0x50000, 0x20000, 0x50000, 0x30000, 0x60000, 0x40000, 0x0, 0x0, 0x0, 0x10000, 0x20000, 0x50000, 0x30000, 0x70000, 0x70000, 0x60000, 0x40000, 0x0, 0x10000, 0x30000, 0x70000, 0x60000, 0x50000, 0x30000, 0x60000, 0x50000, 0x30000, 0x60000, 0x40000, 0x10000, 0x20000, 0x40000, 0x10000, 0x20000, 0x50000, 0x20000, 0x40000, 0x10000}; + + +/** + * \brief Number of rounds of ForkSkinny-128-256 before forking. + */ +#define FORKSKINNY_128_256_ROUNDS_BEFORE 21 + +/** + * \brief Number of rounds of ForkSkinny-128-256 after forking. + */ +#define FORKSKINNY_128_256_ROUNDS_AFTER 27 + +/** + * \brief State information for ForkSkinny-128-256. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_256_state_t; + +#define load_column_8(dest, src) \ + do { \ + dest[0] = (src[12]) << 24 | (src[8]) << 16 | (src[4]) << 8 | (src[0]); \ + dest[1] = (src[13]) << 24 | (src[9]) << 16 | (src[5]) << 8 | (src[1]); \ + dest[2] = (src[14]) << 24 | (src[10]) << 16 | (src[6]) << 8 | (src[2]); \ + dest[3] = (src[15]) << 24 | (src[11]) << 16 | (src[7]) << 8 | (src[3]); \ + } while(0) + +#define store_column_8(dest, src) \ + do { \ + dest[0] = (uint8_t) (src[0]); dest[1] = (uint8_t) (src[1]); dest[2] = (uint8_t) (src[2]); dest[3] = (uint8_t) (src[3]); \ + dest[4] = (uint8_t) (src[0]>>8); dest[5] = (uint8_t) (src[1]>>8); dest[6] = (uint8_t) (src[2]>>8); dest[7] = (uint8_t) (src[3]>>8); \ + dest[8] = (uint8_t) (src[0]>>16);dest[9] = (uint8_t) (src[1]>>16);dest[10]= (uint8_t) (src[2]>>16);dest[11]= (uint8_t)(src[3]>>16); \ + dest[12]= (uint8_t) (src[0]>>24);dest[13]= (uint8_t) (src[1]>>24);dest[14]= (uint8_t) (src[2]>>24);dest[15]= (uint8_t)(src[3]>>24); \ + } while(0) + +#define rows_to_columns_32(columns, row0, row1, row2, row3) \ + do { \ + columns[0] = (row3 & 0xFF) << 24|(row2 & 0xFF) << 16|(row1 & 0xFF) << 8 | (row0 & 0xFF);\ + columns[1] = (row3 & 0xFF00) << 16|(row2 & 0xFF00) << 8 |(row1 & 0xFF00) | (row0>>8 & 0xFF);\ + columns[2] = (row3 & 0xFF0000) << 8 |(row2 & 0xFF0000) |(row1 & 0xFF0000) >> 8 | (row0>>16 & 0xFF);\ + columns[3] = (row3 & 0xFF000000) |(row2 & 0xFF000000) >> 8 |(row1 & 0xFF000000) >> 16| (row0>>24 & 0xFF);\ + } while(0) + +#define columns_to_rows_32(rows, column0, column1, column2, column3) rows_to_columns_32(rows, column0, column1, column2, column3) + +#define TK_to_column_256(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1]; \ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-256. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_256_round + (forkskinny_128_256_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_256(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); +} + + +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_BEFORE; ++round) { + forkskinny_128_256_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_left, state.S); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + +static void forkskinny_128_256_inv_round_first(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_256_inv_round(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + // temp = 0x020000; + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_256_inv_round_final(forkskinny_128_256_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_256_state_t state; + forkskinny_128_256_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_256_inv_round_first(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER*2)-1); + for (round = (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, (FORKSKINNY_128_256_ROUNDS_BEFORE+FORKSKINNY_128_256_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_256_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_256_inv_round_first(&state, FORKSKINNY_128_256_ROUNDS_BEFORE-1); + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_256_inv_round(&state, round - 1); + } + forkskinny_128_256_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + + for (round = FORKSKINNY_128_256_ROUNDS_BEFORE; + round < (FORKSKINNY_128_256_ROUNDS_BEFORE + + FORKSKINNY_128_256_ROUNDS_AFTER); ++round) { + forkskinny_128_256_round(&fstate, round); + } + store_column_8(output_right,fstate.S); + +} + +/** + * \brief Number of rounds of ForkSkinny-128-384 before forking. + */ +#define FORKSKINNY_128_384_ROUNDS_BEFORE 25 + +/** + * \brief Number of rounds of ForkSkinny-128-384 after forking. + */ +#define FORKSKINNY_128_384_ROUNDS_AFTER 31 + +/** + * \brief State information for ForkSkinny-128-384. + */ +typedef struct +{ + uint32_t TK1[4]; /**< First part of the tweakey */ + uint32_t TK2[4]; /**< Second part of the tweakey */ + uint32_t TK3[4]; /**< Third part of the tweakey */ + uint32_t S[4]; /**< Current block state */ + +} forkskinny_128_384_state_t; + +#define TK_to_column_384(columns, state) \ + do { \ + uint32_t TK0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0];\ + uint32_t TK1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1];\ + uint32_t tk00 = TK0 & 0xFF; \ + uint32_t tk01 = TK0 & 0xFF00;\ + uint32_t tk02 = TK0 & 0xFF0000;\ + uint32_t tk03 = TK0 & 0xFF000000;\ + columns[0] = tk00 << 24 | (TK1 & 0xFF000000) >> 8 | tk00 << 8 | tk00; \ + columns[1] = tk01 << 16 | (TK1 & 0xFF) << 16 | tk01 | tk01 >> 8; \ + columns[2] = tk02 << 8 | (TK1 & 0xFF00) << 8 | tk02 >> 8 | tk02 >> 16; \ + columns[3] = tk03 | (TK1 & 0xFF0000) | tk03 >> 16 | tk03 >> 24; \ + } while(0) + +/** + * \brief Applies one round of ForkSkinny-128-384. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_128_384_round + (forkskinny_128_384_state_t *state, unsigned round) +{ + uint32_t s0, s1, s2, s3; + uint32_t tk_columns[4]; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + TK_to_column_384(tk_columns, state); + + state->S[0] = (T[s0 & 0xff]&0xff00ffff) ^ (T[(s3>>8) & 0xff]&0x00ff0000) ^ (T[(s2>>16) & 0xff]&0xffff00ff) ^ (T[(s1>>24)]&0xff) ^ tk_columns[0] ^ AC_column0[round]; + state->S[1] = (T[s1 & 0xff]&0xff00ffff) ^ (T[(s0>>8) & 0xff]&0x00ff0000) ^ (T[(s3>>16) & 0xff]&0xffff00ff) ^ (T[(s2>>24)]&0xff) ^ tk_columns[1] ^ AC_column1[round]; + state->S[2] = (T[s2 & 0xff]&0xff00ffff) ^ (T[(s1>>8) & 0xff]&0x00ff0000) ^ (T[(s0>>16) & 0xff]&0xffff00ff) ^ (T[(s3>>24)]&0xff) ^ tk_columns[2] ^ 0x00020200; + state->S[3] = (T[s3 & 0xff]&0xff00ffff) ^ (T[(s2>>8) & 0xff]&0x00ff0000) ^ (T[(s1>>16) & 0xff]&0xffff00ff) ^ (T[(s0>>24)]&0xff) ^ tk_columns[3]; + /* Permute TK1, TK2, and TK3 for the next round */ + skinny128_permute_tk(state->TK1); + skinny128_permute_tk(state->TK2); + skinny128_permute_tk(state->TK3); + skinny128_LFSR2(state->TK2[0]); + skinny128_LFSR2(state->TK2[1]); + skinny128_LFSR3(state->TK3[0]); + skinny128_LFSR3(state->TK3[1]); +} + +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + + /* State stored per column */ + load_column_8(state.S, input); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_BEFORE; ++round) { + forkskinny_128_384_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint32_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x51051001; /* Branching constant */ + state.S[1] ^= 0xa20a2002; + state.S[2] ^= 0x44144104; + state.S[3] ^= 0x88288208; + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_left, state.S); + + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&state, round); + } + store_column_8(output_right, state.S); + } +} + + +static void forkskinny_128_384_inv_round_first(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + temp = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + s1 ^= leftRotate8(temp); + s2 ^= 0x020000; + + /* Save the local variables back to the state but first convert them to columns*/ + rows_to_columns_32(state->S, s0, s1, s2, s3); +} + +static void forkskinny_128_384_inv_round(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3, tk0, tk1; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1 and TK2 for the next round */ + skinny128_inv_LFSR2(state->TK2[0]); + skinny128_inv_LFSR2(state->TK2[1]); + skinny128_inv_LFSR3(state->TK3[0]); + skinny128_inv_LFSR3(state->TK3[1]); + skinny128_inv_permute_tk(state->TK1); + skinny128_inv_permute_tk(state->TK2); + skinny128_inv_permute_tk(state->TK3); + + + state->S[0] = (T_inv[s0 & 0xff]&0xff000000) ^ (T_inv[(s1>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s2>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s3>>24)]&0xffffff00); + state->S[1] = (T_inv[s1 & 0xff]&0xff000000) ^ (T_inv[(s2>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s3>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s0>>24)]&0xffffff00); + state->S[2] = (T_inv[s2 & 0xff]&0xff000000) ^ (T_inv[(s3>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s0>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s1>>24)]&0xffffff00); + state->S[3] = (T_inv[s3 & 0xff]&0xff000000) ^ (T_inv[(s0>>8) & 0xff]&0x00ffffff) ^ (T_inv[(s1>>16) & 0xff]&0x0000ff00) ^ (T_inv[(s2>>24)]&0xffffff00); + + /* XOR the shifted round constant and the shifted subkey for this round */ + rc = RC[round]; + tk0 = state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ (rc & 0x0F) ^ 0x00020000; + tk1 = state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ (rc >> 4); + tk1 = leftRotate8(tk1); + + state->S[0] ^= (((tk0) &0xff) | ((tk1<<8)&0xff00)); + state->S[1] ^= (((tk0>>8) &0xff) | ((tk1)&0xff00)); + state->S[2] ^= (((tk0>>16)&0xff) | ((tk1>>8)&0xff00)) ^ 0x020000; + state->S[3] ^= (((tk0>>24)&0xff) | ((tk1>>16)&0xff00)); +} + +static void forkskinny_128_384_inv_round_final(forkskinny_128_384_state_t *state, unsigned round){ + uint32_t s0, s1, s2, s3; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny128_inv_sbox(s0); + skinny128_inv_sbox(s1); + skinny128_inv_sbox(s2); + skinny128_inv_sbox(s3); + + /* Save the local variables back to the state but first convert them back to rows*/ + columns_to_rows_32(state->S, s0, s1, s2, s3); + + /* Shift the cells in the rows left, which moves the cell + * values down closer to the LSB. That is, we do a right + * rotate on the word to rotate the cells in the word left */ + state->S[1] = rightRotate8(state->S[1]); + state->S[2] = rightRotate16(state->S[2]); + state->S[3] = rightRotate24(state->S[3]); +} + +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_128_384_state_t state; + forkskinny_128_384_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = le_load_word32(key); + state.TK1[1] = le_load_word32(key + 4); + state.TK1[2] = le_load_word32(key + 8); + state.TK1[3] = le_load_word32(key + 12); + state.TK2[0] = le_load_word32(key + 16); + state.TK2[1] = le_load_word32(key + 20); + state.TK2[2] = le_load_word32(key + 24); + state.TK2[3] = le_load_word32(key + 28); + state.TK3[0] = le_load_word32(key + 32); + state.TK3[1] = le_load_word32(key + 36); + state.TK3[2] = le_load_word32(key + 40); + state.TK3[3] = le_load_word32(key + 44); + state.S[0] = le_load_word32(input); + state.S[1] = le_load_word32(input + 4); + state.S[2] = le_load_word32(input + 8); + state.S[3] = le_load_word32(input + 12); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2); ++round) { + skinny128_permute_tk(state.TK1); + skinny128_permute_tk(state.TK2); + skinny128_permute_tk(state.TK3); + skinny128_LFSR2(state.TK2[0]); + skinny128_LFSR2(state.TK2[1]); + skinny128_LFSR3(state.TK3[0]); + skinny128_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + forkskinny_128_384_inv_round_first(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1); + for (round = (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER * 2)-1; + round > (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, (FORKSKINNY_128_384_ROUNDS_BEFORE + FORKSKINNY_128_384_ROUNDS_AFTER)); + + /* Remove the branching constant */ + state.S[0] ^= 0x08040201U; + state.S[1] ^= 0x82412010U; + state.S[2] ^= 0x28140a05U; + state.S[3] ^= 0x8844a251U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_128_384_ROUNDS_AFTER; ++round) { + skinny128_inv_LFSR2(state.TK2[0]); + skinny128_inv_LFSR2(state.TK2[1]); + skinny128_inv_LFSR3(state.TK3[0]); + skinny128_inv_LFSR3(state.TK3[1]); + skinny128_inv_permute_tk(state.TK1); + skinny128_inv_permute_tk(state.TK2); + skinny128_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point, convert state to columns */ + memcpy(fstate.TK1, state.TK1, 16); + memcpy(fstate.TK2, state.TK2, 16); + memcpy(fstate.TK3, state.TK3, 16); + rows_to_columns_32(fstate.S,state.S[0],state.S[1], state.S[2], state.S[3]); + + /* Generate the left output block after another "before" rounds */ + forkskinny_128_384_inv_round_first(&state, FORKSKINNY_128_384_ROUNDS_BEFORE - 1); + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE-1; round > 0; --round) { + forkskinny_128_384_inv_round(&state, round - 1); + } + forkskinny_128_384_inv_round_final(&state, 0); + + le_store_word32(output_left, state.S[0]); + le_store_word32(output_left + 4, state.S[1]); + le_store_word32(output_left + 8, state.S[2]); + le_store_word32(output_left + 12, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_128_384_ROUNDS_BEFORE; + round < (FORKSKINNY_128_384_ROUNDS_BEFORE + + FORKSKINNY_128_384_ROUNDS_AFTER); ++round) { + forkskinny_128_384_round(&fstate, round); + } + store_column_8(output_right, fstate.S); +} + +/** + * \brief Number of rounds of ForkSkinny-64-192 before forking. + */ +#define FORKSKINNY_64_192_ROUNDS_BEFORE 17 + +/** + * \brief Number of rounds of ForkSkinny-64-192 after forking. + */ +#define FORKSKINNY_64_192_ROUNDS_AFTER 23 + +/** + * \brief State information for ForkSkinny-64-192. + */ +typedef struct +{ + uint16_t TK1[4]; /**< First part of the tweakey */ + uint16_t TK2[4]; /**< Second part of the tweakey */ + uint16_t TK3[4]; /**< Third part of the tweakey */ + uint16_t S[4]; /**< Current block state */ + +} forkskinny_64_192_state_t; + +/** + * \brief Applies one round of ForkSkinny-64-192. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + * + * Note: The cells of each row are order in big-endian nibble order + * so it is easiest to manage the rows in bit-endian byte order. + */ +static void forkskinny_64_192_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Apply the S-box to all cells in the state */ + skinny64_sbox(s0); + skinny64_sbox(s1); + skinny64_sbox(s2); + skinny64_sbox(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Shift the cells in the rows right */ + s1 = rightRotate4_16(s1); + s2 = rightRotate8_16(s2); + s3 = rightRotate12_16(s3); + + /* Mix the columns */ + s1 ^= s2; + s2 ^= s0; + temp = s3 ^ s2; + s3 = s2; + s2 = s1; + s1 = s0; + s0 = temp; + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_permute_tk(state->TK1); + skinny64_permute_tk(state->TK2); + skinny64_permute_tk(state->TK3); + skinny64_LFSR2(state->TK2[0]); + skinny64_LFSR2(state->TK2[1]); + skinny64_LFSR3(state->TK3[0]); + skinny64_LFSR3(state->TK3[1]); +} + +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Run all of the rounds before the forking point */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_BEFORE; ++round) { + forkskinny_64_192_round(&state, round); + } + + /* Determine which output blocks we need */ + if (output_left && output_right) { + /* We need both outputs so save the state at the forking point */ + uint16_t F[4]; + F[0] = state.S[0]; + F[1] = state.S[1]; + F[2] = state.S[2]; + F[3] = state.S[3]; + + /* Generate the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + + /* Restore the state at the forking point */ + state.S[0] = F[0]; + state.S[1] = F[1]; + state.S[2] = F[2]; + state.S[3] = F[3]; + } + if (output_left) { + /* Generate the left output block */ + state.S[0] ^= 0x1249U; /* Branching constant */ + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + } else { + /* We only need the right output block */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&state, round); + } + be_store_word16(output_right, state.S[0]); + be_store_word16(output_right + 2, state.S[1]); + be_store_word16(output_right + 4, state.S[2]); + be_store_word16(output_right + 6, state.S[3]); + } +} + +/** + * \brief Applies one round of ForkSkinny-64-192 in reverse. + * + * \param state State to apply the round to. + * \param round Number of the round to apply. + */ +static void forkskinny_64_192_inv_round + (forkskinny_64_192_state_t *state, unsigned round) +{ + uint16_t s0, s1, s2, s3, temp; + uint8_t rc; + + /* Load the state into local variables */ + s0 = state->S[0]; + s1 = state->S[1]; + s2 = state->S[2]; + s3 = state->S[3]; + + /* Permute TK1, TK2, and TK3 for the next round */ + skinny64_inv_LFSR2(state->TK2[0]); + skinny64_inv_LFSR2(state->TK2[1]); + skinny64_inv_LFSR3(state->TK3[0]); + skinny64_inv_LFSR3(state->TK3[1]); + skinny64_inv_permute_tk(state->TK1); + skinny64_inv_permute_tk(state->TK2); + skinny64_inv_permute_tk(state->TK3); + + /* Inverse mix of the columns */ + temp = s0; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = temp ^ s2; + s2 ^= s0; + s1 ^= s2; + + /* Shift the cells in the rows left */ + s1 = leftRotate4_16(s1); + s2 = leftRotate8_16(s2); + s3 = leftRotate12_16(s3); + + /* XOR the round constant and the subkey for this round */ + rc = RC[round]; + s0 ^= state->TK1[0] ^ state->TK2[0] ^ state->TK3[0] ^ + ((rc & 0x0F) << 12) ^ 0x0020; + s1 ^= state->TK1[1] ^ state->TK2[1] ^ state->TK3[1] ^ + ((rc & 0x70) << 8); + s2 ^= 0x2000; + + /* Apply the inverse of the S-box to all cells in the state */ + skinny64_inv_sbox(s0); + skinny64_inv_sbox(s1); + skinny64_inv_sbox(s2); + skinny64_inv_sbox(s3); + + /* Save the local variables back to the state */ + state->S[0] = s0; + state->S[1] = s1; + state->S[2] = s2; + state->S[3] = s3; +} + +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input) +{ + forkskinny_64_192_state_t state; + forkskinny_64_192_state_t fstate; + unsigned round; + + /* Unpack the tweakey and the input */ + state.TK1[0] = be_load_word16(key); + state.TK1[1] = be_load_word16(key + 2); + state.TK1[2] = be_load_word16(key + 4); + state.TK1[3] = be_load_word16(key + 6); + state.TK2[0] = be_load_word16(key + 8); + state.TK2[1] = be_load_word16(key + 10); + state.TK2[2] = be_load_word16(key + 12); + state.TK2[3] = be_load_word16(key + 14); + state.TK3[0] = be_load_word16(key + 16); + state.TK3[1] = be_load_word16(key + 18); + state.TK3[2] = be_load_word16(key + 20); + state.TK3[3] = be_load_word16(key + 22); + state.S[0] = be_load_word16(input); + state.S[1] = be_load_word16(input + 2); + state.S[2] = be_load_word16(input + 4); + state.S[3] = be_load_word16(input + 6); + + /* Fast-forward the tweakey to the end of the key schedule */ + for (round = 0; round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); ++round) { + skinny64_permute_tk(state.TK1); + skinny64_permute_tk(state.TK2); + skinny64_permute_tk(state.TK3); + skinny64_LFSR2(state.TK2[0]); + skinny64_LFSR2(state.TK2[1]); + skinny64_LFSR3(state.TK3[0]); + skinny64_LFSR3(state.TK3[1]); + } + + /* Perform the "after" rounds on the input to get back + * to the forking point in the cipher */ + for (round = (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER * 2); + round > (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + + /* Remove the branching constant */ + state.S[0] ^= 0x1249U; + state.S[1] ^= 0x36daU; + state.S[2] ^= 0x5b7fU; + state.S[3] ^= 0xec81U; + + /* Roll the tweakey back another "after" rounds */ + for (round = 0; round < FORKSKINNY_64_192_ROUNDS_AFTER; ++round) { + skinny64_inv_LFSR2(state.TK2[0]); + skinny64_inv_LFSR2(state.TK2[1]); + skinny64_inv_LFSR3(state.TK3[0]); + skinny64_inv_LFSR3(state.TK3[1]); + skinny64_inv_permute_tk(state.TK1); + skinny64_inv_permute_tk(state.TK2); + skinny64_inv_permute_tk(state.TK3); + } + + /* Save the state and the tweakey at the forking point */ + fstate = state; + + /* Generate the left output block after another "before" rounds */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; round > 0; --round) { + forkskinny_64_192_inv_round(&state, round - 1); + } + be_store_word16(output_left, state.S[0]); + be_store_word16(output_left + 2, state.S[1]); + be_store_word16(output_left + 4, state.S[2]); + be_store_word16(output_left + 6, state.S[3]); + + /* Generate the right output block by going forward "after" + * rounds from the forking point */ + for (round = FORKSKINNY_64_192_ROUNDS_BEFORE; + round < (FORKSKINNY_64_192_ROUNDS_BEFORE + + FORKSKINNY_64_192_ROUNDS_AFTER); ++round) { + forkskinny_64_192_round(&fstate, round); + } + be_store_word16(output_right, fstate.S[0]); + be_store_word16(output_right + 2, fstate.S[1]); + be_store_word16(output_right + 4, fstate.S[2]); + be_store_word16(output_right + 6, fstate.S[3]); +} + diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.h new file mode 100644 index 0000000..0c1a707 --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-forkskinny.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_FORKSKINNY_H +#define LW_INTERNAL_FORKSKINNY_H + +/** + * \file internal-forkskinny.h + * \brief ForkSkinny block cipher family. + * + * ForkSkinny is a modified version of the SKINNY block cipher that + * supports "forking": half-way through the rounds the cipher is + * forked in two different directions to produce two different outputs. + * + * References: https://www.esat.kuleuven.be/cosic/forkae/ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-192 also uses this function with a padded tweakey. + */ +void forkskinny_128_256_encrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-256. + * + * \param key 256-bit tweakey for ForkSkinny-128-256. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_256_decrypt + (const unsigned char key[32], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of plaintext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 128-bit input plaintext block. + * + * ForkSkinny-128-288 also uses this function with a padded tweakey. + */ +void forkskinny_128_384_encrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-128-384. + * + * \param key 384-bit tweakey for ForkSkinny-128-384. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 128-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_128_384_decrypt + (const unsigned char key[48], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Encrypts a block of input with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left First output block, or NULL if left is not required. + * \param output_right Second output block, or NULL if right is not required. + * \param input 64-bit input block. + */ +/** + * \brief Encrypts a block of plaintext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block for the ciphertext, or NULL if + * the left output is not required. + * \param output_right Right output block for the authentication tag, + * or NULL if the right output is not required. + * \param input 64-bit input plaintext block. + */ +void forkskinny_64_192_encrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +/** + * \brief Decrypts a block of ciphertext with ForkSkinny-64-192. + * + * \param key 192-bit tweakey for ForkSkinny-64-192. + * \param output_left Left output block, which is the plaintext. + * \param output_right Right output block for the authentication tag. + * \param input 64-bit input ciphertext block. + * + * Both output blocks will be populated; neither is optional. + */ +void forkskinny_64_192_decrypt + (const unsigned char key[24], unsigned char *output_left, + unsigned char *output_right, const unsigned char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-skinnyutil.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-skinnyutil.h new file mode 100644 index 0000000..83136cb --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-skinnyutil.h @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_SKINNYUTIL_H +#define LW_INTERNAL_SKINNYUTIL_H + +/** + * \file internal-skinnyutil.h + * \brief Utilities to help implement SKINNY and its variants. + */ + +#include "internal-util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond skinnyutil */ + +/* Utilities for implementing SKINNY-128 */ + +#define skinny128_LFSR2(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x << 1) & 0xFEFEFEFEU) ^ \ + (((_x >> 7) ^ (_x >> 5)) & 0x01010101U); \ + } while (0) + + +#define skinny128_LFSR3(x) \ + do { \ + uint32_t _x = (x); \ + (x) = ((_x >> 1) & 0x7F7F7F7FU) ^ \ + (((_x << 7) ^ (_x << 1)) & 0x80808080U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny128_inv_LFSR2(x) skinny128_LFSR3(x) +#define skinny128_inv_LFSR3(x) skinny128_LFSR2(x) + +#define skinny128_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint32_t row2 = tk[2]; \ + uint32_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 16) | (row3 >> 16); \ + tk[0] = ((row2 >> 8) & 0x000000FFU) | \ + ((row2 << 16) & 0x00FF0000U) | \ + ( row3 & 0xFF00FF00U); \ + tk[1] = ((row2 >> 16) & 0x000000FFU) | \ + (row2 & 0xFF000000U) | \ + ((row3 << 8) & 0x0000FF00U) | \ + ( row3 & 0x00FF0000U); \ + } while (0) + +#define skinny128_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint32_t row0 = tk[0]; \ + uint32_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 >> 16) & 0x000000FFU) | \ + ((row0 << 8) & 0x0000FF00U) | \ + ((row1 << 16) & 0x00FF0000U) | \ + ( row1 & 0xFF000000U); \ + tk[3] = ((row0 >> 16) & 0x0000FF00U) | \ + ((row0 << 16) & 0xFF000000U) | \ + ((row1 >> 16) & 0x000000FFU) | \ + ((row1 << 8) & 0x00FF0000U); \ + } while (0) + +/* + * Apply the SKINNY sbox. The original version from the specification is + * equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE(x) + * ((((x) & 0x01010101U) << 2) | + * (((x) & 0x06060606U) << 5) | + * (((x) & 0x20202020U) >> 5) | + * (((x) & 0xC8C8C8C8U) >> 2) | + * (((x) & 0x10101010U) >> 1)) + * + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE(x); + * x = SBOX_MIX(x); + * return SBOX_SWAP(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + x ^= (((x >> 2) & (x >> 3)) & 0x11111111U); \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 5) & (x << 4)) & 0x40404040U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 2) & (x << 1)) & 0x02020202U) ^ y; \ + y = (((x >> 5) & (x << 1)) & 0x04040404U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [2 7 6 1 3 0 4 5] */ \ + x = ((x & 0x08080808U) << 1) | \ + ((x & 0x32323232U) << 2) | \ + ((x & 0x01010101U) << 5) | \ + ((x & 0x80808080U) >> 6) | \ + ((x & 0x40404040U) >> 4) | \ + ((x & 0x04040404U) >> 2); \ +} while (0) + +/* + * Apply the inverse of the SKINNY sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x11111111U) ^ (x)) + * #define SBOX_SWAP(x) + * (((x) & 0xF9F9F9F9U) | + * (((x) >> 1) & 0x02020202U) | + * (((x) << 1) & 0x04040404U)) + * #define SBOX_PERMUTE_INV(x) + * ((((x) & 0x08080808U) << 1) | + * (((x) & 0x32323232U) << 2) | + * (((x) & 0x01010101U) << 5) | + * (((x) & 0xC0C0C0C0U) >> 5) | + * (((x) & 0x04040404U) >> 2)) + * + * x = SBOX_SWAP(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_PERMUTE_INV(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_PERMUTE_INV and SBOX_SWAP steps to be performed with one + * final permuatation. This reduces the number of shift operations. + */ +#define skinny128_inv_sbox(x) \ +do { \ + uint32_t y; \ + \ + /* Mix the bits */ \ + x = ~x; \ + y = (((x >> 1) & (x >> 3)) & 0x01010101U); \ + x ^= (((x >> 2) & (x >> 3)) & 0x10101010U) ^ y; \ + y = (((x >> 6) & (x >> 1)) & 0x02020202U); \ + x ^= (((x >> 1) & (x >> 2)) & 0x08080808U) ^ y; \ + y = (((x << 2) & (x << 1)) & 0x80808080U); \ + x ^= (((x >> 1) & (x << 2)) & 0x04040404U) ^ y; \ + y = (((x << 5) & (x << 1)) & 0x20202020U); \ + x ^= (((x << 4) & (x << 5)) & 0x40404040U) ^ y; \ + x = ~x; \ + \ + /* Permutation generated by http://programming.sirrida.de/calcperm.php */ \ + /* The final permutation for each byte is [5 3 0 4 6 7 2 1] */ \ + x = ((x & 0x01010101U) << 2) | \ + ((x & 0x04040404U) << 4) | \ + ((x & 0x02020202U) << 6) | \ + ((x & 0x20202020U) >> 5) | \ + ((x & 0xC8C8C8C8U) >> 2) | \ + ((x & 0x10101010U) >> 1); \ +} while (0) + +/* Utilities for implementing SKINNY-64 */ + +#define skinny64_LFSR2(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x << 1) & 0xEEEEU) ^ (((_x >> 3) ^ (_x >> 2)) & 0x1111U); \ + } while (0) + +#define skinny64_LFSR3(x) \ + do { \ + uint16_t _x = (x); \ + (x) = ((_x >> 1) & 0x7777U) ^ ((_x ^ (_x << 3)) & 0x8888U); \ + } while (0) + +/* LFSR2 and LFSR3 are inverses of each other */ +#define skinny64_inv_LFSR2(x) skinny64_LFSR3(x) +#define skinny64_inv_LFSR3(x) skinny64_LFSR2(x) + +#define skinny64_permute_tk(tk) \ + do { \ + /* PT = [9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7] */ \ + uint16_t row2 = tk[2]; \ + uint16_t row3 = tk[3]; \ + tk[2] = tk[0]; \ + tk[3] = tk[1]; \ + row3 = (row3 << 8) | (row3 >> 8); \ + tk[0] = ((row2 << 4) & 0xF000U) | \ + ((row2 >> 8) & 0x00F0U) | \ + ( row3 & 0x0F0FU); \ + tk[1] = ((row2 << 8) & 0xF000U) | \ + ((row3 >> 4) & 0x0F00U) | \ + ( row3 & 0x00F0U) | \ + ( row2 & 0x000FU); \ + } while (0) + +#define skinny64_inv_permute_tk(tk) \ + do { \ + /* PT' = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1] */ \ + uint16_t row0 = tk[0]; \ + uint16_t row1 = tk[1]; \ + tk[0] = tk[2]; \ + tk[1] = tk[3]; \ + tk[2] = ((row0 << 8) & 0xF000U) | \ + ((row0 >> 4) & 0x0F00U) | \ + ((row1 >> 8) & 0x00F0U) | \ + ( row1 & 0x000FU); \ + tk[3] = ((row1 << 8) & 0xF000U) | \ + ((row0 << 8) & 0x0F00U) | \ + ((row1 >> 4) & 0x00F0U) | \ + ((row0 >> 8) & 0x000FU); \ + } while (0) + +/* + * Apply the SKINNY-64 sbox. The original version from the + * specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT(x) + * ((((x) << 1) & 0xEEEEU) | (((x) >> 3) & 0x1111U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT(x); + * return SBOX_MIX(x); + * + * However, we can mix the bits in their original positions and then + * delay the SBOX_SHIFT steps to be performed with one final rotation. + * This reduces the number of required shift operations from 14 to 10. + * + * We can further reduce the number of NOT operations from 4 to 2 + * using the technique from https://github.com/kste/skinny_avx to + * convert NOR-XOR operations into AND-XOR operations by converting + * the S-box into its NOT-inverse. + */ +#define skinny64_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x >> 2) & (x << 1)) & 0x2222U) ^ x; \ + x = ~x; \ + x = ((x >> 1) & 0x7777U) | ((x << 3) & 0x8888U); \ +} while (0) + +/* + * Apply the inverse of the SKINNY-64 sbox. The original version + * from the specification is equivalent to: + * + * #define SBOX_MIX(x) + * (((~((((x) >> 1) | (x)) >> 2)) & 0x1111U) ^ (x)) + * #define SBOX_SHIFT_INV(x) + * ((((x) >> 1) & 0x7777U) | (((x) << 3) & 0x8888U)) + * + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * x = SBOX_MIX(x); + * x = SBOX_SHIFT_INV(x); + * return SBOX_MIX(x); + */ +#define skinny64_inv_sbox(x) \ +do { \ + x = ~x; \ + x = (((x >> 3) & (x >> 2)) & 0x1111U) ^ x; \ + x = (((x << 1) & (x >> 2)) & 0x2222U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x4444U) ^ x; \ + x = (((x << 1) & (x << 2)) & 0x8888U) ^ x; \ + x = ~x; \ + x = ((x << 1) & 0xEEEEU) | ((x >> 3) & 0x1111U); \ +} while (0) + +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-util.h b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-util.h new file mode 100644 index 0000000..e30166d --- /dev/null +++ b/forkae/Implementations/crypto_aead/saefforkskinnyb128t256n120v1/opt32_table/internal-util.h @@ -0,0 +1,702 @@ +/* + * Copyright (C) 2020 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 LW_INTERNAL_UTIL_H +#define LW_INTERNAL_UTIL_H + +#include + +/* Figure out how to inline functions using this C compiler */ +#if defined(__STDC__) && __STDC_VERSION__ >= 199901L +#define STATIC_INLINE static inline +#elif defined(__GNUC__) || defined(__clang__) +#define STATIC_INLINE static __inline__ +#else +#define STATIC_INLINE static +#endif + +/* Try to figure out whether the CPU is little-endian or big-endian. + * May need to modify this to include new compiler-specific defines. + * Alternatively, define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ in your + * compiler flags when you compile this library */ +#if defined(__x86_64) || defined(__x86_64__) || \ + defined(__i386) || defined(__i386__) || \ + defined(__AVR__) || defined(__arm) || defined(__arm__) || \ + defined(_M_AMD64) || defined(_M_X64) || defined(_M_IX86) || \ + defined(_M_IA64) || defined(_M_ARM) || defined(_M_ARM_FP) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 1234) || \ + defined(__LITTLE_ENDIAN__) +#define LW_UTIL_LITTLE_ENDIAN 1 +#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == 4321) || \ + defined(__BIG_ENDIAN__) +/* Big endian */ +#else +#error "Cannot determine the endianess of this platform" +#endif + +/* Helper macros to load and store values while converting endian-ness */ + +/* Load a big-endian 32-bit word from a byte buffer */ +#define be_load_word32(ptr) \ + ((((uint32_t)((ptr)[0])) << 24) | \ + (((uint32_t)((ptr)[1])) << 16) | \ + (((uint32_t)((ptr)[2])) << 8) | \ + ((uint32_t)((ptr)[3]))) + +/* Store a big-endian 32-bit word into a byte buffer */ +#define be_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 24); \ + (ptr)[1] = (uint8_t)(_x >> 16); \ + (ptr)[2] = (uint8_t)(_x >> 8); \ + (ptr)[3] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 32-bit word from a byte buffer */ +#define le_load_word32(ptr) \ + ((((uint32_t)((ptr)[3])) << 24) | \ + (((uint32_t)((ptr)[2])) << 16) | \ + (((uint32_t)((ptr)[1])) << 8) | \ + ((uint32_t)((ptr)[0]))) + +/* Store a little-endian 32-bit word into a byte buffer */ +#define le_store_word32(ptr, x) \ + do { \ + uint32_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + } while (0) + +/* Load a big-endian 64-bit word from a byte buffer */ +#define be_load_word64(ptr) \ + ((((uint64_t)((ptr)[0])) << 56) | \ + (((uint64_t)((ptr)[1])) << 48) | \ + (((uint64_t)((ptr)[2])) << 40) | \ + (((uint64_t)((ptr)[3])) << 32) | \ + (((uint64_t)((ptr)[4])) << 24) | \ + (((uint64_t)((ptr)[5])) << 16) | \ + (((uint64_t)((ptr)[6])) << 8) | \ + ((uint64_t)((ptr)[7]))) + +/* Store a big-endian 64-bit word into a byte buffer */ +#define be_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 56); \ + (ptr)[1] = (uint8_t)(_x >> 48); \ + (ptr)[2] = (uint8_t)(_x >> 40); \ + (ptr)[3] = (uint8_t)(_x >> 32); \ + (ptr)[4] = (uint8_t)(_x >> 24); \ + (ptr)[5] = (uint8_t)(_x >> 16); \ + (ptr)[6] = (uint8_t)(_x >> 8); \ + (ptr)[7] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 64-bit word from a byte buffer */ +#define le_load_word64(ptr) \ + ((((uint64_t)((ptr)[7])) << 56) | \ + (((uint64_t)((ptr)[6])) << 48) | \ + (((uint64_t)((ptr)[5])) << 40) | \ + (((uint64_t)((ptr)[4])) << 32) | \ + (((uint64_t)((ptr)[3])) << 24) | \ + (((uint64_t)((ptr)[2])) << 16) | \ + (((uint64_t)((ptr)[1])) << 8) | \ + ((uint64_t)((ptr)[0]))) + +/* Store a little-endian 64-bit word into a byte buffer */ +#define le_store_word64(ptr, x) \ + do { \ + uint64_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + (ptr)[2] = (uint8_t)(_x >> 16); \ + (ptr)[3] = (uint8_t)(_x >> 24); \ + (ptr)[4] = (uint8_t)(_x >> 32); \ + (ptr)[5] = (uint8_t)(_x >> 40); \ + (ptr)[6] = (uint8_t)(_x >> 48); \ + (ptr)[7] = (uint8_t)(_x >> 56); \ + } while (0) + +/* Load a big-endian 16-bit word from a byte buffer */ +#define be_load_word16(ptr) \ + ((((uint16_t)((ptr)[0])) << 8) | \ + ((uint16_t)((ptr)[1]))) + +/* Store a big-endian 16-bit word into a byte buffer */ +#define be_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)(_x >> 8); \ + (ptr)[1] = (uint8_t)_x; \ + } while (0) + +/* Load a little-endian 16-bit word from a byte buffer */ +#define le_load_word16(ptr) \ + ((((uint16_t)((ptr)[1])) << 8) | \ + ((uint16_t)((ptr)[0]))) + +/* Store a little-endian 16-bit word into a byte buffer */ +#define le_store_word16(ptr, x) \ + do { \ + uint16_t _x = (x); \ + (ptr)[0] = (uint8_t)_x; \ + (ptr)[1] = (uint8_t)(_x >> 8); \ + } while (0) + +/* XOR a source byte buffer against a destination */ +#define lw_xor_block(dest, src, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ ^= *_src++; \ + --_len; \ + } \ + } while (0) + +/* XOR two source byte buffers and put the result in a destination buffer */ +#define lw_xor_block_2_src(dest, src1, src2, len) \ + do { \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest++ = *_src1++ ^ *_src2++; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time */ +#define lw_xor_block_2_dest(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + *_dest2++ = (*_dest++ ^= *_src++); \ + --_len; \ + } \ + } while (0) + +/* XOR two byte buffers and write to a destination which at the same + * time copying the contents of src2 to dest2 */ +#define lw_xor_block_copy_src(dest2, dest, src1, src2, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src1 = (src1); \ + const unsigned char *_src2 = (src2); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src2++; \ + *_dest2++ = _temp; \ + *_dest++ = *_src1++ ^ _temp; \ + --_len; \ + } \ + } while (0) + +/* XOR a source byte buffer against a destination and write to another + * destination at the same time. This version swaps the source value + * into the "dest" buffer */ +#define lw_xor_block_swap(dest2, dest, src, len) \ + do { \ + unsigned char *_dest2 = (dest2); \ + unsigned char *_dest = (dest); \ + const unsigned char *_src = (src); \ + unsigned _len = (len); \ + while (_len > 0) { \ + unsigned char _temp = *_src++; \ + *_dest2++ = *_dest ^ _temp; \ + *_dest++ = _temp; \ + --_len; \ + } \ + } while (0) + +/* Rotation functions need to be optimised for best performance on AVR. + * The most efficient rotations are where the number of bits is 1 or a + * multiple of 8, so we compose the efficient rotations to produce all + * other rotation counts of interest. */ + +#if defined(__AVR__) +#define LW_CRYPTO_ROTATE32_COMPOSED 1 +#else +#define LW_CRYPTO_ROTATE32_COMPOSED 0 +#endif + +/* Rotation macros for 32-bit arguments */ + +/* Generic left rotate */ +#define leftRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (32 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate(a, bits) \ + (__extension__ ({ \ + uint32_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (32 - (bits))); \ + })) + +#if !LW_CRYPTO_ROTATE32_COMPOSED + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1(a) (leftRotate((a), 1)) +#define leftRotate2(a) (leftRotate((a), 2)) +#define leftRotate3(a) (leftRotate((a), 3)) +#define leftRotate4(a) (leftRotate((a), 4)) +#define leftRotate5(a) (leftRotate((a), 5)) +#define leftRotate6(a) (leftRotate((a), 6)) +#define leftRotate7(a) (leftRotate((a), 7)) +#define leftRotate8(a) (leftRotate((a), 8)) +#define leftRotate9(a) (leftRotate((a), 9)) +#define leftRotate10(a) (leftRotate((a), 10)) +#define leftRotate11(a) (leftRotate((a), 11)) +#define leftRotate12(a) (leftRotate((a), 12)) +#define leftRotate13(a) (leftRotate((a), 13)) +#define leftRotate14(a) (leftRotate((a), 14)) +#define leftRotate15(a) (leftRotate((a), 15)) +#define leftRotate16(a) (leftRotate((a), 16)) +#define leftRotate17(a) (leftRotate((a), 17)) +#define leftRotate18(a) (leftRotate((a), 18)) +#define leftRotate19(a) (leftRotate((a), 19)) +#define leftRotate20(a) (leftRotate((a), 20)) +#define leftRotate21(a) (leftRotate((a), 21)) +#define leftRotate22(a) (leftRotate((a), 22)) +#define leftRotate23(a) (leftRotate((a), 23)) +#define leftRotate24(a) (leftRotate((a), 24)) +#define leftRotate25(a) (leftRotate((a), 25)) +#define leftRotate26(a) (leftRotate((a), 26)) +#define leftRotate27(a) (leftRotate((a), 27)) +#define leftRotate28(a) (leftRotate((a), 28)) +#define leftRotate29(a) (leftRotate((a), 29)) +#define leftRotate30(a) (leftRotate((a), 30)) +#define leftRotate31(a) (leftRotate((a), 31)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1(a) (rightRotate((a), 1)) +#define rightRotate2(a) (rightRotate((a), 2)) +#define rightRotate3(a) (rightRotate((a), 3)) +#define rightRotate4(a) (rightRotate((a), 4)) +#define rightRotate5(a) (rightRotate((a), 5)) +#define rightRotate6(a) (rightRotate((a), 6)) +#define rightRotate7(a) (rightRotate((a), 7)) +#define rightRotate8(a) (rightRotate((a), 8)) +#define rightRotate9(a) (rightRotate((a), 9)) +#define rightRotate10(a) (rightRotate((a), 10)) +#define rightRotate11(a) (rightRotate((a), 11)) +#define rightRotate12(a) (rightRotate((a), 12)) +#define rightRotate13(a) (rightRotate((a), 13)) +#define rightRotate14(a) (rightRotate((a), 14)) +#define rightRotate15(a) (rightRotate((a), 15)) +#define rightRotate16(a) (rightRotate((a), 16)) +#define rightRotate17(a) (rightRotate((a), 17)) +#define rightRotate18(a) (rightRotate((a), 18)) +#define rightRotate19(a) (rightRotate((a), 19)) +#define rightRotate20(a) (rightRotate((a), 20)) +#define rightRotate21(a) (rightRotate((a), 21)) +#define rightRotate22(a) (rightRotate((a), 22)) +#define rightRotate23(a) (rightRotate((a), 23)) +#define rightRotate24(a) (rightRotate((a), 24)) +#define rightRotate25(a) (rightRotate((a), 25)) +#define rightRotate26(a) (rightRotate((a), 26)) +#define rightRotate27(a) (rightRotate((a), 27)) +#define rightRotate28(a) (rightRotate((a), 28)) +#define rightRotate29(a) (rightRotate((a), 29)) +#define rightRotate30(a) (rightRotate((a), 30)) +#define rightRotate31(a) (rightRotate((a), 31)) + +#else /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Composed rotation macros where 1 and 8 are fast, but others are slow */ + +/* Left rotate by 1 */ +#define leftRotate1(a) (leftRotate((a), 1)) + +/* Left rotate by 2 */ +#define leftRotate2(a) (leftRotate(leftRotate((a), 1), 1)) + +/* Left rotate by 3 */ +#define leftRotate3(a) (leftRotate(leftRotate(leftRotate((a), 1), 1), 1)) + +/* Left rotate by 4 */ +#define leftRotate4(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 5: Rotate left by 8, then right by 3 */ +#define leftRotate5(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 6: Rotate left by 8, then right by 2 */ +#define leftRotate6(a) (rightRotate(rightRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 7: Rotate left by 8, then right by 1 */ +#define leftRotate7(a) (rightRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 8 */ +#define leftRotate8(a) (leftRotate((a), 8)) + +/* Left rotate by 9: Rotate left by 8, then left by 1 */ +#define leftRotate9(a) (leftRotate(leftRotate((a), 8), 1)) + +/* Left rotate by 10: Rotate left by 8, then left by 2 */ +#define leftRotate10(a) (leftRotate(leftRotate(leftRotate((a), 8), 1), 1)) + +/* Left rotate by 11: Rotate left by 8, then left by 3 */ +#define leftRotate11(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 8), 1), 1), 1)) + +/* Left rotate by 12: Rotate left by 16, then right by 4 */ +#define leftRotate12(a) (rightRotate(rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 13: Rotate left by 16, then right by 3 */ +#define leftRotate13(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 14: Rotate left by 16, then right by 2 */ +#define leftRotate14(a) (rightRotate(rightRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 15: Rotate left by 16, then right by 1 */ +#define leftRotate15(a) (rightRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 16 */ +#define leftRotate16(a) (leftRotate((a), 16)) + +/* Left rotate by 17: Rotate left by 16, then left by 1 */ +#define leftRotate17(a) (leftRotate(leftRotate((a), 16), 1)) + +/* Left rotate by 18: Rotate left by 16, then left by 2 */ +#define leftRotate18(a) (leftRotate(leftRotate(leftRotate((a), 16), 1), 1)) + +/* Left rotate by 19: Rotate left by 16, then left by 3 */ +#define leftRotate19(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1)) + +/* Left rotate by 20: Rotate left by 16, then left by 4 */ +#define leftRotate20(a) (leftRotate(leftRotate(leftRotate(leftRotate(leftRotate((a), 16), 1), 1), 1), 1)) + +/* Left rotate by 21: Rotate left by 24, then right by 3 */ +#define leftRotate21(a) (rightRotate(rightRotate(rightRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 22: Rotate left by 24, then right by 2 */ +#define leftRotate22(a) (rightRotate(rightRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 23: Rotate left by 24, then right by 1 */ +#define leftRotate23(a) (rightRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 24 */ +#define leftRotate24(a) (leftRotate((a), 24)) + +/* Left rotate by 25: Rotate left by 24, then left by 1 */ +#define leftRotate25(a) (leftRotate(leftRotate((a), 24), 1)) + +/* Left rotate by 26: Rotate left by 24, then left by 2 */ +#define leftRotate26(a) (leftRotate(leftRotate(leftRotate((a), 24), 1), 1)) + +/* Left rotate by 27: Rotate left by 24, then left by 3 */ +#define leftRotate27(a) (leftRotate(leftRotate(leftRotate(leftRotate((a), 24), 1), 1), 1)) + +/* Left rotate by 28: Rotate right by 4 */ +#define leftRotate28(a) (rightRotate(rightRotate(rightRotate(rightRotate((a), 1), 1), 1), 1)) + +/* Left rotate by 29: Rotate right by 3 */ +#define leftRotate29(a) (rightRotate(rightRotate(rightRotate((a), 1), 1), 1)) + +/* Left rotate by 30: Rotate right by 2 */ +#define leftRotate30(a) (rightRotate(rightRotate((a), 1), 1)) + +/* Left rotate by 31: Rotate right by 1 */ +#define leftRotate31(a) (rightRotate((a), 1)) + +/* Define the 32-bit right rotations in terms of left rotations */ +#define rightRotate1(a) (leftRotate31((a))) +#define rightRotate2(a) (leftRotate30((a))) +#define rightRotate3(a) (leftRotate29((a))) +#define rightRotate4(a) (leftRotate28((a))) +#define rightRotate5(a) (leftRotate27((a))) +#define rightRotate6(a) (leftRotate26((a))) +#define rightRotate7(a) (leftRotate25((a))) +#define rightRotate8(a) (leftRotate24((a))) +#define rightRotate9(a) (leftRotate23((a))) +#define rightRotate10(a) (leftRotate22((a))) +#define rightRotate11(a) (leftRotate21((a))) +#define rightRotate12(a) (leftRotate20((a))) +#define rightRotate13(a) (leftRotate19((a))) +#define rightRotate14(a) (leftRotate18((a))) +#define rightRotate15(a) (leftRotate17((a))) +#define rightRotate16(a) (leftRotate16((a))) +#define rightRotate17(a) (leftRotate15((a))) +#define rightRotate18(a) (leftRotate14((a))) +#define rightRotate19(a) (leftRotate13((a))) +#define rightRotate20(a) (leftRotate12((a))) +#define rightRotate21(a) (leftRotate11((a))) +#define rightRotate22(a) (leftRotate10((a))) +#define rightRotate23(a) (leftRotate9((a))) +#define rightRotate24(a) (leftRotate8((a))) +#define rightRotate25(a) (leftRotate7((a))) +#define rightRotate26(a) (leftRotate6((a))) +#define rightRotate27(a) (leftRotate5((a))) +#define rightRotate28(a) (leftRotate4((a))) +#define rightRotate29(a) (leftRotate3((a))) +#define rightRotate30(a) (leftRotate2((a))) +#define rightRotate31(a) (leftRotate1((a))) + +#endif /* LW_CRYPTO_ROTATE32_COMPOSED */ + +/* Rotation macros for 64-bit arguments */ + +/* Generic left rotate */ +#define leftRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (64 - (bits))); \ + })) + +/* Generic right rotate */ +#define rightRotate_64(a, bits) \ + (__extension__ ({ \ + uint64_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (64 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_64(a) (leftRotate_64((a), 1)) +#define leftRotate2_64(a) (leftRotate_64((a), 2)) +#define leftRotate3_64(a) (leftRotate_64((a), 3)) +#define leftRotate4_64(a) (leftRotate_64((a), 4)) +#define leftRotate5_64(a) (leftRotate_64((a), 5)) +#define leftRotate6_64(a) (leftRotate_64((a), 6)) +#define leftRotate7_64(a) (leftRotate_64((a), 7)) +#define leftRotate8_64(a) (leftRotate_64((a), 8)) +#define leftRotate9_64(a) (leftRotate_64((a), 9)) +#define leftRotate10_64(a) (leftRotate_64((a), 10)) +#define leftRotate11_64(a) (leftRotate_64((a), 11)) +#define leftRotate12_64(a) (leftRotate_64((a), 12)) +#define leftRotate13_64(a) (leftRotate_64((a), 13)) +#define leftRotate14_64(a) (leftRotate_64((a), 14)) +#define leftRotate15_64(a) (leftRotate_64((a), 15)) +#define leftRotate16_64(a) (leftRotate_64((a), 16)) +#define leftRotate17_64(a) (leftRotate_64((a), 17)) +#define leftRotate18_64(a) (leftRotate_64((a), 18)) +#define leftRotate19_64(a) (leftRotate_64((a), 19)) +#define leftRotate20_64(a) (leftRotate_64((a), 20)) +#define leftRotate21_64(a) (leftRotate_64((a), 21)) +#define leftRotate22_64(a) (leftRotate_64((a), 22)) +#define leftRotate23_64(a) (leftRotate_64((a), 23)) +#define leftRotate24_64(a) (leftRotate_64((a), 24)) +#define leftRotate25_64(a) (leftRotate_64((a), 25)) +#define leftRotate26_64(a) (leftRotate_64((a), 26)) +#define leftRotate27_64(a) (leftRotate_64((a), 27)) +#define leftRotate28_64(a) (leftRotate_64((a), 28)) +#define leftRotate29_64(a) (leftRotate_64((a), 29)) +#define leftRotate30_64(a) (leftRotate_64((a), 30)) +#define leftRotate31_64(a) (leftRotate_64((a), 31)) +#define leftRotate32_64(a) (leftRotate_64((a), 32)) +#define leftRotate33_64(a) (leftRotate_64((a), 33)) +#define leftRotate34_64(a) (leftRotate_64((a), 34)) +#define leftRotate35_64(a) (leftRotate_64((a), 35)) +#define leftRotate36_64(a) (leftRotate_64((a), 36)) +#define leftRotate37_64(a) (leftRotate_64((a), 37)) +#define leftRotate38_64(a) (leftRotate_64((a), 38)) +#define leftRotate39_64(a) (leftRotate_64((a), 39)) +#define leftRotate40_64(a) (leftRotate_64((a), 40)) +#define leftRotate41_64(a) (leftRotate_64((a), 41)) +#define leftRotate42_64(a) (leftRotate_64((a), 42)) +#define leftRotate43_64(a) (leftRotate_64((a), 43)) +#define leftRotate44_64(a) (leftRotate_64((a), 44)) +#define leftRotate45_64(a) (leftRotate_64((a), 45)) +#define leftRotate46_64(a) (leftRotate_64((a), 46)) +#define leftRotate47_64(a) (leftRotate_64((a), 47)) +#define leftRotate48_64(a) (leftRotate_64((a), 48)) +#define leftRotate49_64(a) (leftRotate_64((a), 49)) +#define leftRotate50_64(a) (leftRotate_64((a), 50)) +#define leftRotate51_64(a) (leftRotate_64((a), 51)) +#define leftRotate52_64(a) (leftRotate_64((a), 52)) +#define leftRotate53_64(a) (leftRotate_64((a), 53)) +#define leftRotate54_64(a) (leftRotate_64((a), 54)) +#define leftRotate55_64(a) (leftRotate_64((a), 55)) +#define leftRotate56_64(a) (leftRotate_64((a), 56)) +#define leftRotate57_64(a) (leftRotate_64((a), 57)) +#define leftRotate58_64(a) (leftRotate_64((a), 58)) +#define leftRotate59_64(a) (leftRotate_64((a), 59)) +#define leftRotate60_64(a) (leftRotate_64((a), 60)) +#define leftRotate61_64(a) (leftRotate_64((a), 61)) +#define leftRotate62_64(a) (leftRotate_64((a), 62)) +#define leftRotate63_64(a) (leftRotate_64((a), 63)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_64(a) (rightRotate_64((a), 1)) +#define rightRotate2_64(a) (rightRotate_64((a), 2)) +#define rightRotate3_64(a) (rightRotate_64((a), 3)) +#define rightRotate4_64(a) (rightRotate_64((a), 4)) +#define rightRotate5_64(a) (rightRotate_64((a), 5)) +#define rightRotate6_64(a) (rightRotate_64((a), 6)) +#define rightRotate7_64(a) (rightRotate_64((a), 7)) +#define rightRotate8_64(a) (rightRotate_64((a), 8)) +#define rightRotate9_64(a) (rightRotate_64((a), 9)) +#define rightRotate10_64(a) (rightRotate_64((a), 10)) +#define rightRotate11_64(a) (rightRotate_64((a), 11)) +#define rightRotate12_64(a) (rightRotate_64((a), 12)) +#define rightRotate13_64(a) (rightRotate_64((a), 13)) +#define rightRotate14_64(a) (rightRotate_64((a), 14)) +#define rightRotate15_64(a) (rightRotate_64((a), 15)) +#define rightRotate16_64(a) (rightRotate_64((a), 16)) +#define rightRotate17_64(a) (rightRotate_64((a), 17)) +#define rightRotate18_64(a) (rightRotate_64((a), 18)) +#define rightRotate19_64(a) (rightRotate_64((a), 19)) +#define rightRotate20_64(a) (rightRotate_64((a), 20)) +#define rightRotate21_64(a) (rightRotate_64((a), 21)) +#define rightRotate22_64(a) (rightRotate_64((a), 22)) +#define rightRotate23_64(a) (rightRotate_64((a), 23)) +#define rightRotate24_64(a) (rightRotate_64((a), 24)) +#define rightRotate25_64(a) (rightRotate_64((a), 25)) +#define rightRotate26_64(a) (rightRotate_64((a), 26)) +#define rightRotate27_64(a) (rightRotate_64((a), 27)) +#define rightRotate28_64(a) (rightRotate_64((a), 28)) +#define rightRotate29_64(a) (rightRotate_64((a), 29)) +#define rightRotate30_64(a) (rightRotate_64((a), 30)) +#define rightRotate31_64(a) (rightRotate_64((a), 31)) +#define rightRotate32_64(a) (rightRotate_64((a), 32)) +#define rightRotate33_64(a) (rightRotate_64((a), 33)) +#define rightRotate34_64(a) (rightRotate_64((a), 34)) +#define rightRotate35_64(a) (rightRotate_64((a), 35)) +#define rightRotate36_64(a) (rightRotate_64((a), 36)) +#define rightRotate37_64(a) (rightRotate_64((a), 37)) +#define rightRotate38_64(a) (rightRotate_64((a), 38)) +#define rightRotate39_64(a) (rightRotate_64((a), 39)) +#define rightRotate40_64(a) (rightRotate_64((a), 40)) +#define rightRotate41_64(a) (rightRotate_64((a), 41)) +#define rightRotate42_64(a) (rightRotate_64((a), 42)) +#define rightRotate43_64(a) (rightRotate_64((a), 43)) +#define rightRotate44_64(a) (rightRotate_64((a), 44)) +#define rightRotate45_64(a) (rightRotate_64((a), 45)) +#define rightRotate46_64(a) (rightRotate_64((a), 46)) +#define rightRotate47_64(a) (rightRotate_64((a), 47)) +#define rightRotate48_64(a) (rightRotate_64((a), 48)) +#define rightRotate49_64(a) (rightRotate_64((a), 49)) +#define rightRotate50_64(a) (rightRotate_64((a), 50)) +#define rightRotate51_64(a) (rightRotate_64((a), 51)) +#define rightRotate52_64(a) (rightRotate_64((a), 52)) +#define rightRotate53_64(a) (rightRotate_64((a), 53)) +#define rightRotate54_64(a) (rightRotate_64((a), 54)) +#define rightRotate55_64(a) (rightRotate_64((a), 55)) +#define rightRotate56_64(a) (rightRotate_64((a), 56)) +#define rightRotate57_64(a) (rightRotate_64((a), 57)) +#define rightRotate58_64(a) (rightRotate_64((a), 58)) +#define rightRotate59_64(a) (rightRotate_64((a), 59)) +#define rightRotate60_64(a) (rightRotate_64((a), 60)) +#define rightRotate61_64(a) (rightRotate_64((a), 61)) +#define rightRotate62_64(a) (rightRotate_64((a), 62)) +#define rightRotate63_64(a) (rightRotate_64((a), 63)) + +/* Rotate a 16-bit value left by a number of bits */ +#define leftRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (16 - (bits))); \ + })) + +/* Rotate a 16-bit value right by a number of bits */ +#define rightRotate_16(a, bits) \ + (__extension__ ({ \ + uint16_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (16 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_16(a) (leftRotate_16((a), 1)) +#define leftRotate2_16(a) (leftRotate_16((a), 2)) +#define leftRotate3_16(a) (leftRotate_16((a), 3)) +#define leftRotate4_16(a) (leftRotate_16((a), 4)) +#define leftRotate5_16(a) (leftRotate_16((a), 5)) +#define leftRotate6_16(a) (leftRotate_16((a), 6)) +#define leftRotate7_16(a) (leftRotate_16((a), 7)) +#define leftRotate8_16(a) (leftRotate_16((a), 8)) +#define leftRotate9_16(a) (leftRotate_16((a), 9)) +#define leftRotate10_16(a) (leftRotate_16((a), 10)) +#define leftRotate11_16(a) (leftRotate_16((a), 11)) +#define leftRotate12_16(a) (leftRotate_16((a), 12)) +#define leftRotate13_16(a) (leftRotate_16((a), 13)) +#define leftRotate14_16(a) (leftRotate_16((a), 14)) +#define leftRotate15_16(a) (leftRotate_16((a), 15)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_16(a) (rightRotate_16((a), 1)) +#define rightRotate2_16(a) (rightRotate_16((a), 2)) +#define rightRotate3_16(a) (rightRotate_16((a), 3)) +#define rightRotate4_16(a) (rightRotate_16((a), 4)) +#define rightRotate5_16(a) (rightRotate_16((a), 5)) +#define rightRotate6_16(a) (rightRotate_16((a), 6)) +#define rightRotate7_16(a) (rightRotate_16((a), 7)) +#define rightRotate8_16(a) (rightRotate_16((a), 8)) +#define rightRotate9_16(a) (rightRotate_16((a), 9)) +#define rightRotate10_16(a) (rightRotate_16((a), 10)) +#define rightRotate11_16(a) (rightRotate_16((a), 11)) +#define rightRotate12_16(a) (rightRotate_16((a), 12)) +#define rightRotate13_16(a) (rightRotate_16((a), 13)) +#define rightRotate14_16(a) (rightRotate_16((a), 14)) +#define rightRotate15_16(a) (rightRotate_16((a), 15)) + +/* Rotate an 8-bit value left by a number of bits */ +#define leftRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp << (bits)) | (_temp >> (8 - (bits))); \ + })) + +/* Rotate an 8-bit value right by a number of bits */ +#define rightRotate_8(a, bits) \ + (__extension__ ({ \ + uint8_t _temp = (a); \ + (_temp >> (bits)) | (_temp << (8 - (bits))); \ + })) + +/* Left rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define leftRotate1_8(a) (leftRotate_8((a), 1)) +#define leftRotate2_8(a) (leftRotate_8((a), 2)) +#define leftRotate3_8(a) (leftRotate_8((a), 3)) +#define leftRotate4_8(a) (leftRotate_8((a), 4)) +#define leftRotate5_8(a) (leftRotate_8((a), 5)) +#define leftRotate6_8(a) (leftRotate_8((a), 6)) +#define leftRotate7_8(a) (leftRotate_8((a), 7)) + +/* Right rotate by a specific number of bits. These macros may be replaced + * with more efficient ones on platforms that lack a barrel shifter */ +#define rightRotate1_8(a) (rightRotate_8((a), 1)) +#define rightRotate2_8(a) (rightRotate_8((a), 2)) +#define rightRotate3_8(a) (rightRotate_8((a), 3)) +#define rightRotate4_8(a) (rightRotate_8((a), 4)) +#define rightRotate5_8(a) (rightRotate_8((a), 5)) +#define rightRotate6_8(a) (rightRotate_8((a), 6)) +#define rightRotate7_8(a) (rightRotate_8((a), 7)) + +#endif -- libgit2 0.26.0