ASCON - Light-weight cipherASCON [2] was designed by Christoph Dobraunig, Maria Eichlseder, Florian Mendel and Martin Schläffer from Graz University of Technology, Infineon Technologies, and Radboud University. It is both a light-weight hashing and encryption method. ASCON uses a single lightweight permutation with a Sponge-based modes of operation and a SPN (substitution–permutation network) permutation. Overall it has an easy method of implementing within hardware (2.6 gate equivalents) and software. A 5-bit S-box (as used in Keccak’s S-box core) is used to enable a light weight approach and it has no known side-channel attacks. It can also achieve high throughputs such as throughputs of between 4.9 and 7.3 Gbps. It stores its current state with 320 bits. |
Outline
Overall we have two C files and a few header files. To compile we can use the gcc compiler:
gcc main.c permutations.c printstate.c -o ascon.exe
outline of the C code is [1]:
#include "api.h" #include "ascon.h" #include "crypto_aead.h" #include "permutations.h" #include "printstate.h" #if !ASCON_INLINE_MODE #undef forceinline #define forceinline #endif #define CRYPTO_BYTES 64 void string2hexString(unsigned char* input, int clen, char* output); static unsigned char ascii2byte(char *hexstring, unsigned char *bytearray); int main (int argc, char *argv[]) { unsigned long long mlen; unsigned long long clen; unsigned char plaintext[CRYPTO_BYTES]; unsigned char cipher[CRYPTO_BYTES]; unsigned char npub[CRYPTO_NPUBBYTES]=""; unsigned char ad[CRYPTO_ABYTES]=""; unsigned char nsec[CRYPTO_ABYTES]=""; unsigned char key[CRYPTO_KEYBYTES]; char pl[CRYPTO_BYTES]="hello"; char chex[CRYPTO_BYTES]=""; char keyhex[2*CRYPTO_KEYBYTES+1]="0123456789ABCDEF0123456789ABCDEF"; char nonce[2*CRYPTO_NPUBBYTES+1]="000000000000111111111111"; char add[CRYPTO_ABYTES]=""; if( argc > 1 ) { strcpy(pl,argv[1]); } if( argc > 2 ) { strcpy(keyhex,argv[2]); } if( argc > 3 ) { strcpy(nonce,argv[3]); } if( argc > 4 ) { strcpy(add,argv[4]); } strcpy(plaintext,pl); strcpy(ad,add); ascii2byte(keyhex,key); ascii2byte(nonce,npub); printf("Ascon light-weight cipher\n"); printf("Plaintext: %s\n",plaintext); printf("Key: %s\n",keyhex); printf("Nonce: %s\n",nonce); printf("Additional Information: %s\n\n",ad); printf("Plaintext: %s\n",plaintext); int ret = crypto_aead_encrypt(cipher,&clen,plaintext,strlen(plaintext),ad,strlen(ad),nsec,npub,key); string2hexString(cipher,clen,chex); printf("Cipher: %s, Len: %llu\n",chex, clen); ret = crypto_aead_decrypt(plaintext,&mlen,nsec,cipher,clen,ad,strlen(ad),npub,key); plaintext[mlen]='\0'; printf("Plaintext: %s, Len: %llu\n",plaintext, mlen); if (ret==0) { printf("Success!\n"); } return 0; } forceinline void ascon_loadkey(word_t* K0, word_t* K1, word_t* K2, const uint8_t* k) { KINIT(K0, K1, K2); if (CRYPTO_KEYBYTES == 20) { *K0 = XOR(*K0, KEYROT(WORD_T(0), LOAD(k, 4))); k += 4; } *K1 = XOR(*K1, LOAD(k, 8)); *K2 = XOR(*K2, LOAD(k + 8, 8)); } forceinline void ascon_init(state_t* s, const uint8_t* npub, const uint8_t* k) { /* load nonce */ word_t N0 = LOAD(npub, 8); word_t N1 = LOAD(npub + 8, 8); /* load key */ word_t K0, K1, K2; ascon_loadkey(&K0, &K1, &K2, k); /* initialize */ PINIT(s); if (CRYPTO_KEYBYTES == 16 && ASCON_RATE == 8) s->x0 = XOR(s->x0, ASCON_128_IV); if (CRYPTO_KEYBYTES == 16 && ASCON_RATE == 16) s->x0 = XOR(s->x0, ASCON_128A_IV); if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, ASCON_80PQ_IV); if (CRYPTO_KEYBYTES == 20) s->x0 = XOR(s->x0, K0); s->x1 = XOR(s->x1, K1); s->x2 = XOR(s->x2, K2); s->x3 = XOR(s->x3, N0); s->x4 = XOR(s->x4, N1); P(s, 12); if (CRYPTO_KEYBYTES == 20) s->x2 = XOR(s->x2, K0); s->x3 = XOR(s->x3, K1); s->x4 = XOR(s->x4, K2); printstate("initialization", s); } forceinline void ascon_adata(state_t* s, const uint8_t* ad, uint64_t adlen) { const int nr = (ASCON_RATE == 8) ? 6 : 8; if (adlen) { /* full associated data blocks */ while (adlen >= ASCON_RATE) { s->x0 = XOR(s->x0, LOAD(ad, 8)); if (ASCON_RATE == 16) s->x1 = XOR(s->x1, LOAD(ad + 8, 8)); P(s, nr); ad += ASCON_RATE; adlen -= ASCON_RATE; } /* final associated data block */ word_t* px = &s->x0; if (ASCON_RATE == 16 && adlen >= 8) { s->x0 = XOR(s->x0, LOAD(ad, 8)); px = &s->x1; ad += 8; adlen -= 8; } *px = XOR(*px, PAD(adlen)); if (adlen) *px = XOR(*px, LOAD(ad, adlen)); P(s, nr); } /* domain separation */ s->x4 = XOR(s->x4, WORD_T(1)); printstate("process associated data", s); } forceinline void ascon_encrypt(state_t* s, uint8_t* c, const uint8_t* m, uint64_t mlen) { const int nr = (ASCON_RATE == 8) ? 6 : 8; /* full plaintext blocks */ while (mlen >= ASCON_RATE) { s->x0 = XOR(s->x0, LOAD(m, 8)); STORE(c, s->x0, 8); if (ASCON_RATE == 16) { s->x1 = XOR(s->x1, LOAD(m + 8, 8)); STORE(c + 8, s->x1, 8); } P(s, nr); m += ASCON_RATE; c += ASCON_RATE; mlen -= ASCON_RATE; } /* final plaintext block */ word_t* px = &s->x0; if (ASCON_RATE == 16 && mlen >= 8) { s->x0 = XOR(s->x0, LOAD(m, 8)); STORE(c, s->x0, 8); px = &s->x1; m += 8; c += 8; mlen -= 8; } *px = XOR(*px, PAD(mlen)); if (mlen) { *px = XOR(*px, LOAD(m, mlen)); STORE(c, *px, mlen); } printstate("process plaintext", s); } forceinline void ascon_decrypt(state_t* s, uint8_t* m, const uint8_t* c, uint64_t clen) { const int nr = (ASCON_RATE == 8) ? 6 : 8; /* full ciphertext blocks */ while (clen >= ASCON_RATE) { word_t cx = LOAD(c, 8); s->x0 = XOR(s->x0, cx); STORE(m, s->x0, 8); s->x0 = cx; if (ASCON_RATE == 16) { cx = LOAD(c + 8, 8); s->x1 = XOR(s->x1, cx); STORE(m + 8, s->x1, 8); s->x1 = cx; } P(s, nr); m += ASCON_RATE; c += ASCON_RATE; clen -= ASCON_RATE; } /* final ciphertext block */ word_t* px = &s->x0; if (ASCON_RATE == 16 && clen >= 8) { word_t cx = LOAD(c, 8); s->x0 = XOR(s->x0, cx); STORE(m, s->x0, 8); s->x0 = cx; px = &s->x1; m += 8; c += 8; clen -= 8; } *px = XOR(*px, PAD(clen)); if (clen) { word_t cx = LOAD(c, clen); *px = XOR(*px, cx); STORE(m, *px, clen); *px = CLEAR(*px, clen); *px = XOR(*px, cx); } printstate("process ciphertext", s); } forceinline void ascon_final(state_t* s, const uint8_t* k) { /* load key */ word_t K0, K1, K2; ascon_loadkey(&K0, &K1, &K2, k); /* finalize */ if (CRYPTO_KEYBYTES == 16 && ASCON_RATE == 8) { s->x1 = XOR(s->x1, K1); s->x2 = XOR(s->x2, K2); } if (CRYPTO_KEYBYTES == 16 && ASCON_RATE == 16) { s->x2 = XOR(s->x2, K1); s->x3 = XOR(s->x3, K2); } if (CRYPTO_KEYBYTES == 20) { s->x1 = XOR(s->x1, KEYROT(K0, K1)); s->x2 = XOR(s->x2, KEYROT(K1, K2)); s->x3 = XOR(s->x3, KEYROT(K2, WORD_T(0))); } P(s, 12); s->x3 = XOR(s->x3, K1); s->x4 = XOR(s->x4, K2); printstate("finalization", s); } 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) { state_t s; (void)nsec; *clen = mlen + CRYPTO_ABYTES; /* perform ascon computation */ ascon_init(&s, npub, k); ascon_adata(&s, ad, adlen); ascon_encrypt(&s, c, m, mlen); ascon_final(&s, k); /* set tag */ STOREBYTES(c + mlen, s.x3, 8); STOREBYTES(c + mlen + 8, s.x4, 8); return 0; } 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) { state_t s; (void)nsec; if (clen < CRYPTO_ABYTES) return -1; *mlen = clen = clen - CRYPTO_ABYTES; /* perform ascon computation */ ascon_init(&s, npub, k); ascon_adata(&s, ad, adlen); ascon_decrypt(&s, m, c, clen); ascon_final(&s, k); /* verify tag (should be constant time, check compiler output) */ s.x3 = XOR(s.x3, LOADBYTES(c + clen, 8)); s.x4 = XOR(s.x4, LOADBYTES(c + clen + 8, 8)); return NOTZERO(s.x3, s.x4); }
A sample run is:
ASCON light-weight cipher Plaintext: abc Key: 0123456789ABCDEF0123456789ABCDEF Nonce: AABB000000000111111111111 Additional Information: abc Plaintext: abc Cipher: 0A613CD5FA50ABC0F6C5, Len: 19 Plaintext: abc, Len: 3 Success!
References
[1] ASCON GitHub [here].
[2] Dobraunig, C., Eichlseder, M., Mendel, F., & Schläffer, M. (2016). Ascon v1. 2. Submission to the CAESAR Competition.