diff --git a/crypto/cipher_extra/aead_test.cc b/crypto/cipher_extra/aead_test.cc index 2300d4a6a2..e533354790 100644 --- a/crypto/cipher_extra/aead_test.cc +++ b/crypto/cipher_extra/aead_test.cc @@ -1486,7 +1486,11 @@ static const EvpAeadCtxSerdeTestParams kEvpAeadCtxSerde[] = { {"EVP_aead_aes_128_gcm_tls13", EVP_aead_aes_128_gcm_tls13(), kEvpAeadCtxKey, 16, 16, 23}, {"EVP_aead_aes_256_gcm_tls13", EVP_aead_aes_256_gcm_tls13(), kEvpAeadCtxKey, - 32, 16, 24}}; + 32, 16, 24}, + {"EVP_aead_xaes_256_gcm", EVP_aead_xaes_256_gcm(), kEvpAeadCtxKey, 32, 16, + 29}, + {"EVP_aead_hmac_aes_256_gcm", EVP_aead_hmac_aes_256_gcm(), kEvpAeadCtxKey, 32, 16, + 30}}; INSTANTIATE_TEST_SUITE_P( EvpAeadCtxSerdeTests, EvpAeadCtxSerdeTest, @@ -1579,7 +1583,28 @@ TEST_P(EvpAeadCtxSerdeTest, FailUnknownCipherId) { CIPHER_R_SERIALIZATION_INVALID_CIPHER_ID); } } +#if 0 +struct aead_aes_gcm_ctx_2 { + union { + double align; + AES_KEY ks; + } ks; + GCM128_KEY gcm_key; + ctr128_f ctr; +}; +#define XAES_KEY_COMMIT_SIZE (2*AES_BLOCK_SIZE) +struct aead_xaes_256_gcm_ctx_2 { + AES_KEY xaes_key; // Key K, used in CMAC and key commitment + uint8_t k1[AES_BLOCK_SIZE]; // only value needed from cmac_ctx_st + uint8_t kc[XAES_KEY_COMMIT_SIZE]; // key commitment +}; +#include +struct aead_hmac_aes_256_gcm_ctx_2 { + HMAC_CTX hmac_ctx; + uint8_t kc[XAES_KEY_COMMIT_SIZE]; // key commitment +}; +#endif TEST(EvpAeadCtxSerdeTest, ID) { bool identifiers[AEAD_MAX_ID + 1] = {false}; for (EvpAeadCtxSerdeTestParams params : kEvpAeadCtxSerde) { @@ -1594,6 +1619,11 @@ TEST(EvpAeadCtxSerdeTest, ID) { identifiers[id] = true; } + #if 0 + // Finding out the sizes of the key committing AEAD structs, XAES and HMAC + EXPECT_EQ(sizeof(struct aead_xaes_256_gcm_ctx_2), (size_t)800); + EXPECT_EQ(sizeof(struct aead_hmac_aes_256_gcm_ctx_2), (size_t)800); + #endif // Nothing should have the unknown identifier (0) ASSERT_FALSE(identifiers[0]); diff --git a/crypto/fipsmodule/cipher/e_aes.c b/crypto/fipsmodule/cipher/e_aes.c index 60921abaa0..cc24938c21 100644 --- a/crypto/fipsmodule/cipher/e_aes.c +++ b/crypto/fipsmodule/cipher/e_aes.c @@ -1743,5 +1743,609 @@ int EVP_has_aes_hardware(void) { return 0; #endif } +#if 1 //xaes + +#define XAES_KEY_COMMIT_SIZE (2*AES_BLOCK_SIZE) +struct aead_xaes_256_gcm_ctx { // size: 292 bytes + //struct aead_aes_gcm_ctx gcm_ctx; + AES_KEY xaes_key; // Key K, used in CMAC and key commitment + uint8_t k1[AES_BLOCK_SIZE]; // only value needed from cmac_ctx_st + uint8_t kc[XAES_KEY_COMMIT_SIZE]; // key commitment +}; + +#define BINARY_FIELD_MUL_X_128(out, in) \ + do { \ + unsigned i; \ + /* Shift |in| to left, including carry. */ \ + for (i = 0; i < 15; i++) { \ + out[i] = (in[i] << 1) | (in[i+1] >> 7); \ + } \ + /* If MSB set fixup with R. */ \ + const uint8_t carry = in[0] >> 7; \ + out[i] = (in[i] << 1) ^ ((0 - carry) & 0x87); \ +} while(0); + +static const uint8_t kZeroIn[AES_BLOCK_SIZE] = {0}; + +OPENSSL_STATIC_ASSERT((sizeof((EVP_AEAD_CTX *)NULL)->state) >= + sizeof(struct aead_xaes_256_gcm_ctx), + AEAD_state_is_too_small) +OPENSSL_STATIC_ASSERT(alignof(union evp_aead_ctx_st_state) >= + alignof(struct aead_xaes_256_gcm_ctx), + AEAD_state_has_insufficient_alignment) + +static int aead_xaes_256_gcm_init_common(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t requested_tag_len) { + // [TODO]: check where to put DIT calls + if ((key_len << 3) != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + struct aead_xaes_256_gcm_ctx *xaes_ctx = + (struct aead_xaes_256_gcm_ctx *)&ctx->state; + + // The following are the steps from CMAC_INIT resulting in calculating + // K1 which is the only value needed. + uint8_t L[AES_BLOCK_SIZE]; + + // L := AES256_K(0x(00)^{16}) + if (AES_set_encrypt_key(key, (key_len << 3), &xaes_ctx->xaes_key)) { + return 0; + } + AES_encrypt(kZeroIn, L, &xaes_ctx->xaes_key); + + // if MSB1(L) = 0 then + // K1[0 : 16] := L << 1 + // else + // K1[0 : 16] := (L << 1) XOR 0x(00)^{15}87 + BINARY_FIELD_MUL_X_128(xaes_ctx->k1, L); + + ctx->tag_len = EVP_AEAD_AES_GCM_TAG_LEN; + // = requested_tag_len; + // related to [TODO] about supporting truncated tags. + + return 1; +} + +static int aead_xaes_256_gcm_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t requested_tag_len) { + return aead_xaes_256_gcm_init_common(ctx, key, key_len, requested_tag_len); +} + +static void aead_xaes_256_gcm_cleanup(EVP_AEAD_CTX *ctx) {} + +static int aead_xaes_256_gcm_set_gcm_key( + struct aead_xaes_256_gcm_ctx *xaes_ctx, struct aead_aes_gcm_ctx *gcm_ctx, + const uint8_t *nonce, const size_t nonce_len, const unsigned key_commit) { + + uint8_t M1[AES_BLOCK_SIZE] = {0}; + uint8_t M2[AES_BLOCK_SIZE] = {0}; + + // This is supporting nonce length of 24 for now. + // [TODO]: include the length 20 + if (nonce_len != 24) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + // M1[0 : 16] := 0x0001|0x58|0x00|N[: 12] + M1[1] = 0x01; // [TODO]: change the location of this 0x01 based on b + M1[2] = 0x58; // [TODO]: here too + // [TODO]: change the offset and length, when length 20 is supported + OPENSSL_memcpy(M1 + 4, nonce, 12); + + // M2[0 : 16] := 0x0002|0x58|0x00|N[: 12] + OPENSSL_memcpy(M2, M1, AES_BLOCK_SIZE); + M2[1] = 0x02; + + for (size_t i = 0; i < AES_BLOCK_SIZE; i++) + { + M1[i] ^= xaes_ctx->k1[i]; + M2[i] ^= xaes_ctx->k1[i]; + } + + // K_U[ 0:16] := AES256_K(K1 XOR M1) = CMAC-AES256_K(0x0001|"X"|0x00|N[: 12]) + // K_U[16:32] := AES256_K(K1 XOR M2) = CMAC-AES256_K(0x0002|"X"|0x00|N[: 12]) + uint8_t gcm_key[(256 >> 3)] = {0}; + AES_encrypt(M1, gcm_key, &xaes_ctx->xaes_key); + AES_encrypt(M2, gcm_key + AES_BLOCK_SIZE, &xaes_ctx->xaes_key); + + gcm_ctx->ctr = aes_ctr_set_key(&gcm_ctx->ks.ks, &gcm_ctx->gcm_key, NULL, + gcm_key, sizeof(gcm_key)); + + if (key_commit) { + // Key commitment + // reuse M1 as input to C1 encryption then M3 + // reuse M2 as M4 + + // C1[0:16] := AES256_K(0x58434D5400|N[: 11]) + uint8_t kc_prefix[5] = {0x58, 0x43, 0x4D, 0x54, 0x00}; + uint8_t C1[AES_BLOCK_SIZE]; + OPENSSL_memcpy(M1, kc_prefix, 5); + OPENSSL_memcpy(M1 + 5, nonce, 11); + + // M3[0:16] := N[11:24] | 0x010003 + AES_encrypt(M1, C1, &xaes_ctx->xaes_key); + OPENSSL_memcpy(M1, nonce + 11, nonce_len-11); + M1[AES_BLOCK_SIZE-3] = 0x01; + M1[AES_BLOCK_SIZE-1] = 0x00; + M1[AES_BLOCK_SIZE-1] = 0x03; + + // M4[0:16] := N[11:24] | 0x010004 + OPENSSL_memcpy(M2, nonce + 11, nonce_len-11); + M2[AES_BLOCK_SIZE-3] = 0x01; + M2[AES_BLOCK_SIZE-1] = 0x00; + M2[AES_BLOCK_SIZE-1] = 0x04; + + // K_C[ 0:16] := AES256_K(C1 XOR K1 XOR M3) = CMAC-AES256_K("XCMT"|0x00|N[:24]|0x0100|0x03) + // K_C[16:32] := AES256_K(C1 XOR K1 XOR M4) = CMAC-AES256_K("XCMT"|0x00|N[:24]|0x0100|0x04) + for (size_t i = 0; i < AES_BLOCK_SIZE; i++) + { + M1[i] ^= C1[i] ^ xaes_ctx->k1[i]; + M2[i] ^= C1[i] ^ xaes_ctx->k1[i]; + } + AES_encrypt(M1, xaes_ctx->kc, &xaes_ctx->xaes_key); + AES_encrypt(M2, xaes_ctx->kc + AES_BLOCK_SIZE, &xaes_ctx->xaes_key); + } + + return 1; +} + +static int aead_xaes_256_gcm_seal_scatter( + const EVP_AEAD_CTX *ctx, uint8_t *out, + uint8_t *out_tag, size_t *out_tag_len, + const size_t max_out_tag_len, + const uint8_t *nonce, const size_t nonce_len, + const uint8_t *in, const size_t in_len, + const uint8_t *extra_in, + const size_t extra_in_len, const uint8_t *ad, + const size_t ad_len) { + // [TODO] : do we uncomment this? or is it not just gcm so we shouldn't increase the counter? + // boringssl_fips_inc_counter(fips_counter_evp_aes_256_gcm); + + struct aead_xaes_256_gcm_ctx *xaes_ctx = + (struct aead_xaes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + if (!aead_xaes_256_gcm_set_gcm_key(xaes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 0)) { + return 0; + } + + // V[0:12] := N[12:] + // (C,T) := AES-256-GCM(K_U[:32], AAD, IV =V, P) + return aead_aes_gcm_seal_scatter_impl( + &gcm_ctx, out, out_tag, out_tag_len, max_out_tag_len, + nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, extra_in, extra_in_len, ad, ad_len, ctx->tag_len); +} + +static int aead_xaes_256_gcm_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) { + struct aead_xaes_256_gcm_ctx *xaes_ctx = + (struct aead_xaes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + if (!aead_xaes_256_gcm_set_gcm_key(xaes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 0)) { + return 0; + } + + return aead_aes_gcm_open_gather_impl( + &gcm_ctx, out, nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, in_tag, in_tag_len, + ad, ad_len, ctx->tag_len); +} + +DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_xaes_256_gcm) { + memset(out, 0, sizeof(EVP_AEAD)); + + out->key_len = 32; + out->nonce_len = 2 * AES_GCM_NONCE_LENGTH; + out->overhead = EVP_AEAD_AES_GCM_TAG_LEN; + out->max_tag_len = EVP_AEAD_AES_GCM_TAG_LEN; + out->aead_id = AEAD_XAES_256_GCM_ID; + out->seal_scatter_supports_extra_in = 0; // [TODO]: check if we will need this feature + + out->init = aead_xaes_256_gcm_init; + out->cleanup = aead_xaes_256_gcm_cleanup; + out->seal_scatter = aead_xaes_256_gcm_seal_scatter; + out->open_gather = aead_xaes_256_gcm_open_gather; +} + +static int aead_xaes_256_gcm_init_key_commit( + EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t requested_tag_len) { + if (requested_tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH) { + if (requested_tag_len < XAES_KEY_COMMIT_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + // [TODO]: see if the following will be needed + requested_tag_len -= AES_GCM_NONCE_LENGTH; + } + if (!aead_xaes_256_gcm_init_common(ctx, key, key_len, requested_tag_len)) { + return 0; + } + + ctx->tag_len += XAES_KEY_COMMIT_SIZE; + return 1; +} + +static int aead_xaes_256_gcm_seal_scatter_key_commit( + const EVP_AEAD_CTX *ctx, uint8_t *out, + uint8_t *out_tag, size_t *out_tag_len, + const size_t max_out_tag_len, + const uint8_t *nonce, const size_t nonce_len, + const uint8_t *in, const size_t in_len, + const uint8_t *extra_in, + const size_t extra_in_len, const uint8_t *ad, + const size_t ad_len) { + // [TODO] : do we uncomment this? or is it not just gcm so we shouldn't increase the counter? + // boringssl_fips_inc_counter(fips_counter_evp_aes_256_gcm); + + struct aead_xaes_256_gcm_ctx *xaes_ctx = + (struct aead_xaes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + // [TODO]: will we allow truncated tags? It's a bit tricky with + // requested_tag_length and the init function not being the gcm init + if (max_out_tag_len < XAES_KEY_COMMIT_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (!aead_xaes_256_gcm_set_gcm_key(xaes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 1)) { + return 0; + } + + if (!aead_aes_gcm_seal_scatter_impl( + &gcm_ctx, out, out_tag, out_tag_len, + max_out_tag_len - XAES_KEY_COMMIT_SIZE, + nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, extra_in, extra_in_len, + ad, ad_len, ctx->tag_len - XAES_KEY_COMMIT_SIZE)) { + return 0; + } + + // Copy the key commitment to the output buffer after the tag + assert(*out_tag_len + XAES_KEY_COMMIT_SIZE <= max_out_tag_len); + OPENSSL_memcpy(out_tag + *out_tag_len, xaes_ctx->kc, XAES_KEY_COMMIT_SIZE); + *out_tag_len += XAES_KEY_COMMIT_SIZE; + + return 1; +} + +static int aead_xaes_256_gcm_open_gather_key_commit( + 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) { + struct aead_xaes_256_gcm_ctx *xaes_ctx = + (struct aead_xaes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + if (!aead_xaes_256_gcm_set_gcm_key(xaes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 1)) { + return 0; + } + + if (!aead_aes_gcm_open_gather_impl( + &gcm_ctx, out, + nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, in_tag, in_tag_len - XAES_KEY_COMMIT_SIZE, + ad, ad_len, ctx->tag_len - XAES_KEY_COMMIT_SIZE)) { + return 0; + } + + // Check key commitment + if (OPENSSL_memcmp(in_tag + (in_tag_len - XAES_KEY_COMMIT_SIZE), + xaes_ctx->kc, XAES_KEY_COMMIT_SIZE)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + return 1; +} + +DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_xaes_256_gcm_key_commit) { + memset(out, 0, sizeof(EVP_AEAD)); + + out->key_len = 32; + out->nonce_len = 2 * AES_GCM_NONCE_LENGTH; + out->overhead = EVP_AEAD_AES_GCM_TAG_LEN + XAES_KEY_COMMIT_SIZE; + out->max_tag_len = EVP_AEAD_AES_GCM_TAG_LEN + XAES_KEY_COMMIT_SIZE; + out->aead_id = AEAD_XAES_256_GCM_ID; + out->seal_scatter_supports_extra_in = 0; // [TODO]: check if we will need this feature + + out->init = aead_xaes_256_gcm_init_key_commit; + out->cleanup = aead_xaes_256_gcm_cleanup; + out->seal_scatter = aead_xaes_256_gcm_seal_scatter_key_commit; + out->open_gather = aead_xaes_256_gcm_open_gather_key_commit; +} +#endif + + +#if 1 // AES-GCM with HMAC-SHA256 as a key-deriving PRF +struct aead_hmac_aes_256_gcm_ctx { //size: 1256 bytes + HMAC_CTX hmac_ctx; + uint8_t kc[XAES_KEY_COMMIT_SIZE]; // key commitment +}; + +OPENSSL_STATIC_ASSERT((sizeof((EVP_AEAD_CTX *)NULL)->state) >= + sizeof(struct aead_hmac_aes_256_gcm_ctx), + AEAD_state_is_too_small) +OPENSSL_STATIC_ASSERT(alignof(union evp_aead_ctx_st_state) >= + alignof(struct aead_hmac_aes_256_gcm_ctx), + AEAD_state_has_insufficient_alignment) + +static int aead_hmac_aes_256_gcm_init_common(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t requested_tag_len) { + if ((key_len << 3) != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + struct aead_hmac_aes_256_gcm_ctx *hmac_aes_ctx = + (struct aead_hmac_aes_256_gcm_ctx *)&ctx->state; + + if (!HMAC_Init_ex(&hmac_aes_ctx->hmac_ctx, key, key_len, EVP_sha256(), NULL)) { + return 0; + } + + ctx->tag_len = EVP_AEAD_AES_GCM_TAG_LEN; + // = requested_tag_len; + // related to [TODO] about supporting truncated tags. + + return 1; + } + + static int aead_hmac_aes_256_gcm_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t requested_tag_len) { + return aead_hmac_aes_256_gcm_init_common(ctx, key, key_len, requested_tag_len); + } + + static void aead_hmac_aes_256_gcm_cleanup(EVP_AEAD_CTX *ctx) {} + + static int aead_hmac_aes_256_gcm_set_gcm_key( + struct aead_hmac_aes_256_gcm_ctx *hmac_aes_ctx, struct aead_aes_gcm_ctx *gcm_ctx, + const uint8_t *nonce, const size_t nonce_len, const unsigned key_commit) { + + uint8_t M1[AES_BLOCK_SIZE] = {0}; + + // This is supporting nonce length of 24 for now. + // [TODO]: include the length 20 + if (nonce_len != 24) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + // M1[0 : 16] := 0x0001|0x58|0x00|N[: 12] + M1[1] = 0x01; // [TODO]: change the location of this 0x01 based on b + M1[2] = 0x58; // [TODO]: here too + // [TODO]: change the offset and length, when length 20 is supported + OPENSSL_memcpy(M1 + 4, nonce, 12); + + // K_U[0:32] := HMAC-SHA256_K(0x0001|"X"|0x00|N[: 12]) + uint8_t gcm_key[(256 >> 3)] = {0}; + HMAC_CTX *hctx = &hmac_aes_ctx->hmac_ctx; + unsigned int out_len = 0; + if (!HMAC_Init_ex(hctx, NULL, 0, NULL, NULL) || + !HMAC_Update(hctx, M1, AES_BLOCK_SIZE) || + !HMAC_Final(hctx, gcm_key, &out_len) || + out_len != 2*AES_BLOCK_SIZE + ) { + return 0; + } + + gcm_ctx->ctr = aes_ctr_set_key(&gcm_ctx->ks.ks, &gcm_ctx->gcm_key, NULL, + gcm_key, sizeof(gcm_key)); + + if (key_commit) { + uint8_t M3[2*AES_BLOCK_SIZE]; + uint8_t kc_prefix[5] = {0x58, 0x43, 0x4D, 0x54, 0x00}; + OPENSSL_memcpy(M3, kc_prefix, 5); + OPENSSL_memcpy(M3 + 5, nonce, 24); + + M3[2*AES_BLOCK_SIZE-3] = 0x01; + M3[2*AES_BLOCK_SIZE-1] = 0x00; + M3[2*AES_BLOCK_SIZE-1] = 0x03; + + // Key commitment + // K_C[0:32] := HMAC-SHA256_K("XCMT"|0x00|N[:24]|0x0100|0x03) + if (!HMAC_Init_ex(hctx, NULL, 0, NULL, NULL) || + !HMAC_Update(hctx, M3, AES_BLOCK_SIZE) || + !HMAC_Final(hctx, hmac_aes_ctx->kc, &out_len) || + out_len != 2*AES_BLOCK_SIZE + ) { + return 0; + } + } + return 1; +} + +static int aead_hmac_aes_256_gcm_seal_scatter( + const EVP_AEAD_CTX *ctx, uint8_t *out, + uint8_t *out_tag, size_t *out_tag_len, + const size_t max_out_tag_len, + const uint8_t *nonce, const size_t nonce_len, + const uint8_t *in, const size_t in_len, + const uint8_t *extra_in, + const size_t extra_in_len, const uint8_t *ad, + const size_t ad_len) { + // [TODO] : do we uncomment this? or is it not just gcm so we shouldn't increase the counter? + // boringssl_fips_inc_counter(fips_counter_evp_aes_256_gcm); + + struct aead_hmac_aes_256_gcm_ctx *hmac_aes_ctx = + (struct aead_hmac_aes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + if (!aead_hmac_aes_256_gcm_set_gcm_key(hmac_aes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 0)) { + return 0; + } + + // V[0:12] := N[12:] + // (C,T) := AES-256-GCM(K_U[:32], AAD, IV =V, P) + return aead_aes_gcm_seal_scatter_impl( + &gcm_ctx, out, out_tag, out_tag_len, max_out_tag_len, + nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, extra_in, extra_in_len, ad, ad_len, ctx->tag_len); +} + +static int aead_hmac_aes_256_gcm_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) { + struct aead_hmac_aes_256_gcm_ctx *hmac_aes_ctx = + (struct aead_hmac_aes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + if (!aead_hmac_aes_256_gcm_set_gcm_key(hmac_aes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 0)) { + return 0; + } + + return aead_aes_gcm_open_gather_impl( + &gcm_ctx, out, nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, in_tag, in_tag_len, + ad, ad_len, ctx->tag_len); +} + +DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_hmac_aes_256_gcm) { + memset(out, 0, sizeof(EVP_AEAD)); + + out->key_len = 32; + out->nonce_len = 2 * AES_GCM_NONCE_LENGTH; + out->overhead = EVP_AEAD_AES_GCM_TAG_LEN; + out->max_tag_len = EVP_AEAD_AES_GCM_TAG_LEN; + out->aead_id = AEAD_HMAC_AES_256_GCM_ID; + out->seal_scatter_supports_extra_in = 0; // [TODO]: check if we will need this feature + + out->init = aead_hmac_aes_256_gcm_init; + out->cleanup = aead_hmac_aes_256_gcm_cleanup; + out->seal_scatter = aead_hmac_aes_256_gcm_seal_scatter; + out->open_gather = aead_hmac_aes_256_gcm_open_gather; +} + +static int aead_hmac_aes_256_gcm_init_key_commit( + EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t requested_tag_len) { + if (requested_tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH) { + if (requested_tag_len < XAES_KEY_COMMIT_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + // [TODO]: see if the following will be needed + requested_tag_len -= AES_GCM_NONCE_LENGTH; + } + if (!aead_hmac_aes_256_gcm_init_common(ctx, key, key_len, requested_tag_len)) { + return 0; + } + + ctx->tag_len += XAES_KEY_COMMIT_SIZE; + return 1; +} + +static int aead_hmac_aes_256_gcm_seal_scatter_key_commit( + const EVP_AEAD_CTX *ctx, uint8_t *out, + uint8_t *out_tag, size_t *out_tag_len, + const size_t max_out_tag_len, + const uint8_t *nonce, const size_t nonce_len, + const uint8_t *in, const size_t in_len, + const uint8_t *extra_in, + const size_t extra_in_len, const uint8_t *ad, + const size_t ad_len) { + // [TODO] : do we uncomment this? or is it not just gcm so we shouldn't increase the counter? + // boringssl_fips_inc_counter(fips_counter_evp_aes_256_gcm); + + struct aead_hmac_aes_256_gcm_ctx *hmac_aes_ctx = + (struct aead_hmac_aes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + // [TODO]: will we allow truncated tags? It's a bit tricky with + // requested_tag_length and the init function not being the gcm init + if (max_out_tag_len < XAES_KEY_COMMIT_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (!aead_hmac_aes_256_gcm_set_gcm_key(hmac_aes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 1)) { + return 0; + } + + if (!aead_aes_gcm_seal_scatter_impl( + &gcm_ctx, out, out_tag, out_tag_len, + max_out_tag_len - XAES_KEY_COMMIT_SIZE, + nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, extra_in, extra_in_len, + ad, ad_len, ctx->tag_len - XAES_KEY_COMMIT_SIZE)) { + return 0; + } + + // Copy the key commitment to the output buffer after the tag + assert(*out_tag_len + XAES_KEY_COMMIT_SIZE <= max_out_tag_len); + OPENSSL_memcpy(out_tag + *out_tag_len, hmac_aes_ctx->kc, XAES_KEY_COMMIT_SIZE); + *out_tag_len += XAES_KEY_COMMIT_SIZE; + + return 1; +} + +static int aead_hmac_aes_256_gcm_open_gather_key_commit( + 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) { + struct aead_hmac_aes_256_gcm_ctx *hmac_aes_ctx = + (struct aead_hmac_aes_256_gcm_ctx *)&ctx->state; + struct aead_aes_gcm_ctx gcm_ctx; + + if (!aead_hmac_aes_256_gcm_set_gcm_key(hmac_aes_ctx, &gcm_ctx, nonce, nonce_len, + /*key_commit*/ 1)) { + return 0; + } + + if (!aead_aes_gcm_open_gather_impl( + &gcm_ctx, out, + nonce + AES_GCM_NONCE_LENGTH, AES_GCM_NONCE_LENGTH, + in, in_len, in_tag, in_tag_len - XAES_KEY_COMMIT_SIZE, + ad, ad_len, ctx->tag_len - XAES_KEY_COMMIT_SIZE)) { + return 0; + } + + // Check key commitment + if (OPENSSL_memcmp(in_tag + (in_tag_len - XAES_KEY_COMMIT_SIZE), + hmac_aes_ctx->kc, XAES_KEY_COMMIT_SIZE)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + return 1; +} + +DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_hmac_aes_256_gcm_key_commit) { + memset(out, 0, sizeof(EVP_AEAD)); + + out->key_len = 32; + out->nonce_len = 2 * AES_GCM_NONCE_LENGTH; + out->overhead = EVP_AEAD_AES_GCM_TAG_LEN + XAES_KEY_COMMIT_SIZE; + out->max_tag_len = EVP_AEAD_AES_GCM_TAG_LEN + XAES_KEY_COMMIT_SIZE; + out->aead_id = AEAD_XAES_256_GCM_ID; + out->seal_scatter_supports_extra_in = 0; // [TODO]: check if we will need this feature + + out->init = aead_hmac_aes_256_gcm_init_key_commit; + out->cleanup = aead_hmac_aes_256_gcm_cleanup; + out->seal_scatter = aead_hmac_aes_256_gcm_seal_scatter_key_commit; + out->open_gather = aead_hmac_aes_256_gcm_open_gather_key_commit; +} +#endif OPENSSL_MSVC_PRAGMA(warning(pop)) diff --git a/crypto/fipsmodule/cipher/internal.h b/crypto/fipsmodule/cipher/internal.h index a2170f0691..8779fa8ffa 100644 --- a/crypto/fipsmodule/cipher/internal.h +++ b/crypto/fipsmodule/cipher/internal.h @@ -107,7 +107,9 @@ extern "C" { #define AEAD_AES_128_CCM_BLUETOOTH_8_ID 26 #define AEAD_AES_128_CCM_MATTER_ID 27 #define AEAD_AES_256_CBC_SHA384_TLS_ID 28 -#define AEAD_MAX_ID 28 +#define AEAD_XAES_256_GCM_ID 29 +#define AEAD_HMAC_AES_256_GCM_ID 30 +#define AEAD_MAX_ID 30 // EVP_AEAD represents a specific AEAD algorithm. struct evp_aead_st { diff --git a/crypto/fipsmodule/cmac/cmac.c b/crypto/fipsmodule/cmac/cmac.c index a42ca02bbf..8ac93ce001 100644 --- a/crypto/fipsmodule/cmac/cmac.c +++ b/crypto/fipsmodule/cmac/cmac.c @@ -56,21 +56,9 @@ #include #include +#include "internal.h" #include "../../internal.h" - -struct cmac_ctx_st { - EVP_CIPHER_CTX cipher_ctx; - // k1 and k2 are the CMAC subkeys. See - // https://tools.ietf.org/html/rfc4493#section-2.3 - uint8_t k1[AES_BLOCK_SIZE]; - uint8_t k2[AES_BLOCK_SIZE]; - // Last (possibly partial) scratch - uint8_t block[AES_BLOCK_SIZE]; - // block_used contains the number of valid bytes in |block|. - unsigned block_used; -}; - static void CMAC_CTX_init(CMAC_CTX *ctx) { EVP_CIPHER_CTX_init(&ctx->cipher_ctx); } @@ -99,7 +87,7 @@ int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len, // We have to verify that all the CMAC services actually succeed before // updating the indicator state, so we lock the state here. FIPS_service_indicator_lock_state(); - + size_t scratch_out_len; CMAC_CTX ctx; CMAC_CTX_init(&ctx); diff --git a/crypto/fipsmodule/cmac/internal.h b/crypto/fipsmodule/cmac/internal.h new file mode 100644 index 0000000000..6dec34546d --- /dev/null +++ b/crypto/fipsmodule/cmac/internal.h @@ -0,0 +1,29 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef AWSLC_HEADER_CMAC_INTERNAL_H +#define AWSLC_HEADER_CMAC_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct cmac_ctx_st { + EVP_CIPHER_CTX cipher_ctx; + // k1 and k2 are the CMAC subkeys. See + // https://tools.ietf.org/html/rfc4493#section-2.3 + uint8_t k1[AES_BLOCK_SIZE]; + uint8_t k2[AES_BLOCK_SIZE]; + // Last (possibly partial) scratch + uint8_t block[AES_BLOCK_SIZE]; + // block_used contains the number of valid bytes in |block|. + unsigned block_used; +}; + +#if defined(__cplusplus) +} // extern C +#endif + +#endif // OPENSSL_HEADER_CMAC_INTERNAL_H diff --git a/include/openssl/aead.h b/include/openssl/aead.h index 64df91ecfe..7523b85159 100644 --- a/include/openssl/aead.h +++ b/include/openssl/aead.h @@ -211,7 +211,7 @@ OPENSSL_EXPORT size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead); // AEAD operations. union evp_aead_ctx_st_state { - uint8_t opaque[564]; + uint8_t opaque[1256]; uint64_t alignment; void *ptr; }; @@ -431,6 +431,17 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm_tls13(void); // 1.3 nonce construction. OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm_tls13(void); +#if 1 //xaes +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_xaes_256_gcm(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_xaes_256_gcm_key_commit(void); +#endif + +#if 1 // AES-GCM with HMAC-SHA256 as a key-deriving PRF +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_hmac_aes_256_gcm(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_hmac_aes_256_gcm_key_commit(void); +#endif // Obscure functions. diff --git a/tool/speed.cc b/tool/speed.cc index 84c0ebb08d..2f37582336 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -67,6 +67,7 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) #else #include #endif +#include #if !defined(OPENSSL_IS_AWSLC) // align_pointer returns |ptr|, advanced to |alignment|. |alignment| must be a @@ -662,9 +663,9 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, std::string name, const size_t overhead_len = EVP_AEAD_max_overhead(aead); std::unique_ptr key(new uint8_t[key_len]); - BM_memset(key.get(), 0, key_len); + BM_memset(key.get(), 5, key_len); std::unique_ptr nonce(new uint8_t[nonce_len]); - BM_memset(nonce.get(), 0, nonce_len); + BM_memset(nonce.get(), 3, nonce_len); std::unique_ptr in_storage(new uint8_t[chunk_len + kAlignment]); // N.B. for EVP_AEAD_CTX_seal_scatter the input and output buffers may be the // same size. However, in the direction == evp_aead_open case we still use @@ -1018,7 +1019,7 @@ static bool SpeedAESBlock(const std::string &name, unsigned bits, return true; } -static bool SpeedAES256XTS(const std::string &name, //const size_t in_len, +static bool SpeedAES256XTS(const std::string &name, const std::string &selected) { if (!selected.empty() && name.find(selected) == std::string::npos) { return true; @@ -1116,6 +1117,254 @@ static bool SpeedAES256XTS(const std::string &name, //const size_t in_len, return true; } +#if !defined(OPENSSL_BENCHMARK) +#include "../crypto/fipsmodule/cmac/internal.h" + +// This is a benchmark of XAES-256-GCM constructed from existing APIs of CMAC +// and AES-GCM. It is slower than using EVP_aead_xaes_256_gcm() and +// EVP_aead_xaes_256_gcm_key_commit(). +static bool SpeedXAES256GCM(const std::string &name, + const std::string &selected) { + if (!selected.empty() && name.find(selected) == std::string::npos) { + return true; + } + static const size_t ad_len = 0; + static const unsigned kAlignment = 16; + + const EVP_AEAD *aead = EVP_aead_aes_256_gcm(); + // key_len = 256 for the CMAC key, GCM key and key commitment + const size_t key_len = EVP_AEAD_key_length(aead); + const size_t overhead_len = EVP_AEAD_max_overhead(aead); + const size_t nonce_len = 24; + std::vector key(key_len); + std::vector gcm_key(key_len); + std::vector nonce(nonce_len, 9); + BM_NAMESPACE::UniquePtr cmac_ctx(CMAC_CTX_new()); + std::vector cmac_msg1({0x00, 0x01, 0x58, 0x00}); + std::vector cmac_msg2({0x00, 0x02, 0x58, 0x00}); + + cmac_msg1.insert(cmac_msg1.end(), nonce.begin(), nonce.begin()+12); + cmac_msg2.insert(cmac_msg2.end(), nonce.begin(), nonce.begin()+12); + assert(cmac_msg1.size() == 16); + assert(cmac_msg2.size() == 16); + + // Key commitment inputs + std::vector cmac_cmt_msg1({0x58, 0x43, 0x4D, 0x54, 0x00}); + //cmac_cmt_msg1.insert(cmac_cmt_msg1.end(), nonce.begin(), nonce.begin()+11); + cmac_cmt_msg1.resize(16); + cmac_cmt_msg1.insert(cmac_cmt_msg1.begin()+5, nonce.begin(), nonce.begin()+11); + + std::vector cmac_cmt_msg21({0x01, 0x00, 0x03}); + cmac_cmt_msg21.insert(cmac_cmt_msg21.begin(), nonce.begin()+11, nonce.end()); + std::vector cmac_cmt_msg22({0x01, 0x00, 0x04}); + cmac_cmt_msg22.insert(cmac_cmt_msg22.begin(), nonce.begin()+11, nonce.end()); + assert(cmac_cmt_msg21.size() == 16); + assert(cmac_cmt_msg22.size() == 16); + std::vector key_cmt(key_len); + + BM_NAMESPACE::UniquePtr cmac_ctx2(CMAC_CTX_new()); + + TimeResults results; + + // This is equivalent to the Init function of XAES-256-GCM if the AEAD API + // is used to implement it, i.e. EVP_AEAD_CTX_init(); + // it takes only the key and not the nonce. + if (!TimeFunction(&results, [&]() -> bool { + if (!CMAC_Init(cmac_ctx.get(), key.data(), key_len, EVP_aes_256_cbc(), NULL)) { + return false; + } + return true; + })) { + fprintf(stderr, "XAES-256-GCM initialisation failed.\n"); + return false; + } + results.Print(name + " init with key"); + + BM_NAMESPACE::ScopedEVP_AEAD_CTX aead_ctx; + size_t cmac_out_len1, cmac_out_len2; + + for (size_t chunk_len : g_chunk_lengths) { + std::unique_ptr in_storage(new uint8_t[chunk_len + kAlignment]); + std::unique_ptr out_storage( + new uint8_t[chunk_len + overhead_len + kAlignment]); + std::unique_ptr tag_storage( + new uint8_t[overhead_len + kAlignment]); + std::unique_ptr ad(new uint8_t[ad_len]); + BM_memset(ad.get(), 0, ad_len); + + uint8_t *const in = + static_cast(align_pointer(in_storage.get(), kAlignment)); + BM_memset(in, 0, chunk_len); + + uint8_t *const out = + static_cast(align_pointer(out_storage.get(), kAlignment)); + + uint8_t *const tag = + static_cast(align_pointer(tag_storage.get(), kAlignment)); + BM_memset(tag, 0, overhead_len); + + size_t tag_len; + + // This is equivalent to the seal function of XAES-256-GCM if the AEAD API + // is used to implement it, i.e. EVP_AEAD_CTX_seal; + // it takes the nonce as input and computes the tag, that is not a streaming + // interface where Update can be called multiple times, then Final. + // Key derivation using AES-CMAC: + // One-shot function, AES_CMAC, is not used because the context is reused. + // Because the input to CMAC is exactly one block of 16 bytes, + // CMAC_Update effectively just copies the input to a buffer in the context. + // The AES invocation happens in CMAC_Final. + + if (!TimeFunction(&results, [&]() -> bool { + if (!CMAC_Update(cmac_ctx.get(), cmac_msg1.data(),cmac_msg1.size()) || + !CMAC_Final(cmac_ctx.get(), gcm_key.data(), &cmac_out_len1) || + !CMAC_Reset(cmac_ctx.get()) || + !CMAC_Update(cmac_ctx.get(), cmac_msg2.data(),cmac_msg2.size()) || + !CMAC_Final(cmac_ctx.get(), gcm_key.data() + (key_len/2) , &cmac_out_len2) || + !CMAC_Reset(cmac_ctx.get()) || + !EVP_AEAD_CTX_init_with_direction(aead_ctx.get(), aead, gcm_key.data(), key_len, + EVP_AEAD_DEFAULT_TAG_LENGTH, + evp_aead_seal) || + !EVP_AEAD_CTX_seal_scatter( + aead_ctx.get(), out, tag, &tag_len, overhead_len, + nonce.data()+12, nonce_len/2, in, chunk_len, nullptr, 0, + ad.get(), ad_len)) { + return false; + } + return true; + })) { + fprintf(stderr, "XAES-256-GCM seal (encrypt) failed.\n"); + return false; + } + results.PrintWithBytes(name + " seal", chunk_len); + + assert(cmac_out_len1 == key_len/2); + assert(cmac_out_len2 == key_len/2); + + // Key commitment: + // Formed of two independent CMAC 128-bit outputs each with 256-bit inputs. + // The CMAC context is reused from key derivation because K1 is the same. + // The input to each CMAC is two blocks of 16 bytes. The first block + // is the same for both CMAC operations, i.e. 0x58434D5400 || N[:11], + // where N[:11] are the first 11 bytes of the nonce. + // + // Update() processes all blocks as in AES-CBC (XORing with previous block + // and encrypting) except for the last block; it's saved in the context. + // Final() processes the last block (XOR with previous block, XOR with K1 + // and encrypt). + // - Pass as input to Update() the entire 32-byte input 1. This will + // process (AES) only the first 16 bytes which are common between + // both inputs. + // - Copy the context to a second context and override the block stored + // within it with the second block of input 2. + // - Call Final() for both contexts (2 x AES). + if (!TimeFunction(&results, [&]() -> bool { + // Seal + if (!CMAC_Update(cmac_ctx.get(), cmac_msg1.data(),cmac_msg1.size()) || + !CMAC_Final(cmac_ctx.get(), gcm_key.data(), &cmac_out_len1) || + !CMAC_Reset(cmac_ctx.get()) || + !CMAC_Update(cmac_ctx.get(), cmac_msg2.data(),cmac_msg2.size()) || + !CMAC_Final(cmac_ctx.get(), gcm_key.data() + (key_len/2) , &cmac_out_len2) || + !CMAC_Reset(cmac_ctx.get()) || + !EVP_AEAD_CTX_init_with_direction(aead_ctx.get(), aead, gcm_key.data(), key_len, + EVP_AEAD_DEFAULT_TAG_LENGTH, + evp_aead_seal) || + !EVP_AEAD_CTX_seal_scatter( + aead_ctx.get(), out, tag, &tag_len, overhead_len, + nonce.data()+12, nonce_len/2, in, chunk_len, nullptr, 0, + ad.get(), ad_len)) { + return false; + } + // Seal with key commitment + if (!CMAC_Update(cmac_ctx.get(), cmac_cmt_msg1.data(), cmac_cmt_msg1.size()) || + !CMAC_CTX_copy(cmac_ctx2.get(), cmac_ctx.get()) || + !CMAC_Final(cmac_ctx.get(), key_cmt.data(), &cmac_out_len1) || + !CMAC_Reset(cmac_ctx.get())) { + return false; + } + memcpy(cmac_ctx2.get()->block, cmac_cmt_msg22.data(), AES_BLOCK_SIZE); + if (!CMAC_Final(cmac_ctx2.get(), key_cmt.data() + (key_len/2), &cmac_out_len2) || + !CMAC_Reset(cmac_ctx2.get())) { + return false; + } + return true; + })) { + fprintf(stderr, "XAES-256-GCM seal with key commitment failed.\n"); + return false; + } + results.PrintWithBytes(name + " seal with key_commitment", chunk_len); + + assert(cmac_out_len1 == key_len/2); + assert(cmac_out_len2 == key_len/2); + } + + for (size_t chunk_len : g_chunk_lengths) { + std::unique_ptr in_storage(new uint8_t[chunk_len + kAlignment]); + std::unique_ptr out_storage( + new uint8_t[chunk_len + overhead_len + kAlignment]); + std::unique_ptr in2_storage( + new uint8_t[chunk_len + overhead_len + kAlignment]); + std::unique_ptr tag_storage( + new uint8_t[overhead_len + kAlignment]); + std::unique_ptr ad(new uint8_t[ad_len]); + BM_memset(ad.get(), 0, ad_len); + + uint8_t *const in = + static_cast(align_pointer(in_storage.get(), kAlignment)); + BM_memset(in, 0, chunk_len); + + uint8_t *const out = + static_cast(align_pointer(out_storage.get(), kAlignment)); + + uint8_t *const tag = + static_cast(align_pointer(tag_storage.get(), kAlignment)); + BM_memset(tag, 0, overhead_len); + + uint8_t *const in2 = + static_cast(align_pointer(in2_storage.get(), kAlignment)); + + size_t in2_len; + size_t out_len; + EVP_AEAD_CTX_seal(aead_ctx.get(), out, &out_len, chunk_len + overhead_len, + nonce.data()+12, nonce_len/2, + in, chunk_len, ad.get(), ad_len); + + // This is equivalent to the open function of XAES-256-GCM if the AEAD API + // is used to implement it, i.e. EVP_AEAD_CTX_open; + // it takes the nonce as input and validates the tag, it is not a streaming + // interface where Update can be called multiple times, then Final. + if (!TimeFunction(&results, [&]() -> bool { + if (!CMAC_Update(cmac_ctx.get(), cmac_msg1.data(),cmac_msg1.size()) || + !CMAC_Final(cmac_ctx.get(), gcm_key.data(), &cmac_out_len1) || + !CMAC_Reset(cmac_ctx.get()) || + !CMAC_Update(cmac_ctx.get(), cmac_msg2.data(),cmac_msg2.size()) || + !CMAC_Final(cmac_ctx.get(), gcm_key.data() + (key_len/2) , &cmac_out_len2) || + !CMAC_Reset(cmac_ctx.get()) || + !EVP_AEAD_CTX_init_with_direction(aead_ctx.get(), aead, + gcm_key.data(), key_len, + EVP_AEAD_DEFAULT_TAG_LENGTH, + evp_aead_open) || + !EVP_AEAD_CTX_open(aead_ctx.get(), in2, &in2_len, + chunk_len + overhead_len, + nonce.data()+12, nonce_len/2, out, out_len, + ad.get(), ad_len)) { + return false; + } + return true; + })) { + fprintf(stderr, "XAES-256-GCM open (decrypt) failed.\n"); + return false; + } + results.PrintWithBytes(name + " open", chunk_len); + + assert(cmac_out_len1 == key_len/2); + assert(cmac_out_len2 == key_len/2); + } + + return true; +} +#endif // !OPENSSL_BENCHMARK + static bool SpeedHashChunk(const EVP_MD *md, std::string name, size_t chunk_len) { // OpenSSL 1.0.x has a different API to create an EVP_MD_CTX @@ -3052,6 +3301,14 @@ bool Speed(const std::vector &args) { #endif #if AWSLC_API_VERSION > 31 !SpeedDigestSign(selected) || + !SpeedAEADSeal(EVP_aead_xaes_256_gcm(), "AEAD-XAES-256-GCM", kTLSADLen, selected) || + !SpeedAEADOpen(EVP_aead_xaes_256_gcm(), "AEAD-XAES-256-GCM", kTLSADLen, selected) || + !SpeedAEADSeal(EVP_aead_xaes_256_gcm_key_commit(), "AEAD-XAES-256-GCM key commit", kTLSADLen, selected) || + !SpeedAEADOpen(EVP_aead_xaes_256_gcm_key_commit(), "AEAD-XAES-256-GCM key commit", kTLSADLen, selected) || + !SpeedAEADSeal(EVP_aead_hmac_aes_256_gcm(), "AEAD-HMAC-AES-256-GCM", kTLSADLen, selected) || + !SpeedAEADOpen(EVP_aead_hmac_aes_256_gcm(), "AEAD-HMAC-AES-256-GCM", kTLSADLen, selected) || + !SpeedAEADSeal(EVP_aead_hmac_aes_256_gcm_key_commit(), "AEAD-HMAC-AES-256-GCM key commit", kTLSADLen, selected) || + !SpeedAEADOpen(EVP_aead_hmac_aes_256_gcm_key_commit(), "AEAD-HMAC-AES-256-GCM key commit", kTLSADLen, selected) || #endif !SpeedAEADSeal(EVP_aead_aes_128_gcm(), "AEAD-AES-128-GCM", kTLSADLen, selected) || !SpeedAEADOpen(EVP_aead_aes_128_gcm(), "AEAD-AES-128-GCM", kTLSADLen, selected) || @@ -3077,6 +3334,7 @@ bool Speed(const std::vector &args) { #if defined(OPENSSL_IS_AWSLC) !SpeedRefcount(selected) || #endif + !SpeedXAES256GCM("XAES-256-GCM", selected) || #if defined(INTERNAL_TOOL) !SpeedRandom(CRYPTO_sysrand, "CRYPTO_sysrand", selected) || !SpeedHashToCurve(selected) ||