Add generic AES-GCM-SIV support. AES-GCM-SIV is an AEAD with nonce-misuse resistance. It can reuse hardware support for AES-GCM and thus encrypt at ~66% the speed, and decrypt at 100% the speed, of AES-GCM. See https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 This implementation is generic, not optimised, and reuses existing AES and GHASH support as much as possible. It is guarded by !OPENSSL_SMALL, at least for now. Change-Id: Ia9f77b256ef5dfb8588bb9ecfe6ee0e827626f57 Reviewed-on: https://boringssl-review.googlesource.com/12541 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/cipher/aead_test.cc b/crypto/cipher/aead_test.cc index b33a36d..8dbc8a2 100644 --- a/crypto/cipher/aead_test.cc +++ b/crypto/cipher/aead_test.cc
@@ -23,6 +23,16 @@ #include "../test/file_test.h" + +#if defined(OPENSSL_SMALL) +const EVP_AEAD* EVP_aead_aes_128_gcm_siv(void) { + return nullptr; +} +const EVP_AEAD* EVP_aead_aes_256_gcm_siv(void) { + return nullptr; +} +#endif + namespace bssl { // This program tests an AEAD against a series of test vectors from a file, @@ -302,6 +312,8 @@ static const struct KnownAEAD kAEADs[] = { { "aes-128-gcm", EVP_aead_aes_128_gcm, false }, { "aes-256-gcm", EVP_aead_aes_256_gcm, false }, + { "aes-128-gcm-siv", EVP_aead_aes_128_gcm_siv, false }, + { "aes-256-gcm-siv", EVP_aead_aes_256_gcm_siv, false }, { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false }, { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old, false }, { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true }, @@ -342,6 +354,11 @@ } const EVP_AEAD *const aead = known_aead->func(); + if (aead == NULL) { + // AEAD is not compiled in this configuration. + printf("PASS\n"); + return 0; + } if (!TestCleanupAfterInitFailure(aead)) { return 1;
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c index 9225d6a..f99022f 100644 --- a/crypto/cipher/e_aes.c +++ b/crypto/cipher/e_aes.c
@@ -1446,6 +1446,305 @@ return &aead_aes_256_ctr_hmac_sha256; } +#if !defined(OPENSSL_SMALL) + +#define EVP_AEAD_AES_GCM_SIV_TAG_LEN 16 + +struct aead_aes_gcm_siv_ctx { + union { + double align; + AES_KEY ks; + } ks; + block128_f kgk_block; + unsigned is_256:1; +}; + +static int aead_aes_gcm_siv_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + const size_t key_bits = key_len * 8; + + if (key_bits != 128 && key_bits != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_GCM_SIV_TAG_LEN; + } + + if (tag_len != EVP_AEAD_AES_GCM_SIV_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = + OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_ctx)); + if (gcm_siv_ctx == NULL) { + return 0; + } + memset(gcm_siv_ctx, 0, sizeof(struct aead_aes_gcm_siv_ctx)); + + if (aesni_capable()) { + aesni_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)aesni_encrypt; + } else if (hwaes_capable()) { + aes_hw_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)aes_hw_encrypt; + } else if (vpaes_capable()) { + vpaes_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)vpaes_encrypt; + } else { + AES_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)AES_encrypt; + } + + gcm_siv_ctx->is_256 = (key_len == 32); + ctx->aead_state = gcm_siv_ctx; + + return 1; +} + +static void aead_aes_gcm_siv_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + OPENSSL_cleanse(gcm_siv_ctx, sizeof(struct aead_aes_gcm_siv_ctx)); + OPENSSL_free(gcm_siv_ctx); +} + +/* gcm_siv_crypt encrypts (or decrypts—it's the same thing) |in_len| bytes from + * |in| to |out|, using the block function |enc_block| with |key| in counter + * mode, starting at |initial_counter|. This differs from the traditional + * counter mode code in that the counter is handled little-endian, only the + * first four bytes are used and the GCM-SIV tweak to the final byte is + * applied. The |in| and |out| pointers may be equal but otherwise must not + * alias. */ +static void gcm_siv_crypt(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t initial_counter[AES_BLOCK_SIZE], + block128_f enc_block, const AES_KEY *key) { + union { + uint32_t w[4]; + uint8_t c[16]; + } counter; + + memcpy(counter.c, initial_counter, AES_BLOCK_SIZE); + counter.c[15] |= 0x80; + + for (size_t done = 0; done < in_len;) { + uint8_t keystream[AES_BLOCK_SIZE]; + enc_block(counter.c, keystream, key); + counter.w[0]++; + + size_t todo = AES_BLOCK_SIZE; + if (in_len - done < todo) { + todo = in_len - done; + } + + for (size_t i = 0; i < todo; i++) { + out[done + i] = keystream[i] ^ in[done + i]; + } + + done += todo; + } +} + +/* gcm_siv_polyval evaluates POLYVAL at |auth_key| on the given plaintext and + * AD. The result is written to |out_tag|. */ +static void gcm_siv_polyval(uint8_t out_tag[16], const uint8_t *in, + size_t in_len, const uint8_t *ad, size_t ad_len, + const uint8_t auth_key[16]) { + struct polyval_ctx polyval_ctx; + CRYPTO_POLYVAL_init(&polyval_ctx, auth_key); + + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, ad, ad_len & ~15); + + uint8_t scratch[16]; + if (ad_len & 15) { + memset(scratch, 0, sizeof(scratch)); + memcpy(scratch, &ad[ad_len & ~15], ad_len & 15); + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch)); + } + + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, in, in_len & ~15); + if (in_len & 15) { + memset(scratch, 0, sizeof(scratch)); + memcpy(scratch, &in[in_len & ~15], in_len & 15); + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch)); + } + + union { + uint8_t c[16]; + struct { + uint64_t ad; + uint64_t in; + } bitlens; + } length_block; + + length_block.bitlens.ad = ad_len * 8; + length_block.bitlens.in = in_len * 8; + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, length_block.c, + sizeof(length_block)); + + CRYPTO_POLYVAL_finish(&polyval_ctx, out_tag); + out_tag[15] &= 0x7f; +} + +/* gcm_siv_record_keys contains the keys used for a specific GCM-SIV record. */ +struct gcm_siv_record_keys { + uint8_t auth_key[16]; + union { + double align; + AES_KEY ks; + } enc_key; + block128_f enc_block; +}; + +/* gcm_siv_keys calculates the keys for a specific GCM-SIV record with the + * given nonce and writes them to |*out_keys|. */ +static void gcm_siv_keys( + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx, + struct gcm_siv_record_keys *out_keys, + const uint8_t nonce[EVP_AEAD_AES_GCM_SIV_TAG_LEN]) { + const AES_KEY *const key = &gcm_siv_ctx->ks.ks; + gcm_siv_ctx->kgk_block(nonce, out_keys->auth_key, key); + + if (gcm_siv_ctx->is_256) { + uint8_t record_enc_key[32]; + gcm_siv_ctx->kgk_block(out_keys->auth_key, record_enc_key + 16, key); + gcm_siv_ctx->kgk_block(record_enc_key + 16, record_enc_key, key); + aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block, + record_enc_key, sizeof(record_enc_key)); + } else { + uint8_t record_enc_key[16]; + gcm_siv_ctx->kgk_block(out_keys->auth_key, record_enc_key, key); + aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block, + record_enc_key, sizeof(record_enc_key)); + } +} + +static int aead_aes_gcm_siv_seal(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) { + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + const uint64_t in_len_64 = in_len; + const uint64_t ad_len_64 = ad_len; + + if (in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN < in_len || + in_len_64 > (UINT64_C(1) << 36) || + ad_len_64 >= (UINT64_C(1) << 61)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != AES_BLOCK_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + struct gcm_siv_record_keys keys; + gcm_siv_keys(gcm_siv_ctx, &keys, nonce); + + uint8_t tag[16]; + gcm_siv_polyval(tag, in, in_len, ad, ad_len, keys.auth_key); + keys.enc_block(tag, tag, &keys.enc_key.ks); + + gcm_siv_crypt(out, in, in_len, tag, keys.enc_block, &keys.enc_key.ks); + + memcpy(&out[in_len], tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN); + *out_len = in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN; + + return 1; +} + +static int aead_aes_gcm_siv_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) { + const uint64_t ad_len_64 = ad_len; + if (ad_len_64 >= (UINT64_C(1) << 61)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + 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) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + struct gcm_siv_record_keys keys; + gcm_siv_keys(gcm_siv_ctx, &keys, nonce); + + gcm_siv_crypt(out, in, plaintext_len, &in[plaintext_len], keys.enc_block, + &keys.enc_key.ks); + + uint8_t expected_tag[EVP_AEAD_AES_GCM_SIV_TAG_LEN]; + gcm_siv_polyval(expected_tag, out, plaintext_len, ad, ad_len, keys.auth_key); + keys.enc_block(expected_tag, expected_tag, &keys.enc_key.ks); + + if (CRYPTO_memcmp(expected_tag, &in[plaintext_len], sizeof(expected_tag)) != + 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_gcm_siv = { + 16, /* key length */ + AES_BLOCK_SIZE, /* nonce length */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */ + + aead_aes_gcm_siv_init, + NULL /* init_with_direction */, + aead_aes_gcm_siv_cleanup, + aead_aes_gcm_siv_seal, + aead_aes_gcm_siv_open, + NULL /* get_iv */, +}; + +static const EVP_AEAD aead_aes_256_gcm_siv = { + 32, /* key length */ + AES_BLOCK_SIZE, /* nonce length */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */ + + aead_aes_gcm_siv_init, + NULL /* init_with_direction */, + aead_aes_gcm_siv_cleanup, + aead_aes_gcm_siv_seal, + aead_aes_gcm_siv_open, + NULL /* get_iv */, +}; + +const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void) { + return &aead_aes_128_gcm_siv; +} + +const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) { + return &aead_aes_256_gcm_siv; +} + +#endif /* !OPENSSL_SMALL */ + int EVP_has_aes_hardware(void) { #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) return aesni_capable() && crypto_gcm_clmul_enabled();
diff --git a/crypto/cipher/test/aes_128_gcm_siv_tests.txt b/crypto/cipher/test/aes_128_gcm_siv_tests.txt new file mode 100644 index 0000000..a929b59 --- /dev/null +++ b/crypto/cipher/test/aes_128_gcm_siv_tests.txt
@@ -0,0 +1,236 @@ +# This is the example from +# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-8 + +KEY: ee8e1ed9ff2540ae8f2ba9f50bc2f27c +NONCE: 752abad3e0afb5f434dc4310f71f3d21 +IN: "Hello world" +AD: "example" +CT: 810649724764545b3625ff +TAG: 010a10f4942710781d2948ac0192572f + +# Test vectors from +# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-B + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: cb52de357fad226ae428d0ed5a575496 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: 7e139f58002d68ee +TAG: 715835541f2136f03b6dc80ae0a8ac46 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: 4a87f0cd26e5d5086e90da02 +TAG: 4dff905e48d512e9c34ae8f3be66ec43 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 048ca58c46d2368ce00132389f40b511 +TAG: 971da9aa385283522c4f67a9aedb37e5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: e1cf1cf545d2743ec005b26bd2c836ac1a4233d646c195ffa401f28063127baa +TAG: 1071338b8c2930d3ec4c17cecbefa4b4 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: 2e7e6881a02d57b877794b2fbfbfef5484f1cf74f4ad53a751b2582c0e698466bd9a49dcab53806d8e31d864c4632d00 +TAG: 04b1b8a9c1630ff028b14d2e57bca429 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: 0ac5be860726209d9218de3e9d533743e1efe1595bc58f93f00e9bb9a7558dc1e1b14a9c0d49eb5064c7efa79842f9c7cfdd77614709f0b545d3227498e774d5 +TAG: 860b73a1ed8a5b9acd925c3f3f49c5c5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4919e29e9890e452 +TAG: 1433a5c0284c911163888dbd128e6874 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: db55d6da719fe0473538294e +TAG: 5a8ab948ccd205a70c78e8fdf954693b + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: aea3c54272abc1b58ed34a536743f4da +TAG: da10d98bfe23784cfdfd0af97b6d5b78 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: aa694c0cfe148100cb5c6e27a77a7ff7b4233d6af251d9faa3d84f7c0d1113f1 +TAG: 778c5b68356a1a6a6f3c14a8f96c35ca + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 9ac909928bcde79c2afa885df9c035c85a9eab136f6f6ea11034456bd306ea3c5dd542f706fffe538b5f139fa9dc622e +TAG: 26c0c0d146d38787ca0fcbc3f911577a + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: c56be9d61ecf6a31a6289cddc9b91aaf84cdb53a3913b825d6eb5e157906dfb0a308c6b0b095d6fd1a5b761ca7fa0e39ca92f38ae206eec844c0c4ab0c1c165e +TAG: a60986309b99431a35dd8c5ebeef8375 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 47995b96 +TAG: 16b668094202cadde992e0c16205793c + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 8fe25de75089e9f849150e57ab7f7810981cd319 +TAG: 89ca91ebc560709432fe9496746404cc + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: b26d43ae158316ac37f41579ccf1d461274e +TAG: 13b7c01d08dd6969d51d1bf0fbbdc4d2 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: cb52de357fad226ae428d0ed5a575496 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: 7e139f58002d68ee +TAG: 715835541f2136f03b6dc80ae0a8ac46 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: 4a87f0cd26e5d5086e90da02 +TAG: 4dff905e48d512e9c34ae8f3be66ec43 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 048ca58c46d2368ce00132389f40b511 +TAG: 971da9aa385283522c4f67a9aedb37e5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: e1cf1cf545d2743ec005b26bd2c836ac1a4233d646c195ffa401f28063127baa +TAG: 1071338b8c2930d3ec4c17cecbefa4b4 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: 2e7e6881a02d57b877794b2fbfbfef5484f1cf74f4ad53a751b2582c0e698466bd9a49dcab53806d8e31d864c4632d00 +TAG: 04b1b8a9c1630ff028b14d2e57bca429 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: 0ac5be860726209d9218de3e9d533743e1efe1595bc58f93f00e9bb9a7558dc1e1b14a9c0d49eb5064c7efa79842f9c7cfdd77614709f0b545d3227498e774d5 +TAG: 860b73a1ed8a5b9acd925c3f3f49c5c5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4919e29e9890e452 +TAG: 1433a5c0284c911163888dbd128e6874 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: db55d6da719fe0473538294e +TAG: 5a8ab948ccd205a70c78e8fdf954693b + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: aea3c54272abc1b58ed34a536743f4da +TAG: da10d98bfe23784cfdfd0af97b6d5b78 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: aa694c0cfe148100cb5c6e27a77a7ff7b4233d6af251d9faa3d84f7c0d1113f1 +TAG: 778c5b68356a1a6a6f3c14a8f96c35ca + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 9ac909928bcde79c2afa885df9c035c85a9eab136f6f6ea11034456bd306ea3c5dd542f706fffe538b5f139fa9dc622e +TAG: 26c0c0d146d38787ca0fcbc3f911577a + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: c56be9d61ecf6a31a6289cddc9b91aaf84cdb53a3913b825d6eb5e157906dfb0a308c6b0b095d6fd1a5b761ca7fa0e39ca92f38ae206eec844c0c4ab0c1c165e +TAG: a60986309b99431a35dd8c5ebeef8375 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 47995b96 +TAG: 16b668094202cadde992e0c16205793c + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 8fe25de75089e9f849150e57ab7f7810981cd319 +TAG: 89ca91ebc560709432fe9496746404cc + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: b26d43ae158316ac37f41579ccf1d461274e +TAG: 13b7c01d08dd6969d51d1bf0fbbdc4d2
diff --git a/crypto/cipher/test/aes_256_gcm_siv_tests.txt b/crypto/cipher/test/aes_256_gcm_siv_tests.txt new file mode 100644 index 0000000..cd38e23 --- /dev/null +++ b/crypto/cipher/test/aes_256_gcm_siv_tests.txt
@@ -0,0 +1,226 @@ +# Test vectors from +# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-B + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: eb7ccf36eeff369241379c87cc08e4f0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: ab3f382a6f0fb4c3 +TAG: a0a69e07b73281f5cdfd034f646cfa08 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: be8d81f033ca23b953da2197 +TAG: cdf3ba70da9c7cbd45f5140ba0cca9f1 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 46e05b7116dbe27aaeffe99892194072 +TAG: be19d78991c62130cf97f628c37c3eaa + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: 23ddbe9ef342b03003f56d6b4a2e8aff035c7d7cfd705e1ab4502904254bb67a +TAG: 16c5944034050657af7c0fec7efbc40f + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: b104c8945f280e75b52c05c45a63d1872c7f0552b1501968d9913d71207d0433f978f1a3eecdf782016b77e8c9d3ff53 +TAG: abedb4841c20f3b05e61e0fd1fcaf3d0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: e3f2bd14f4c80c9cea4c90c81f0e4d7eedb87eb19a7c0cf5a5a95cd3e441a71083b1191d115e9a9ff008b93feeb5a86d012a3e0adb89de2d1e3225479022292f +TAG: 3ced67f5e03bb476a738c1343926dc19 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4dca2c16c3b0413c +TAG: ac9b952c76a6f8b5df315f88126daa1c + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: ee0ca9068b5b85dfe115a660 +TAG: 756d6155927271077d790a05390ecb71 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: 590edb785c0cb89d19f031fa7e7d4f91 +TAG: ac2c8f711c86dbecc8c7b663c5fbc1ea + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: dcf2024f5f98d463b82a8673c47dd82159748cac8bcc7c76b8cfa26029cb333c +TAG: a9b406643e190e602fb104fbb842a1ac + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 79216506b1ddadfe16366e4ec886d10dc9400b995259f74c0091f9b5a6add5680a612130f6c31ab833aa76d9b2be86de +TAG: 3ddfe9ad2c350980942638d3f954ac6d + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: 9535eb67240c49f30a0de5a90670813fa615e71fcb4c522ca79d9a33459a22f8c6a56d650bf0b15eecdd706e7689cf6510a281724613fea76b5366b40574b1b9 +TAG: abcb59ee31d25ee8889b70d7c36f9a41 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 9611baa0 +TAG: 53daf2bc5916f7a6750f2432068dabee + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 78e3a1b54daa6547f775f30c38a45e887aea5c87 +TAG: f65187d8c28adba364d659b627b16431 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: c6d3d28704bf20067d62e1a3872d40dda44b +TAG: 6ac0135a4379dbc67967ff55fd4d1f2f + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: eb7ccf36eeff369241379c87cc08e4f0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: ab3f382a6f0fb4c3 +TAG: a0a69e07b73281f5cdfd034f646cfa08 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: be8d81f033ca23b953da2197 +TAG: cdf3ba70da9c7cbd45f5140ba0cca9f1 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 46e05b7116dbe27aaeffe99892194072 +TAG: be19d78991c62130cf97f628c37c3eaa + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: 23ddbe9ef342b03003f56d6b4a2e8aff035c7d7cfd705e1ab4502904254bb67a +TAG: 16c5944034050657af7c0fec7efbc40f + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: b104c8945f280e75b52c05c45a63d1872c7f0552b1501968d9913d71207d0433f978f1a3eecdf782016b77e8c9d3ff53 +TAG: abedb4841c20f3b05e61e0fd1fcaf3d0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: e3f2bd14f4c80c9cea4c90c81f0e4d7eedb87eb19a7c0cf5a5a95cd3e441a71083b1191d115e9a9ff008b93feeb5a86d012a3e0adb89de2d1e3225479022292f +TAG: 3ced67f5e03bb476a738c1343926dc19 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4dca2c16c3b0413c +TAG: ac9b952c76a6f8b5df315f88126daa1c + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: ee0ca9068b5b85dfe115a660 +TAG: 756d6155927271077d790a05390ecb71 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: 590edb785c0cb89d19f031fa7e7d4f91 +TAG: ac2c8f711c86dbecc8c7b663c5fbc1ea + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: dcf2024f5f98d463b82a8673c47dd82159748cac8bcc7c76b8cfa26029cb333c +TAG: a9b406643e190e602fb104fbb842a1ac + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 79216506b1ddadfe16366e4ec886d10dc9400b995259f74c0091f9b5a6add5680a612130f6c31ab833aa76d9b2be86de +TAG: 3ddfe9ad2c350980942638d3f954ac6d + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: 9535eb67240c49f30a0de5a90670813fa615e71fcb4c522ca79d9a33459a22f8c6a56d650bf0b15eecdd706e7689cf6510a281724613fea76b5366b40574b1b9 +TAG: abcb59ee31d25ee8889b70d7c36f9a41 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 9611baa0 +TAG: 53daf2bc5916f7a6750f2432068dabee + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 78e3a1b54daa6547f775f30c38a45e887aea5c87 +TAG: f65187d8c28adba364d659b627b16431 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: c6d3d28704bf20067d62e1a3872d40dda44b +TAG: 6ac0135a4379dbc67967ff55fd4d1f2f
diff --git a/crypto/modes/CMakeLists.txt b/crypto/modes/CMakeLists.txt index 17faa15..dc9e504 100644 --- a/crypto/modes/CMakeLists.txt +++ b/crypto/modes/CMakeLists.txt
@@ -48,10 +48,11 @@ OBJECT cbc.c - ctr.c - ofb.c cfb.c + ctr.c gcm.c + ofb.c + polyval.c ${MODES_ARCH_SOURCES} )
diff --git a/crypto/modes/internal.h b/crypto/modes/internal.h index 64232c4..a53da04 100644 --- a/crypto/modes/internal.h +++ b/crypto/modes/internal.h
@@ -189,6 +189,12 @@ uint8_t ecount_buf[16], unsigned *num, ctr128_f ctr); +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec); +#endif + /* GCM. * @@ -328,11 +334,36 @@ block128_f block); -#if !defined(OPENSSL_NO_ASM) && \ - (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) -void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, - const void *key, const uint8_t *ivec); -#endif +/* POLYVAL. + * + * POLYVAL is a polynomial authenticator that operates over a field very + * similar to the one that GHASH uses. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-3. */ + +typedef union { + uint64_t u[2]; + uint8_t c[16]; +} polyval_block; + +struct polyval_ctx { + polyval_block S; + u128 Htable[16]; + gmult_func gmult; + ghash_func ghash; +}; + +/* CRYPTO_POLYVAL_init initialises |ctx| using |key|. */ +void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]); + +/* CRYPTO_POLYVAL_update_blocks updates the accumulator in |ctx| given the + * blocks from |in|. Only a whole number of blocks can be processed so |in_len| + * must be a multiple of 16. */ +void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in, + size_t in_len); + +/* CRYPTO_POLYVAL_finish writes the accumulator from |ctx| to |out|. */ +void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]); + #if defined(__cplusplus) } /* extern C */
diff --git a/crypto/modes/polyval.c b/crypto/modes/polyval.c new file mode 100644 index 0000000..c5121a1 --- /dev/null +++ b/crypto/modes/polyval.c
@@ -0,0 +1,93 @@ +/* Copyright (c) 2016, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <openssl/base.h> + +#if !defined(OPENSSL_SMALL) + +#include <assert.h> +#include <string.h> + +#include "internal.h" +#include "../internal.h" + + +/* byte_reverse reverses the order of the bytes in |b->c|. */ +static void byte_reverse(polyval_block *b) { + const uint64_t t = CRYPTO_bswap8(b->u[0]); + b->u[0] = CRYPTO_bswap8(b->u[1]); + b->u[1] = t; +} + +/* reverse_and_mulX_ghash interprets the bytes |b->c| as a reversed element of + * the GHASH field, multiplies that by 'x' and serialises the result back into + * |b|, but with GHASH's backwards bit ordering. */ +static void reverse_and_mulX_ghash(polyval_block *b) { + uint64_t hi = b->u[0]; + uint64_t lo = b->u[1]; + const unsigned carry = constant_time_eq(hi & 1, 1); + hi >>= 1; + hi |= lo << 63; + lo >>= 1; + lo ^= ((uint64_t) constant_time_select(carry, 0xe1, 0)) << 56; + + b->u[0] = CRYPTO_bswap8(lo); + b->u[1] = CRYPTO_bswap8(hi); +} + +/* POLYVAL(H, X_1, ..., X_n) = + * ByteReverse(GHASH(mulX_GHASH(ByteReverse(H)), ByteReverse(X_1), ..., + * ByteReverse(X_n))). + * + * See https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-A. */ + +void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]) { + polyval_block H; + memcpy(H.c, key, 16); + reverse_and_mulX_ghash(&H); + + CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, ctx->Htable, H.c); + memset(&ctx->S, 0, sizeof(ctx->S)); +} + +void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in, + size_t in_len) { + assert((in_len & 15) == 0); + polyval_block reversed[32]; + + while (in_len > 0) { + size_t todo = in_len; + if (todo > sizeof(reversed)) { + todo = sizeof(reversed); + } + memcpy(reversed, in, todo); + in_len -= todo; + + size_t blocks = todo / sizeof(polyval_block); + for (size_t i = 0; i < blocks; i++) { + byte_reverse(&reversed[i]); + } + + ctx->ghash(ctx->S.u, ctx->Htable, (const uint8_t *) reversed, todo); + } +} + +void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]) { + polyval_block S = ctx->S; + byte_reverse(&S); + memcpy(out, &S.c, sizeof(polyval_block)); +} + + +#endif /* !OPENSSL_SMALL */
diff --git a/include/openssl/aead.h b/include/openssl/aead.h index fff0e49..eaa2b8f 100644 --- a/include/openssl/aead.h +++ b/include/openssl/aead.h
@@ -114,6 +114,14 @@ * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void); +/* EVP_aead_aes_128_gcm_siv is AES-128 in GCM-SIV mode. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void); + +/* EVP_aead_aes_256_gcm_siv is AES-256 in GCM-SIV mode. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void); + /* EVP_has_aes_hardware returns one if we enable hardware support for fast and * constant-time AES-GCM. */ OPENSSL_EXPORT int EVP_has_aes_hardware(void);
diff --git a/tool/speed.cc b/tool/speed.cc index f16a9eb..5fd1058 100644 --- a/tool/speed.cc +++ b/tool/speed.cc
@@ -654,6 +654,12 @@ kLegacyADLen, selected) || !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1", kLegacyADLen, selected) || +#if !defined(OPENSSL_SMALL) + !SpeedAEAD(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen, + selected) || + !SpeedAEAD(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen, + selected) || +#endif !SpeedHash(EVP_sha1(), "SHA-1", selected) || !SpeedHash(EVP_sha256(), "SHA-256", selected) || !SpeedHash(EVP_sha512(), "SHA-512", selected) ||
diff --git a/util/all_tests.json b/util/all_tests.json index d2e39ce..5ffa5e8 100644 --- a/util/all_tests.json +++ b/util/all_tests.json
@@ -8,6 +8,8 @@ ["crypto/chacha/chacha_test"], ["crypto/cipher/aead_test", "aes-128-gcm", "crypto/cipher/test/aes_128_gcm_tests.txt"], ["crypto/cipher/aead_test", "aes-256-gcm", "crypto/cipher/test/aes_256_gcm_tests.txt"], + ["crypto/cipher/aead_test", "aes-128-gcm-siv", "crypto/cipher/test/aes_128_gcm_siv_tests.txt"], + ["crypto/cipher/aead_test", "aes-256-gcm-siv", "crypto/cipher/test/aes_256_gcm_siv_tests.txt"], ["crypto/cipher/aead_test", "chacha20-poly1305", "crypto/cipher/test/chacha20_poly1305_tests.txt"], ["crypto/cipher/aead_test", "chacha20-poly1305-old", "crypto/cipher/test/chacha20_poly1305_old_tests.txt"], ["crypto/cipher/aead_test", "aes-128-cbc-sha1-tls", "crypto/cipher/test/aes_128_cbc_sha1_tls_tests.txt"],