blob: 6c793c23303c9ae85874bfb56f88b73874c28408 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/lib/crypto/aes_gcm/aes_gcm.h"
#include <stddef.h>
#include <stdint.h>
#include "sw/device/lib/base/hardened.h"
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/memory.h"
#include "sw/device/lib/crypto/drivers/aes.h"
enum {
/* Log2 of the number of bytes in an AES block. */
kAesBlockLog2NumBytes = 4,
};
OT_ASSERT_ENUM_VALUE(kAesBlockNumBytes, 1 << kAesBlockLog2NumBytes);
/**
* Precomputed modular reduction constants for Galois field multiplication.
*
* This implementation uses 4-bit windows. The bytes here represent 12-bit
* little-endian values.
*
* The entry with index i in this table is equal to i * 0xe1, where the bytes i
* and 0xe1 are interpreted as polynomials in the GCM Galois field. For
* example, 0xe1 = 0b1110_0001 is the degree-8 polynomial x^8 + x^2 + x + 1.
*
* The field modulus for GCM is 2^128 + x^8 + x^2 + x + 1. Therefore, if a
* field element is shifted, it can be reduced by multiplying the high bits
* (128 and above) by 0xe1 and adding them to the low bits.
*
* There is a size/speed tradeoff in window size. For 8-bit windows, GHASH
* becomes significantly faster, but the overhead for computing the product
* table of a given hash subkey becomes higher, so larger windows are slower
* for smaller inputs but faster for large inputs.
*/
static const uint16_t kGFReduceTable[16] = {
0x0000, 0x201c, 0x4038, 0x6024, 0x8070, 0xa06c, 0xc048, 0xe054,
0x00e1, 0x20fd, 0x40d9, 0x60c5, 0x8091, 0xa08d, 0xc0a9, 0xe0b5};
/**
* Product table for a given hash subkey.
*
* See `make_product_table`.
*/
typedef struct aes_gcm_product_table {
aes_block_t products[16];
} aes_gcm_product_table_t;
/**
* Performs a bitwise XOR of two blocks.
*
* This operation corresponds to addition in the Galois field.
*
* @param x First operand block
* @param y Second operand block
* @param[out] out Buffer in which to store output; can be the same as one or
* both operands.
*/
static inline void block_xor(const aes_block_t *x, const aes_block_t *y,
aes_block_t *out) {
for (size_t i = 0; i < kAesBlockNumWords; ++i) {
out->data[i] = x->data[i] ^ y->data[i];
}
}
/**
* Reverse the bits of a 4-bit number.
*
* @param byte Input byte.
* @return byte with lower 4 bits reversed and upper 4 unmodified.
*/
static uint8_t reverse_bits(uint8_t byte) {
/* TODO: replace with rev.n (from 0.93 draft of bitmanip) once bitmanip
* extension is enabled. */
uint8_t out = 0;
for (size_t i = 0; i < 4; ++i) {
out <<= 1;
out |= (byte >> i) & 1;
}
return out;
}
/**
* Reverse the bytes of a 32-bit word.
*
* This function is convenient for converting between the processor's native
* integers, which are little-endian, and NIST's integer representation, which
* is big-endian.
*
* @param word Input word.
* @return Word with bytes reversed.
*/
static uint32_t reverse_bytes(uint32_t word) {
/* TODO: replace with rev8 once bitmanip extension is enabled. */
uint32_t out = 0;
for (size_t i = 0; i < sizeof(uint32_t); ++i) {
out <<= 8;
out |= (word >> (i << 3)) & 255;
}
return out;
}
/**
* Logical right shift of an AES block.
*
* NIST represents AES blocks as big-endian, and a "right shift" in that
* representation means shifting out the LSB. However, the processor is
* little-endian, so we need to reverse the bytes before shifting.
*
* @param block Input AES block, modified in-place
* @param nbits Number of bits to shift
*/
static inline void block_shiftr(aes_block_t *block, size_t nbits) {
// To perform a "right shift" with respect to the big-endian block
// representation, we traverse the words of the block and, for each word,
// reverse the bytes, save the new LSB as `carry`, shift right, set the MSB
// to the last block's carry, and then reverse the bytes back.
uint32_t carry = 0;
for (size_t i = 0; i < kAesBlockNumWords; ++i) {
uint32_t rev = reverse_bytes(block->data[i]);
uint32_t next_carry = rev & ((1 << nbits) - 1);
rev >>= nbits;
rev |= carry << (32 - nbits);
carry = next_carry;
block->data[i] = reverse_bytes(rev);
}
}
/**
* Retrieve the byte at a given index from the AES block.
*
* @param block Input AES block
* @param index Index of byte to retrieve (must be < `kAesBlockNumBytes`)
* @return Value of block[index]
*/
static inline uint8_t block_byte_get(const aes_block_t *block, size_t index) {
return (uint8_t)((char *)block->data)[index];
}
/**
* Get the size of the last block for a given input size.
*
* Equivalent to `sz % kAesBlockNumBytes`, except that if `sz` is a multiple of
* `kAesBlockNumBytes` then this will return `kAesBlockNumBytes` (since the
* last block would then be a full block).
*
* Assumes that `sz` is nonzero.
*
* @param sz Number of bytes in the buffer, must be nonzero
* @return Number of bytes in the last block
*/
static inline size_t get_last_block_num_bytes(size_t sz) {
size_t remainder = sz % kAesBlockNumBytes;
if (remainder == 0) {
return kAesBlockNumBytes;
}
return remainder;
}
/**
* Get the minimum number of AES blocks needed to represent `sz` bytes.
*
* This routine does not run in constant time and should not be used for
* sensitive input values.
*
* @param sz Number of bytes to represent
* @return Minimum number of blocks needed
*/
static inline size_t get_nblocks(size_t sz) {
size_t out = sz >> kAesBlockLog2NumBytes;
if (get_last_block_num_bytes(sz) != kAesBlockNumBytes) {
out += 1;
}
return out;
}
/**
* Increment a 32-bit big-endian word.
*
* This operation theoretically increments the "rightmost" (last) 32 bits of
* the input modulo 2^32. However, NIST treats all bitvectors as big-endian and
* the processor is little-endian. In order to increment we first need to
* reverse the bytes of the 32-bit word, then increment, then reverse it back.
*
* @param word Input word in big-endian form.
* @returns (word + 1) mod 2^32 in big-endian form.
*/
static inline uint32_t word_inc32(const uint32_t word) {
// Reverse the bytes, increment, and reverse back.
return reverse_bytes(reverse_bytes(word) + 1);
}
/**
* Implements the inc32() function on blocks from NIST SP800-38D.
*
* Interprets the last (rightmost) 32 bits of the block as a big-endian integer
* and increments this value modulo 2^32 in-place.
*
* @param block AES block, modified in place.
*/
static inline void block_inc32(aes_block_t *block) {
// Set the last word to the incremented value.
block->data[kAesBlockNumWords - 1] =
word_inc32(block->data[kAesBlockNumWords - 1]);
}
/**
* Multiply an element of the GCM Galois field by the polynomial `x`.
*
* This corresponds to a shift right in the bit representation, and then
* reduction with the field modulus.
*
* Runs in constant time.
*
* @param p Polynomial to be multiplied
* @param[out] out Buffer for output
*/
static inline void galois_mulx(const aes_block_t *p, aes_block_t *out) {
// Get the very rightmost bit of the input block (coefficient of x^127).
uint8_t p127 = block_byte_get(p, kAesBlockNumBytes - 1) & 1;
// Set the output to p >> 1.
memcpy(out->data, p->data, kAesBlockNumBytes);
block_shiftr(out, 1);
// If the highest coefficient was 1, then subtract the polynomial that
// corresponds to (modulus - 2^128).
uint32_t mask = 0 - p127;
out->data[0] ^= (0xe1 & mask);
}
/**
* Construct a product table for the hash subkey H.
*
* The product table entry at index i is equal to i * H, where both i and H are
* interpreted as Galois field polynomials.
*
* @param H Hash subkey
* @param[out] product_table Buffer for output
*/
static void make_product_table(const aes_block_t *H,
aes_gcm_product_table_t *tbl) {
// Initialize 0 * H = 0.
memset(tbl->products[0].data, 0, kAesBlockNumBytes);
// Initialize 1 * H = H.
memcpy(tbl->products[0x8].data, H->data, kAesBlockNumBytes);
// To get remaining entries, we use a variant of "shift and add"; in
// polynomial terms, a shift is a multiplication by x. Note that, because the
// processor represents bytes with the MSB on the left and NIST uses a fully
// little-endian polynomial representation with the MSB on the right, we have
// to reverse the bits of the indices.
for (size_t i = 2; i < 16; i += 2) {
// Find the product corresponding to (i >> 1) * H and multiply by x to
// shift 1; this will be i * H.
galois_mulx(&tbl->products[reverse_bits(i >> 1)],
&tbl->products[reverse_bits(i)]);
// Add H to i * H to get (i + 1) * H.
block_xor(&tbl->products[reverse_bits(i)], H,
&tbl->products[reverse_bits(i + 1)]);
}
}
/**
* Computes the "product block" as defined in NIST SP800-38D, section 6.3.
*
* The NIST documentation shows a very slow double-and-add algorithm, which
* iterates through the first operand bit-by-bit. However, since the second
* operand is always the hash subkey H, we can speed things up significantly
* with a little precomputation.
*
* The `tbl` input should be a precomputed table with the products of H and
* 256 all possible byte values (see `make_product_table`).
*
* This operation corresponds to multiplication in the Galois field with order
* 2^128, modulo the polynomial x^128 + x^8 + x^2 + x + 1
*
* @param p Polynomial to multiply
* @param tbl Precomputed product table for the hash subkey
* @param[out] result Block in which to store output
*/
static void galois_mul(const aes_block_t *p, const aes_gcm_product_table_t *tbl,
aes_block_t *result) {
// Initialize the result to 0.
memset(result->data, 0, kAesBlockNumBytes);
// 4-bit windows, so number of windows is 2x number of bytes.
const size_t kNumWindows = kAesBlockNumBytes << 1;
// To compute the product, we iterate through the bytes of the input block,
// considering the most significant (in polynomial terms) first. For each
// byte b, we:
// * multiply `result` by x^8 (shift all coefficients to the right)
// * reduce the shifted `result` modulo the field modulus
// * look up the product `b * H` and add it to `result`
//
// We can skip the shift and reduce steps on the first iteration, since
// `result` is 0.
for (size_t i = 0; i < kNumWindows; ++i) {
if (i != 0) {
// Save the most significant half-byte of `result` before shifting.
uint8_t overflow = block_byte_get(result, kAesBlockNumBytes - 1) & 0x0f;
// Shift `result` to the right, discarding high bits.
block_shiftr(result, 4);
// Look up the product of `overflow` and the low terms of the modulus in
// the precomputed table.
uint16_t reduce_term = kGFReduceTable[overflow];
// Add (xor) this product to the low bits to complete modular reduction.
// This works because (low + x^128 * high) is equivalent to (low + (x^128
// - modulus) * high).
result->data[0] ^= reduce_term;
}
// Add the product of the next window and H to `result`. We process the
// windows starting with the most significant polynomial terms, which means
// starting from the last byte and proceeding to the first.
uint8_t pi = block_byte_get(p, (kNumWindows - 1 - i) >> 1);
// Select the less significant 4 bits if i is even, or the more significant
// 4 bits if i is odd. This does not need to be constant time, since the
// values of i in this loop are constant.
if ((i & 1) == 1) {
pi >>= 4;
} else {
pi &= 0x0f;
}
block_xor(result, &tbl->products[pi], result);
}
}
/**
* Advances the GHASH state for the given input.
*
* This function is convenient for computing the GHASH of large, concatenated
* buffers. Given a state representing GHASH(A) and a new input B, this
* function will return a state representing GHASH(A || B || <padding for B>).
*
* Pads the input with 0s on the right-hand side if needed so that the input
* size is a multiple of the block size.
*
* The product table should match the format from `make_product_table`.
*
* @param tbl Precomputed product table
* @param input_len Length of input in bytes
* @param input Input buffer
* @param state GHASH state, updated in place
*/
static void aes_gcm_ghash_update(const aes_gcm_product_table_t *tbl,
const size_t input_len, const uint8_t *input,
aes_block_t *state) {
// Calculate the number of AES blocks needed for the input.
size_t nblocks = get_nblocks(input_len);
// Main loop.
for (size_t i = 0; i < nblocks; ++i) {
// Construct block i of the input.
aes_block_t input_block;
if (i == nblocks - 1) {
// Last block may be partial; pad with zeroes.
size_t nbytes = get_last_block_num_bytes(input_len);
memset(input_block.data, 0, kAesBlockNumBytes);
memcpy(input_block.data, input, nbytes);
} else {
// Full block; copy data and advance input pointer.
memcpy(input_block.data, input, kAesBlockNumBytes);
input += kAesBlockNumBytes;
}
// XOR `state` with the next input block.
block_xor(state, &input_block, state);
// Multiply state by H and update.
aes_block_t yH;
galois_mul(state, tbl, &yH);
memcpy(state->data, yH.data, kAesBlockNumBytes);
}
}
aes_error_t aes_gcm_ghash(const aes_block_t *hash_subkey,
const size_t input_len, const uint8_t *input,
aes_block_t *output) {
// Compute the product table for H.
aes_gcm_product_table_t tbl;
make_product_table(hash_subkey, &tbl);
// If the input length is not a multiple of the block size, fail.
if (get_last_block_num_bytes(input_len) != kAesBlockNumBytes) {
return kAesInternalError;
}
// Initialize the GHASH state to 0.
memset(output->data, 0, kAesBlockNumBytes);
// Update the GHASH state with the input.
aes_gcm_ghash_update(&tbl, input_len, input, output);
return kAesOk;
}
/**
* One-shot version of the AES API for a single block, for convenience.
*/
static aes_error_t aes_single_block(const aes_params_t params,
const aes_block_t *input,
aes_block_t *output) {
aes_error_t err = aes_begin(params);
if (err != kAesOk) {
return err;
}
err = aes_update(output, input);
if (err != kAesOk) {
return err;
}
err = aes_end();
if (err != kAesOk) {
return err;
}
return kAesOk;
}
/**
* Implements the GCTR function as specified in SP800-38D, section 6.5.
*
* The block cipher is fixed to AES. Note that the GCTR function is a modified
* version of the AES-CTR mode of encryption.
*
* Input must be less than 2^32 blocks long; that is, `len` < 2^36, since each
* block is 16 bytes.
*
* @param key_len length of the AES key
* @param key_shares key, expressed in two shares
* @param icb Initial counter block, 128 bits
* @param len Number of bytes for input and output
* @param input Pointer to input buffer (may be NULL if `len` is 0)
* @param[out] output Pointer to output buffer (same size as input, may be the
* same buffer)
*/
aes_error_t aes_gcm_gctr(const aes_key_len_t key_len,
const uint32_t *key_shares[2], const aes_block_t *icb,
const size_t len, const uint8_t *input,
uint8_t *output) {
// If the input is empty, the output must be as well. Since the output length
// is 0, simply return.
if (len == 0) {
return kAesOk;
}
// NULL pointers are not allowed for nonzero input length.
if (input == NULL || output == NULL) {
return kAesInternalError;
}
// Prepare AES parameters for AES-CTR encryption. Encrypting a single block B
// with these parameters will return AES_K(IV) ^ B, where AES_K is the core
// AES block cipher encryption operation using key K.
aes_params_t aes_ctr_params = {
.encrypt = true,
.mode = kAesCipherModeCtr,
.key_len = key_len,
.key = {key_shares[0], key_shares[1]},
.iv = {0},
};
memcpy(aes_ctr_params.iv, icb->data, kAesBlockNumBytes);
// Calculate the number of blocks needed to represent the input. Since we
// checked for empty input above, nblocks must be at least 1.
size_t nblocks = get_nblocks(len);
for (size_t i = 0; i < nblocks; ++i) {
// Retrieve the next block of input. All blocks are full-size except for
// the last block, which may be partial. If the block is partial, the input
// data will be padded with zeroes.
aes_block_t block_in;
size_t nbytes = kAesBlockNumBytes;
if (i == nblocks - 1) {
// Last block is partial; copy the bytes that exist and set the rest of
// the block to 0.
nbytes = get_last_block_num_bytes(len);
memset(block_in.data, 0, kAesBlockNumBytes);
memcpy(block_in.data, &input[i * kAesBlockNumBytes], nbytes);
} else {
// This block is a full block.
memcpy(block_in.data, &input[i * kAesBlockNumBytes], kAesBlockNumBytes);
}
// Run the AES-CTR encryption operation on the next block of input.
aes_block_t block_out;
aes_error_t err = aes_single_block(aes_ctr_params, &block_in, &block_out);
if (err != kAesOk) {
return err;
}
// Copy the result block into the output buffer, truncating some bytes if
// the input block was partial.
memcpy(&output[i * kAesBlockNumBytes], block_out.data, nbytes);
// Update the counter block.
aes_ctr_params.iv[kAesBlockNumWords - 1] =
word_inc32(aes_ctr_params.iv[kAesBlockNumWords - 1]);
}
return kAesOk;
}
/**
* Verify that the lengths of AES-GCM parameters are acceptable.
*
* This routine can be used for both authenticated encryption and authenticated
* decryption; the lengths of the plaintext and ciphertext always match, and
* `plaintext_len` may represent either.
*
* @param iv_len IV length in bytes
* @param plaintext_len Plaintext/ciphertext length in bytes
* @param aad_len Associated data length in bytes
*/
static hardened_bool_t check_buffer_lengths(const size_t iv_len,
const size_t plaintext_len,
const size_t aad_len) {
// Check IV length (must be 96 or 128 bits = 12 or 16 bytes).
if (iv_len != 12 && iv_len != 16) {
return kHardenedBoolFalse;
}
// Check plaintext/AAD length. Both must be less than 2^32 bytes long. This
// is stricter than NIST requires, but SP800-38D also allows implementations
// to stipulate lower length limits.
if (plaintext_len > UINT32_MAX || aad_len > UINT32_MAX) {
return kHardenedBoolFalse;
}
return kHardenedBoolTrue;
}
/**
* Compute the hash subkey for AES-GCM.
*
* This routine computes the hash subkey H and the product table for H; see
* `make_product_table` for representation details.
*
* If any step in this process fails, the function returns an error and the
* output should not be used.
*
* @param key_len length of key
* @param key_shares key, expressed in two shares
* @param[out] tbl Destination for the output hash subkey product table
* @return OK or error
*/
static aes_error_t aes_gcm_hash_subkey(const aes_key_len_t key_len,
const uint32_t *key_shares[2],
aes_gcm_product_table_t *tbl) {
// Set AES parameters to perform AES-CTR encryption with IV=0.
aes_params_t aes_ctr_params = {
.encrypt = true,
.mode = kAesCipherModeCtr,
.key_len = key_len,
.key = {key_shares[0], key_shares[1]},
.iv = {0},
};
// Compute the initial hash subkey H = AES_K(0). Note that to get this
// result from AES_CTR, we set both the IV and plaintext to zero; this way,
// AES-CTR's final XOR with the plaintext does nothing.
aes_block_t zero;
memset(zero.data, 0, kAesBlockNumBytes);
aes_block_t hash_subkey;
aes_error_t err = aes_single_block(aes_ctr_params, &zero, &hash_subkey);
if (err != kAesOk) {
return err;
}
// Compute the product table for H.
make_product_table(&hash_subkey, tbl);
return kAesOk;
}
/**
* Compute the counter block based on the given IV and hash subkey.
*
* This block is called J0 in the NIST documentation, and is the same for both
* encryption and decryption.
*
* @param iv_len IV length in bytes
* @param iv IV value
* @param tbl Product table for the hash subkey H
* @param[out] j0 Destination for the output counter block
* @return OK or error
*/
static aes_error_t aes_gcm_counter(const size_t iv_len, const uint8_t *iv,
aes_gcm_product_table_t *tbl,
aes_block_t *j0) {
if (iv_len == 12) {
// If the IV is 96 bits, then J0 = (IV || {0}^31 || 1).
memcpy(j0->data, iv, iv_len);
// Set the last word to 1 (as a big-endian integer).
j0->data[kAesBlockNumWords - 1] = reverse_bytes(1);
} else if (iv_len == 16) {
// If the IV is 128 bits, then J0 = GHASH(H, IV || {0}^120 || 0x80), where
// {0}^120 means 120 zero bits (15 0x00 bytes).
memset(j0->data, 0, kAesBlockNumBytes);
aes_gcm_ghash_update(tbl, iv_len, iv, j0);
uint8_t buffer[kAesBlockNumBytes];
memset(buffer, 0, kAesBlockNumBytes);
buffer[kAesBlockNumBytes - 1] = 0x80;
aes_gcm_ghash_update(tbl, kAesBlockNumBytes, buffer, j0);
} else {
// Should not happen; invalid IV length.
return kAesInternalError;
}
return kAesOk;
}
/**
* Compute the AES-GCM authentication tag.
*
* @param key_len Length of the AES key
* @param key_shares AES key, split into two shares
* @param tbl Product table for the hash subkey H
* @param ciphertext_len Length of the ciphertext in bytes
* @param ciphertext Ciphertext value
* @param aad_len Length of the associated data in bytes
* @param aad Associated data value
* @param j0 Counter block (J0 in the NIST specification)
* @param[out] tag Buffer for output tag (128 bits)
*/
static aes_error_t aes_gcm_compute_tag(const aes_key_len_t key_len,
const uint32_t *key_shares[2],
const aes_gcm_product_table_t *tbl,
const size_t ciphertext_len,
const uint8_t *ciphertext,
const size_t aad_len, const uint8_t *aad,
const aes_block_t *j0, uint8_t *tag) {
// Compute S = GHASH(H, expand(A) || expand(C) || len64(A) || len64(C))
// where:
// * A is the aad, C is the ciphertext
// * expand(x) pads x to a multiple of 128 bits by adding zeroes to the
// right-hand side
// * len64(x) is the length of x in bits expressed as a
// big-endian 64-bit integer.
// Compute GHASH(H, expand(A) || expand(C)).
aes_block_t s;
memset(s.data, 0, kAesBlockNumBytes);
aes_gcm_ghash_update(tbl, aad_len, aad, &s);
aes_gcm_ghash_update(tbl, ciphertext_len, ciphertext, &s);
// Compute len64(A) and len64(C) by computing the length in *bits* (shift by
// 3) and then converting to big-endian.
uint64_t last_block[2] = {
__builtin_bswap64(((uint64_t)aad_len) * 8),
__builtin_bswap64(((uint64_t)ciphertext_len) * 8),
};
// Use memcpy() to avoid violating strict aliasing when converting to bytes.
uint8_t last_block_bytes[sizeof(last_block)];
memcpy(last_block_bytes, last_block, sizeof(last_block));
// Finish computing S by appending (len64(A) || len64(C)).
aes_gcm_ghash_update(tbl, kAesBlockNumBytes, last_block_bytes, &s);
// Compute the tag T = GCTR(K, J0, S).
uint8_t s_data_bytes[sizeof(s.data)];
memcpy(s_data_bytes, s.data, sizeof(s.data));
return aes_gcm_gctr(key_len, key_shares, j0, kAesBlockNumBytes, s_data_bytes,
tag);
}
aes_error_t aes_gcm_encrypt(const aes_key_len_t key_len,
const uint32_t *key_shares[2], const size_t iv_len,
const uint8_t *iv, const size_t plaintext_len,
const uint8_t *plaintext, const size_t aad_len,
const uint8_t *aad, uint8_t *ciphertext,
uint8_t *tag) {
// Check that the input parameter sizes are valid.
if (check_buffer_lengths(iv_len, plaintext_len, aad_len) !=
kHardenedBoolTrue) {
return kAesInternalError;
}
// Compute the hash subkey H as a product table.
aes_gcm_product_table_t Htbl;
aes_error_t err = aes_gcm_hash_subkey(key_len, key_shares, &Htbl);
if (err != kAesOk) {
return err;
}
// Compute the counter block (called J0 in the NIST specification).
aes_block_t j0;
err = aes_gcm_counter(iv_len, iv, &Htbl, &j0);
if (err != kAesOk) {
return err;
}
// Compute inc32(J0).
aes_block_t j0_inc;
memcpy(j0_inc.data, j0.data, kAesBlockNumBytes);
block_inc32(&j0_inc);
// Compute ciphertext C = GCTR(K, inc32(J0), plaintext).
err = aes_gcm_gctr(key_len, key_shares, &j0_inc, plaintext_len, plaintext,
ciphertext);
if (err != kAesOk) {
return err;
}
// Compute the authentication tag T.
return aes_gcm_compute_tag(key_len, key_shares, &Htbl, plaintext_len,
ciphertext, aad_len, aad, &j0, tag);
}