/** * Multiply to elements of GF(2**128) using the reducing polynomial * (x^128 + x^7 + x^2 + x + 1). */ static void gcm_mult(uint8_t out[16], const uint8_t x[16], const uint8_t y[16]) { uint64_t z[2], v[2]; int i; /** z, v = 0, y **/ z[0] = z[1] = 0; v[0] = be_to_word(&y[0]); v[1] = be_to_word(&y[8]); for (i=0; i<16; i++) { uint8_t j; for (j=0x80; j>0; j>>=1) { uint64_t c; /** z ^= (x>>i&1)*v **/ if (x[i] & j) { z[0] ^= v[0]; z[1] ^= v[1]; } /** v = (v&1)*0xE1000000000000000000000000000000L ^ (v>>1) **/ c = v[1]&1 ? 0xE100000000000000 : 0; v[1] = v[1]>>1 | (v[0] << 63); v[0] = v[0]>>1 ^ c; } } word_to_be(out, z[0]); word_to_be(out+8, z[1]); }
/** * Create a V table. V[i] is the value H*x^i (i=0..127). * \param h The 16 byte GHASH key * \param tables A pointer to an allocated V table */ static void make_v_tables(const uint8_t h[16], t_v_tables *tables) { uint64_t (*cur)[2]; int i; memset(tables, 0, sizeof(t_v_tables)); cur = &((*tables)[0][1]); (*cur)[0] = be_to_word(&h[0]); (*cur)[1] = be_to_word(&h[8]); for (i=1; i<128; i++) { uint64_t c; uint64_t (*next)[2]; next = &((*tables)[i][1]); /** v = (v&1)*0xE1000000000000000000000000000000L ^ (v>>1) **/ c = (*cur)[1]&1 ? 0xE100000000000000 : 0; (*next)[1] = (*cur)[1]>>1 | (*cur)[0]<<63; (*next)[0] = (*cur)[0]>>1 ^ c; cur = next; } }
/** * Compute H*x^i for i=0..127. Store the results in a new * vector indexed by i. */ static const t_v_tables* make_v_tables(const uint8_t y[16]) { t_v_tables *tables; uint64_t *cur; int i; tables = (t_v_tables*) calloc(128*2, sizeof(uint64_t)); if (!tables) { return NULL; } cur = &((*tables)[0][0]); cur[0] = be_to_word(&y[0]); cur[1] = be_to_word(&y[8]); for (i=1; i<128; i++) { uint64_t c; uint64_t *next; next = &((*tables)[i][0]); /** v = (v&1)*0xE1000000000000000000000000000000L ^ (v>>1) **/ c = cur[1]&1 ? 0xE100000000000000 : 0; next[1] = cur[1]>>1 | cur[0]<<63; next[0] = cur[0]>>1 ^ c; cur = next; } return (const t_v_tables*)tables; }