#define MIN(x, y) ((x) < (y)) ? (x) : (y) #define ghash_start(buf) memset((buf), 0, 16) void ghash(aes_ctx *ctx, uint8_t *out_buf, const uint8_t *data, size_t len) { uint8_t tbuf[AES_BLOCK_SIZE]; size_t data_offset = 0; // the cache allows for incomplete blocks to be queued // the next call to update will concat the queue and new aad if(ctx->mode.gcm.aad_cache_len){ size_t cache_len = ctx->mode.gcm.aad_cache_len; data_offset = MIN(len, AES_BLOCK_SIZE - cache_len); if(data_offset + cache_len < AES_BLOCK_SIZE){ // if new aad is not enough to fill a block, update queue and stop w/o processing memcpy(&ctx->mode.gcm.aad_cache[cache_len], data, data_offset); ctx->mode.gcm.aad_cache_len += data_offset; return; } else { // if new aad is enough to fill a block, concat queue and rest of block from aad // then update hash memcpy(tbuf, ctx->mode.gcm.aad_cache, ctx->mode.gcm.aad_cache_len); memcpy(&tbuf[cache_len], data, data_offset); xor_buf(tbuf, out_buf, AES_BLOCK_SIZE); aes_gf2_mul(out_buf, out_buf, ctx->mode.gcm.ghash_key); } } // now process any remaining aad data for(uint24_t idx = data_offset; idx < len; idx += AES_BLOCK_SIZE){ size_t bytes_copy = MIN(AES_BLOCK_SIZE, len - idx); if(bytes_copy < AES_BLOCK_SIZE){ // if aad_len < block size, write bytes to queue. // no return here because this condition should just exit out next loop memcpy(ctx->mode.gcm.aad_cache, &data[idx], bytes_copy); ctx->mode.gcm.aad_cache_len = bytes_copy; } else { // if aad_len >= block size, update hash for block memcpy(tbuf, &data[idx], AES_BLOCK_SIZE); memset(&tbuf[bytes_copy], 0, AES_BLOCK_SIZE-bytes_copy); xor_buf(tbuf, out_buf, AES_BLOCK_SIZE); aes_gf2_mul(out_buf, out_buf, ctx->mode.gcm.ghash_key); } } } void aes_gcm_prepare_iv(aes_ctx *ctx, const uint8_t *iv, size_t iv_len) { uint8_t len_buf[16]; memset(ctx->iv, 0, AES_BLOCK_SIZE); if (iv_len == 12) { /* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */ memcpy(ctx->iv, iv, iv_len); ctx->iv[AES_BLOCK_SIZE - 1] = 0x01; } else { /* * s = 128 * ceil(len(IV)/128) - len(IV) * J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64) */ // hash the IV. Pad to block size ghash(ctx, ctx->iv, iv, iv_len); memset(len_buf, 0, 8); memcpy(&len_buf[8], &bitlen, 8); bitlen_to_bytelen(iv_len, &len_buf[8]); // outputs in BE //ll_byte_swap(&len_buf[8]); ghash(ctx, ctx->iv, len_buf, sizeof(len_buf)); } }