GIFT: A Small Present for Cybersecurity and IoT

The PRESENT cipher supported a light-weight approach to encryption, and is well suited to resource-limited devices. A paper in 2017 by…

Photo by Kira auf der Heide on Unsplash

GIFT: A Small Present for Cybersecurity and IoT

The PRESENT cipher supported a lightweight approach to encryption and is well suited to resource-limited devices. A paper in 2017 by Banik et al showed an extension of this method and which created an even smaller footprint, and more optimized for hardware [1]:

It also fixed some of the security weaknesses of PRESENT. As many systems are now looking to authenticate encryption with AEAD (Authenticated Encryption with Additional Data). With AEAD we add in extra data and which can be used to authenticate the connected cipertext. For example, with network packets, we could add in the source port and sequence number into the additional data, and where these were used to perform the authentication. The AEAD addition was then added through a submission to the NIST competition for lightweight cryptography with GIFT-COFB [2]. In Round 1, there were 56 cipher methods submitted, and this has been reduced down, to the last 10 in the final round.

GIFT-COFB is a lightweight crypto cipher created by Subhadeep Banik, Avik Chakraborti, Tetsu Iwata, Kazuhiko Minematsu Mridul Nandi, Thomas Peyrin, Yu Sasaki, Siang Meng Sim and Yosuke Todo. It uses a COFB (COmbined FeedBack) block cipher based AEAD mode using the GIFT-128 block cipher. Overall GIFT is similar to a smaller version of PRESENT. It is thought that GIFT has better performance than SIMON and SKINNY.

The final round will take until March 2022 to be completed, and the key metrics for the evaluation are: side-channel and fault attack resistance, cost, performance, third-party analysis, and suitability for hardware and software.

Overall we have two C files and a few header files. To compile we can use the gcc compiler:

gcc main.c giftb129.c -o gift.exe

An outline of the C code is [1] [here]:

