/** * Compute the GHASH of a piece of data given an arbitrary Y_0, * as specified in NIST SP 800 38D. * * \param y_out The resulting GHASH (16 bytes). * \param block_data Pointer to the data to hash. * \param len Length of the data to hash (multiple of 16). * \param y_in The initial Y (Y_0, 16 bytes). * \param exp_key The expanded hash key (16*256*16 bytes + alignment). * * y_out and y_int can point to the same buffer. */ EXPORT_SYM int ghash( uint8_t y_out[16], const uint8_t block_data[], size_t len, const uint8_t y_in[16], const t_exp_key *exp_key ) { int i; const t_v_tables *v_tables; if (NULL==y_out || NULL==block_data || NULL==y_in || NULL==exp_key) return ERR_NULL; if (len % 16) return ERR_NOT_ENOUGH_DATA; v_tables = (const t_v_tables*)(exp_key->buffer + exp_key->offset); memcpy(y_out, y_in, 16); for (i=0; i<len; i+=16) { int j; uint8_t x[16]; for (j=0; j<16; j++) { x[j] = y_out[j] ^ block_data[i+j]; } gcm_mult2(y_out, v_tables, x); } return 0; }
/** * Compute the GHASH of a piece of an arbitrary data given an * arbitrary Y_0, as specified in NIST SP 800 38D. * * \param y_out The resulting GHASH (16 bytes). * \param block_data Pointer to the data to hash. * \param len Length of the data to hash (multiple of 16). * \param y_in The initial Y (Y_0, 16 bytes). * \param key_tables The hash key, possibly expanded to 16*256*16 bytes. * \param key_tables_len The length of the data pointed by key_table. */ static void ghash( uint8_t y_out[16], const uint8_t block_data[], int len, const uint8_t y_in[16], const void *key_tables, int key_tables_len ) { int i, j; uint8_t x[16]; const t_key_tables *key_tables_64 = NULL; const uint8_t (*key)[16] = NULL; switch (key_tables_len) { case sizeof(t_key_tables): { key_tables_64 = (const t_key_tables*) key_tables; break; } case 16: { key = (const uint8_t (*)[16]) key_tables; break; } default: return; } memcpy(y_out, y_in, 16); if (key_tables_64) { for (i=0; i<len; i+=16) { for (j=0; j<16; j++) { x[j] = y_out[j] ^ block_data[i+j]; } gcm_mult2(y_out, key_tables_64, x); } } else { for (i=0; i<len; i+=16) { for (j=0; j<16; j++) { x[j] = y_out[j] ^ block_data[i+j]; } gcm_mult(y_out, *key, x); } } }