GIFT-COFB - Light-weight cipherGIFT-COFB is a light-weight crypto cipher created by Subhadeep Banik, Avik Chakraborti, Tetsu Iwata, Kazuhiko Minematsu Mridul Nandi, Thomas Peyrin, Yu Sasaki, Siang Meng Sim and Yosuke Todo [3]. It uses a COFB (COmbined FeedBack) block cipher based AEAD mode using the GIFT-128 block cipher [2]. Overall GIFT is similar to a smaller version of PRESENT. It is thought that GIFT has better performance than SIMON and SKINNY. GIFT-COFB fixes 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. |
Outline
Overall we have two C files and a few header files. To compile we can use the gcc compiler:
gcc main.c giftb128.c -o gift.exe
An outline of the C code is [1]:
/******************************************************************************* * 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:
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] Gift GitHub [here].
[2] 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.
[3] 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).