/*******************************************************************************
* Constant-time 32-bit implementation of the GIFT-COFB authenticated cipher.
*
* See "Fixslicing: A New GIFT Representation" paper available at
* https://eprint.iacr.org/2020/412.pdf for more details on the fixsliced
* representation.
*******************************************************************************/
#include "api.h"
#include "cofb.h"
#include "giftb128.h"
#define TAGBYTES        CRYPTO_ABYTES
#define BLOCKBYTES CRYPTO_ABYTES
#define COFB_ENCRYPT 1
#define COFB_DECRYPT 0
#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("GIFT 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;
}
/****************************************************************************
* 32-bit padding implementation.
****************************************************************************/
static inline void padding(u32* d, const u32* s, const u32 no_of_bytes){
u32 i;
if (no_of_bytes == 0) {
d[0] = 0x00000080; // little-endian
d[1] = 0x00000000;
d[2] = 0x00000000;
d[3] = 0x00000000;
}
else if (no_of_bytes < BLOCKBYTES) {
for (i = 0; i < no_of_bytes/4+1; i++)
d[i] = s[i];
d[i-1] &= ~(0xffffffffL << (no_of_bytes % 4)*8);
d[i-1] |= 0x00000080L << (no_of_bytes % 4)*8;
for (; i < 4; i++)
d[i] = 0x00000000;
}
else {
d[0] = s[0];
d[1] = s[1];
d[2] = s[2];
d[3] = s[3];
}
}
/****************************************************************************
* Constant-time implementation of the GIFT-COFB authenticated cipher based on
* fixsliced GIFTb-128. Encryption/decryption is handled by the same function,
* depending on the 'encrypting' parameter (1/0).
****************************************************************************/
int giftcofb_crypt(u8* out, const u8* key, const u8* nonce, const u8* ad,
u32 ad_len, const u8* in, u32 in_len, const int encrypting) {
    u32 tmp0, tmp1, emptyA, emptyM;
u32 offset[2], input[4], rkey[80];
u8 Y[16];
    if (!encrypting) {
if (in_len < TAGBYTES)
return -1;
in_len -= TAGBYTES;
}
    if (ad_len == 0)
emptyA = 1;
else
emptyA = 0;
    if (in_len == 0)
emptyM =1;
else
emptyM = 0;
    precompute_rkeys(rkey, key);
giftb128(Y, nonce, rkey);
offset[0] = ((u32*)Y)[0];
offset[1] = ((u32*)Y)[1];
    while (ad_len > BLOCKBYTES) {
RHO1(input, (u32*)Y, (u32*)ad, BLOCKBYTES);
DOUBLE_HALF_BLOCK(offset);
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
ad += BLOCKBYTES;
ad_len -= BLOCKBYTES;
}

TRIPLE_HALF_BLOCK(offset);
if ((ad_len % BLOCKBYTES != 0) || (emptyA))
TRIPLE_HALF_BLOCK(offset);
if (emptyM) {
TRIPLE_HALF_BLOCK(offset);
TRIPLE_HALF_BLOCK(offset);
}
    RHO1(input, (u32*)Y, (u32*)ad, ad_len);
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
    while (in_len > BLOCKBYTES) {
DOUBLE_HALF_BLOCK(offset);
if (encrypting)
RHO((u32*)Y, (u32*)in, input, (u32*)out, BLOCKBYTES);
else
RHO_PRIME((u32*)Y, (u32*)in, input, (u32*)out, BLOCKBYTES);
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
in += BLOCKBYTES;
out += BLOCKBYTES;
in_len -= BLOCKBYTES;
}

if (!emptyM) {
TRIPLE_HALF_BLOCK(offset);
if(in_len % BLOCKBYTES != 0)
TRIPLE_HALF_BLOCK(offset);
if (encrypting) {
RHO((u32*)Y, (u32*)in, input, (u32*)out, in_len);
out += in_len;
}
else {
RHO_PRIME((u32*)Y, (u32*)in, input, (u32*)out, in_len);
in += in_len;
}
XOR_TOP_BAR_BLOCK(input, offset);
giftb128(Y, (u8*)input, rkey);
}
    if (encrypting) {
memcpy(out, Y, TAGBYTES);
return 0;
}
// decrypting
tmp0 = 0;
for(tmp1 = 0; tmp1 < TAGBYTES; tmp1++)
tmp0 |= in[tmp1] ^ Y[tmp1];
return tmp0;
}
/****************************************************************************
* API required by the NIST for the LWC competition.
****************************************************************************/
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) {
(void)nsec;
*clen = mlen + TAGBYTES;
return giftcofb_crypt(c, k, npub, ad, adlen, m, mlen, COFB_ENCRYPT);
}
/****************************************************************************
* API required by the NIST for the LWC competition.
****************************************************************************/
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) {
(void)nsec;
*mlen = clen - TAGBYTES;
return giftcofb_crypt(m, k, npub, ad, adlen, c, clen, COFB_DECRYPT);
}

A sample run is [here]:

GIFT light-weight cipher
Plaintext: abc
Key: 0123456789ABCDEF0123456789ABCDEF
Nonce: AABB000000000111111111111
Additional Information: abc
Plaintext: abc
Cipher: 90387420E4F5452A517C, Len: 19
Plaintext: abc, Len: 3
Success!

References

[1] Banik, S., Pandey, S. K., Peyrin, T., Sasaki, Y., Sim, S. M., & Todo, Y. (2017, September). GIFT: a small present. In International Conference on Cryptographic Hardware and Embedded Systems (pp. 321–345). Springer, Cham.

[2] Banik, Subhadeep, Avik Chakraborti, Tetsu Iwata, Kazuhiko Minematsu, Mridul Nandi, Thomas Peyrin, Yu Sasaki, Siang Meng Sim, and Yosuke Todo. “Gift-cofb.” Submission to Round 1 (2019).