Reworking bssl_crypto: support AES-GCM-SIV open_gather.
On x86-64, the Rust tests notice that open_gather wasn't implemented for
AES-GCM-SIV when the assembly code is used. Fix that.
Change-Id: I7de9d009922bcc0ed7e3e2f8a7a3cfb671893d63
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65187
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl b/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl
index e044259..6241237 100644
--- a/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl
+++ b/crypto/cipher_extra/asm/aes128gcmsiv-x86_64.pl
@@ -1257,14 +1257,15 @@
.L${labelPrefix}_dec_start:
vzeroupper
vmovdqa ($POL), $T
+ # The claimed tag is provided after the current calculated tag value.
+ # CTRBLKs is made from it.
+ vmovdqu 16($POL), $CTR
+ vpor OR_MASK(%rip), $CTR, $CTR # CTR = [1]TAG[126...32][00..00]
movq $POL, $secureBuffer
leaq 32($secureBuffer), $secureBuffer
leaq 32($Htbl), $Htbl
- # make CTRBLKs from given tag.
- vmovdqu ($CT,$LEN), $CTR
- vpor OR_MASK(%rip), $CTR, $CTR # CTR = [1]TAG[126...32][00..00]
andq \$~15, $LEN
# If less then 6 blocks, make singles
diff --git a/crypto/cipher_extra/e_aesgcmsiv.c b/crypto/cipher_extra/e_aesgcmsiv.c
index 15601e1..63deb05 100644
--- a/crypto/cipher_extra/e_aesgcmsiv.c
+++ b/crypto/cipher_extra/e_aesgcmsiv.c
@@ -126,16 +126,16 @@
uint8_t in_out_poly[16]);
// aes128gcmsiv_dec decrypts |in_len| & ~15 bytes from |out| and writes them to
-// |in|. (The full value of |in_len| is still used to find the authentication
-// tag appended to the ciphertext, however, so must not be pre-masked.)
+// |in|. |in| and |out| may be equal, but must not otherwise alias.
//
-// |in| and |out| may be equal, but must not otherwise overlap.
+// |in_out_calculated_tag_and_scratch|, on entry, must contain:
+// 1. The current value of the calculated tag, which will be updated during
+// decryption and written back to the beginning of this buffer on exit.
+// 2. The claimed tag, which is needed to derive counter values.
//
-// While decrypting, it updates the POLYVAL value found at the beginning of
-// |in_out_calculated_tag_and_scratch| and writes the updated value back before
-// return. During executation, it may use the whole of this space for other
-// purposes. In order to decrypt and update the POLYVAL value, it uses the
-// expanded key from |key| and the table of powers in |htable|.
+// While decrypting, the whole of |in_out_calculated_tag_and_scratch| may be
+// used for other purposes. In order to decrypt and update the POLYVAL value, it
+// uses the expanded key from |key| and the table of powers in |htable|.
extern void aes128gcmsiv_dec(const uint8_t *in, uint8_t *out,
uint8_t in_out_calculated_tag_and_scratch[16 * 8],
const uint8_t htable[16 * 6],
@@ -393,14 +393,10 @@
return 1;
}
-// TODO(martinkr): Add aead_aes_gcm_siv_asm_open_gather. N.B. aes128gcmsiv_dec
-// expects ciphertext and tag in a contiguous buffer.
-
-static int aead_aes_gcm_siv_asm_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
- size_t *out_len, size_t max_out_len,
- const uint8_t *nonce, size_t nonce_len,
- const uint8_t *in, size_t in_len,
- const uint8_t *ad, size_t ad_len) {
+static int aead_aes_gcm_siv_asm_open_gather(
+ const EVP_AEAD_CTX *ctx, uint8_t *out, const uint8_t *nonce,
+ size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *in_tag,
+ size_t in_tag_len, const uint8_t *ad, size_t ad_len) {
const uint64_t ad_len_64 = ad_len;
if (ad_len_64 >= (UINT64_C(1) << 61)) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
@@ -408,8 +404,8 @@
}
const uint64_t in_len_64 = in_len;
- if (in_len < EVP_AEAD_AES_GCM_SIV_TAG_LEN ||
- in_len_64 > (UINT64_C(1) << 36) + AES_BLOCK_SIZE) {
+ if (in_len_64 > UINT64_C(1) << 36 ||
+ in_tag_len != EVP_AEAD_AES_GCM_SIV_TAG_LEN) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
return 0;
}
@@ -420,13 +416,6 @@
}
const struct aead_aes_gcm_siv_asm_ctx *gcm_siv_ctx = asm_ctx_from_ctx(ctx);
- const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN;
- const uint8_t *const given_tag = in + plaintext_len;
-
- if (max_out_len < plaintext_len) {
- OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
- return 0;
- }
alignas(16) uint64_t record_auth_key[2];
alignas(16) uint64_t record_enc_key[4];
@@ -459,27 +448,27 @@
alignas(16) uint8_t htable[16 * 6];
aesgcmsiv_htable6_init(htable, (const uint8_t *)record_auth_key);
+ // aes[128|256]gcmsiv_dec needs access to the claimed tag. So it's put into
+ // its scratch space.
+ memcpy(calculated_tag + 16, in_tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN);
if (gcm_siv_ctx->is_128_bit) {
- aes128gcmsiv_dec(in, out, calculated_tag, htable, &expanded_key,
- plaintext_len);
+ aes128gcmsiv_dec(in, out, calculated_tag, htable, &expanded_key, in_len);
} else {
- aes256gcmsiv_dec(in, out, calculated_tag, htable, &expanded_key,
- plaintext_len);
+ aes256gcmsiv_dec(in, out, calculated_tag, htable, &expanded_key, in_len);
}
- if (plaintext_len & 15) {
+ if (in_len & 15) {
aead_aes_gcm_siv_asm_crypt_last_block(gcm_siv_ctx->is_128_bit, out, in,
- plaintext_len, given_tag,
- &expanded_key);
+ in_len, in_tag, &expanded_key);
OPENSSL_memset(scratch, 0, sizeof(scratch));
- OPENSSL_memcpy(scratch, out + (plaintext_len & ~15), plaintext_len & 15);
+ OPENSSL_memcpy(scratch, out + (in_len & ~15), in_len & 15);
aesgcmsiv_polyval_horner(calculated_tag, (const uint8_t *)record_auth_key,
scratch, 1);
}
uint8_t length_block[16];
CRYPTO_store_u64_le(length_block, ad_len * 8);
- CRYPTO_store_u64_le(length_block + 8, plaintext_len * 8);
+ CRYPTO_store_u64_le(length_block + 8, in_len * 8);
aesgcmsiv_polyval_horner(calculated_tag, (const uint8_t *)record_auth_key,
length_block, 1);
@@ -495,13 +484,12 @@
aes256gcmsiv_ecb_enc_block(calculated_tag, calculated_tag, &expanded_key);
}
- if (CRYPTO_memcmp(calculated_tag, given_tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN) !=
+ if (CRYPTO_memcmp(calculated_tag, in_tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN) !=
0) {
OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
return 0;
}
- *out_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN;
return 1;
}
@@ -515,9 +503,9 @@
aead_aes_gcm_siv_asm_init,
NULL /* init_with_direction */,
aead_aes_gcm_siv_asm_cleanup,
- aead_aes_gcm_siv_asm_open,
+ NULL /* open */,
aead_aes_gcm_siv_asm_seal_scatter,
- NULL /* open_gather */,
+ aead_aes_gcm_siv_asm_open_gather,
NULL /* get_iv */,
NULL /* tag_len */,
};
@@ -532,9 +520,9 @@
aead_aes_gcm_siv_asm_init,
NULL /* init_with_direction */,
aead_aes_gcm_siv_asm_cleanup,
- aead_aes_gcm_siv_asm_open,
+ NULL /* open */,
aead_aes_gcm_siv_asm_seal_scatter,
- NULL /* open_gather */,
+ aead_aes_gcm_siv_asm_open_gather,
NULL /* get_iv */,
NULL /* tag_len */,
};