encrypt.c 4.35 KB
Newer Older
1
#include <string.h>
2
#include "cofb.h"
3 4
#include "giftb128.h"

5
static inline void padding(u32* d, const u32* s, const u32 no_of_bytes){
6 7
    u32 i;
    if (no_of_bytes == 0) {
8 9 10 11
        d[0] = 0x00000080; // little-endian
        d[1] = 0x00000000;
        d[2] = 0x00000000;
        d[3] = 0x00000000;
12 13 14
    }
    else if (no_of_bytes < GIFT128_BLOCK_SIZE) {
        for (i = 0; i < no_of_bytes/4+1; i++)
15 16 17
            d[i] = s[i];
        d[i-1] &= ~(0xffffffffL << (no_of_bytes % 4)*8);
        d[i-1] |= 0x00000080L << (no_of_bytes % 4)*8;
18
        for (; i < 4; i++)
19
            d[i] = 0x00000000;
20 21
    }
    else {
22 23 24 25
        d[0] = s[0];
        d[1] = s[1];
        d[2] = s[2];
        d[3] = s[3];
26 27 28 29 30 31 32
    }
}

/****************************************************************************
* 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).
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
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;
}

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);
}

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);
}