encrypt.c 5.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/*******************************************************************************
* Constant-time 32-bit implementation of the GIFT-COFB authenticated cipher.
* 
* @author   Alexandre Adomnicai, Nanyang Technological University,
*           alexandre.adomnicai@ntu.edu.sg
* @date     January 2020
*******************************************************************************/
#include <string.h>
#include "giftb128.h"
#include "giftcofb128v1.h"

static inline void padding(u32* dest, const u32* src, const u32 no_of_bytes) {
    u32 i;
    if (no_of_bytes == 0) {
        dest[0] = 0x00000080; // little-endian
        dest[1] = 0x00000000;
        dest[2] = 0x00000000;
        dest[3] = 0x00000000;
    }
    else if (no_of_bytes < GIFT128_BLOCK_SIZE) {
        for (i = 0; i < no_of_bytes/4+1; i++)
            dest[i] = src[i];
        dest[i-1] &= ~(0xffffffffL << (no_of_bytes % 4)*8);
        dest[i-1] |= 0x00000080L << (no_of_bytes % 4)*8;
        for (; i < 4; i++)
            dest[i] = 0x00000000;
    }
    else {
        dest[0] = src[0];
        dest[1] = src[1];
        dest[2] = src[2];
        dest[3] = src[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 'mode' 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, offset[2];
    u32 input[4], rkey[80];
    u8 Y[GIFT128_BLOCK_SIZE];

    if (!encrypting) {
        if (in_len < TAG_SIZE)
            return -1;
        in_len -= TAG_SIZE;
    }

    if(ad_len == 0)
        emptyA = 1;
    else
        emptyA = 0;

    if(in_len == 0)
        emptyM =1;
    else
        emptyM = 0;

    gift128_keyschedule(key, rkey);
    giftb128_encrypt_block(Y, rkey, nonce);
    offset[0] = ((u32*)Y)[0];
    offset[1] = ((u32*)Y)[1];

    while(ad_len > GIFT128_BLOCK_SIZE){
        RHO1(input, (u32*)Y, (u32*)ad, GIFT128_BLOCK_SIZE);
        DOUBLE_HALF_BLOCK(offset);
        XOR_TOP_BAR_BLOCK(input, offset);
        giftb128_encrypt_block(Y, rkey, (u8*)input);
        ad += GIFT128_BLOCK_SIZE;
        ad_len -= GIFT128_BLOCK_SIZE;
    }
    
    TRIPLE_HALF_BLOCK(offset);
    if((ad_len % GIFT128_BLOCK_SIZE != 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_encrypt_block(Y, rkey, (u8*)input);

    while (in_len > GIFT128_BLOCK_SIZE){
        DOUBLE_HALF_BLOCK(offset);
        if (encrypting)
            RHO((u32*)Y, (u32*)in, input, (u32*)out, GIFT128_BLOCK_SIZE);
        else
            RHO_PRIME((u32*)Y, (u32*)in, input, (u32*)out, GIFT128_BLOCK_SIZE);
        XOR_TOP_BAR_BLOCK(input, offset);
        giftb128_encrypt_block(Y, rkey, (u8*)input);
        in += GIFT128_BLOCK_SIZE;
        out += GIFT128_BLOCK_SIZE;
        in_len -= GIFT128_BLOCK_SIZE;
    }
    
    if(!emptyM){
        TRIPLE_HALF_BLOCK(offset);
        if(in_len % GIFT128_BLOCK_SIZE != 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_encrypt_block(Y, rkey, (u8*)input);
    }
    
    if (encrypting) { // encryption mode
        memcpy(out, Y, TAG_SIZE);
        return 0;
    }
    // decrypting
    tmp0 = 0;
    for(tmp1 = 0; tmp1 < TAG_SIZE; 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 + TAG_SIZE;
    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 - TAG_SIZE;
    return giftcofb_crypt(m, k, npub, ad, adlen, c, clen, COFB_DECRYPT);
}