diff options
author | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2019-06-29 09:09:35 +0000 |
---|---|---|
committer | Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | 2019-06-29 09:09:35 +0000 |
commit | 00c960bfaca656693d371d9777e88811d3d91d71 (patch) | |
tree | c3ef8d02d69d94ffc7f788e135e08e0917983043 | |
parent | 0725968d0605eef8acb6fdcd7d692c56141a5176 (diff) | |
parent | 7afa9278fce2f0996fa616d4da47f7f106a12673 (diff) | |
download | gnutls-00c960bfaca656693d371d9777e88811d3d91d71.tar.gz |
Merge branch 'mac-gmac' into 'master'
lib: add support for AES-GMAC
Closes #781
See merge request gnutls/gnutls!1036
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | devel/libgnutls-latest-x86_64.abi | 3 | ||||
-rw-r--r-- | lib/algorithms/mac.c | 15 | ||||
-rw-r--r-- | lib/crypto-api.c | 3 | ||||
-rw-r--r-- | lib/crypto-selftests.c | 54 | ||||
-rw-r--r-- | lib/fips.h | 3 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 10 | ||||
-rw-r--r-- | lib/nettle/mac.c | 142 | ||||
-rw-r--r-- | tests/gnutls_hmac_fast.c | 51 |
9 files changed, 280 insertions, 6 deletions
@@ -41,6 +41,8 @@ See the end for copying conditions. ** libgnutls: Added new flag for GNUTLS_CPUID_OVERRIDE 0x20: Enable SHA_NI instruction set +** libgnutls: Added support for AES-GMAC MAC (#781) + ** API and ABI modifications: gnutls_get_system_config_file: Added gnutls_crypto_register_cipher: Deprecated @@ -49,6 +51,9 @@ gnutls_crypto_register_digest: Deprecated gnutls_crypto_register_mac: Deprecated gnutls_hash_copy: Added gnutls_hmac_copy: Added +GNUTLS_MAC_AES_GMAC_128: Added +GNUTLS_MAC_AES_GMAC_192: Added +GNUTLS_MAC_AES_CMAC_256: Added * Version 3.6.8 (released 2019-05-28) diff --git a/devel/libgnutls-latest-x86_64.abi b/devel/libgnutls-latest-x86_64.abi index 3fa7f45238..17e8d40663 100644 --- a/devel/libgnutls-latest-x86_64.abi +++ b/devel/libgnutls-latest-x86_64.abi @@ -1546,6 +1546,9 @@ <enumerator name='GNUTLS_MAC_UMAC_128' value='202'/> <enumerator name='GNUTLS_MAC_AES_CMAC_128' value='203'/> <enumerator name='GNUTLS_MAC_AES_CMAC_256' value='204'/> + <enumerator name='GNUTLS_MAC_AES_GMAC_128' value='205'/> + <enumerator name='GNUTLS_MAC_AES_GMAC_192' value='206'/> + <enumerator name='GNUTLS_MAC_AES_GMAC_256' value='207'/> </enum-decl> <typedef-decl name='gnutls_mac_algorithm_t' type-id='type-id-44' id='type-id-31'/> <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-45'> diff --git a/lib/algorithms/mac.c b/lib/algorithms/mac.c index 11847f5246..ddbba2f453 100644 --- a/lib/algorithms/mac.c +++ b/lib/algorithms/mac.c @@ -162,6 +162,21 @@ mac_entry_st hash_algorithms[] = { .id = GNUTLS_MAC_AES_CMAC_256, .output_size = 16, .key_size = 32}, + {.name = "AES-GMAC-128", + .id = GNUTLS_MAC_AES_GMAC_128, + .output_size = 16, + .key_size = 16, + .nonce_size = 12}, + {.name = "AES-GMAC-192", + .id = GNUTLS_MAC_AES_GMAC_192, + .output_size = 16, + .key_size = 24, + .nonce_size = 12}, + {.name = "AES-GMAC-256", + .id = GNUTLS_MAC_AES_GMAC_256, + .output_size = 16, + .key_size = 32, + .nonce_size = 12}, {.name = "MAC-NULL", .id = GNUTLS_MAC_NULL}, {0, 0, 0, 0, 0, 0, 0, 0, 0} diff --git a/lib/crypto-api.c b/lib/crypto-api.c index 0cd3d21723..8af3f3b7dc 100644 --- a/lib/crypto-api.c +++ b/lib/crypto-api.c @@ -464,7 +464,8 @@ unsigned gnutls_hmac_get_len(gnutls_mac_algorithm_t algorithm) * @digest: is the output value of the hash * * This convenience function will hash the given data and return output - * on a single call. + * on a single call. Note, this call will not work for MAC algorithms + * that require nonce (like UMAC or GMAC). * * Returns: Zero or a negative error code on error. * diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c index eddf935680..821271f22b 100644 --- a/lib/crypto-selftests.c +++ b/lib/crypto-selftests.c @@ -1427,6 +1427,8 @@ static int test_digest(gnutls_digest_algorithm_t dig, struct mac_vectors_st { const uint8_t *key; unsigned int key_size; + const uint8_t *nonce; + unsigned int nonce_size; const uint8_t *plaintext; unsigned int plaintext_size; const uint8_t *output; @@ -1560,6 +1562,47 @@ const struct mac_vectors_st aes_cmac_256_vectors[] = { /* NIST SP800-38A */ }, }; +const struct mac_vectors_st aes_gmac_128_vectors[] = { /* NIST test vectors */ + { + STR(key, key_size, + "\x23\x70\xe3\x20\xd4\x34\x42\x08\xe0\xff\x56\x83\xf2\x43\xb2\x13"), + STR(nonce, nonce_size, + "\x04\xdb\xb8\x2f\x04\x4d\x30\x83\x1c\x44\x12\x28"), + STR(plaintext, plaintext_size, + "\xd4\x3a\x8e\x50\x89\xee\xa0\xd0\x26\xc0\x3a\x85\x17\x8b\x27\xda"), + STR(output, output_size, + "\x2a\x04\x9c\x04\x9d\x25\xaa\x95\x96\x9b\x45\x1d\x93\xc3\x1c\x6e"), + }, +}; + +const struct mac_vectors_st aes_gmac_192_vectors[] = { /* NIST test vectors */ + { + STR(key, key_size, + "\xaa\x92\x1c\xb5\xa2\x43\xab\x08\x91\x1f\x32\x89\x26\x6b\x39\xda" + "\xb1\x33\xf5\xc4\x20\xa6\xc5\xcd"), + STR(nonce, nonce_size, + "\x8f\x73\xdb\x68\xda\xee\xed\x2d\x15\x5f\xb1\xa0"), + STR(plaintext, plaintext_size, + "\x48\x74\x43\xc7\xc1\x4c\xe4\x74\xcb\x3d\x29\x1f\x25\x70\x70\xa2"), + STR(output, output_size, + "\xb1\x26\x74\xfb\xea\xc6\x88\x9a\x24\x94\x8f\x27\x92\xe3\x0a\x50"), + }, +}; + +const struct mac_vectors_st aes_gmac_256_vectors[] = { /* NIST test vectors */ + { + STR(key, key_size, + "\x6d\xfd\xaf\xd6\x70\x3c\x28\x5c\x01\xf1\x4f\xd1\x0a\x60\x12\x86" + "\x2b\x2a\xf9\x50\xd4\x73\x3a\xbb\x40\x3b\x2e\x74\x5b\x26\x94\x5d"), + STR(nonce, nonce_size, + "\x37\x49\xd0\xb3\xd5\xba\xcb\x71\xbe\x06\xad\xe6"), + STR(plaintext, plaintext_size, + "\xc0\xd2\x49\x87\x19\x92\xe7\x03\x02\xae\x00\x81\x93\xd1\xe8\x9f"), + STR(output, output_size, + "\x4a\xa4\xcc\x69\xf8\x4e\xe6\xac\x16\xd9\xbf\xb4\xe0\x5d\xe5\x00"), + }, +}; + static int test_mac(gnutls_mac_algorithm_t mac, const struct mac_vectors_st *vectors, size_t vectors_size, unsigned flags) @@ -1582,6 +1625,11 @@ static int test_mac(gnutls_mac_algorithm_t mac, return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); } + if (vectors[i].nonce_size) + gnutls_hmac_set_nonce(hd, + vectors[i].nonce, + vectors[i].nonce_size); + ret = gnutls_hmac(hd, vectors[i].plaintext, 1); if (ret < 0) return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); @@ -1794,6 +1842,12 @@ int gnutls_mac_self_test(unsigned flags, gnutls_mac_algorithm_t mac) CASE(GNUTLS_MAC_AES_CMAC_128, test_mac, aes_cmac_128_vectors); FALLTHROUGH; CASE(GNUTLS_MAC_AES_CMAC_256, test_mac, aes_cmac_256_vectors); + FALLTHROUGH; + CASE(GNUTLS_MAC_AES_GMAC_128, test_mac, aes_gmac_128_vectors); + FALLTHROUGH; + CASE(GNUTLS_MAC_AES_GMAC_192, test_mac, aes_gmac_192_vectors); + FALLTHROUGH; + CASE(GNUTLS_MAC_AES_GMAC_256, test_mac, aes_gmac_256_vectors); break; default: diff --git a/lib/fips.h b/lib/fips.h index 7385a95de0..1464c9595b 100644 --- a/lib/fips.h +++ b/lib/fips.h @@ -107,6 +107,9 @@ static unsigned is_mac_algo_forbidden(gnutls_mac_algorithm_t algo) case GNUTLS_MAC_SHA3_512: case GNUTLS_MAC_AES_CMAC_128: case GNUTLS_MAC_AES_CMAC_256: + case GNUTLS_MAC_AES_GMAC_128: + case GNUTLS_MAC_AES_GMAC_192: + case GNUTLS_MAC_AES_GMAC_256: return 0; default: if (mode == GNUTLS_FIPS140_LAX) diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 365a582805..11652a8c2b 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -278,10 +278,13 @@ typedef enum { * @GNUTLS_MAC_STREEBOG_256: HMAC GOST R 34.11-2001 (Streebog) algorithm, 256 bit. * @GNUTLS_MAC_STREEBOG_512: HMAC GOST R 34.11-2001 (Streebog) algorithm, 512 bit. * @GNUTLS_MAC_AEAD: MAC implicit through AEAD cipher. - * @GNUTLS_MAC_UMAC_96: The UMAC-96 MAC algorithm. - * @GNUTLS_MAC_UMAC_128: The UMAC-128 MAC algorithm. + * @GNUTLS_MAC_UMAC_96: The UMAC-96 MAC algorithm (requires nonce). + * @GNUTLS_MAC_UMAC_128: The UMAC-128 MAC algorithm (requires nonce). * @GNUTLS_MAC_AES_CMAC_128: The AES-CMAC-128 MAC algorithm. * @GNUTLS_MAC_AES_CMAC_256: The AES-CMAC-256 MAC algorithm. + * @GNUTLS_MAC_AES_GMAC_128: The AES-GMAC-128 MAC algorithm (requires nonce). + * @GNUTLS_MAC_AES_GMAC_192: The AES-GMAC-192 MAC algorithm (requires nonce). + * @GNUTLS_MAC_AES_GMAC_256: The AES-GMAC-256 MAC algorithm (requires nonce). * @GNUTLS_MAC_SHA3_224: Reserved; unimplemented. * @GNUTLS_MAC_SHA3_256: Reserved; unimplemented. * @GNUTLS_MAC_SHA3_384: Reserved; unimplemented. @@ -316,6 +319,9 @@ typedef enum { GNUTLS_MAC_UMAC_128 = 202, GNUTLS_MAC_AES_CMAC_128 = 203, GNUTLS_MAC_AES_CMAC_256 = 204, + GNUTLS_MAC_AES_GMAC_128 = 205, + GNUTLS_MAC_AES_GMAC_192 = 206, + GNUTLS_MAC_AES_GMAC_256 = 207, } gnutls_mac_algorithm_t; /** diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c index 8107f7cea4..5e8bcec0a7 100644 --- a/lib/nettle/mac.c +++ b/lib/nettle/mac.c @@ -42,6 +42,7 @@ #else #include "cmac.h" #endif /* HAVE_NETTLE_CMAC128_UPDATE */ +#include <nettle/gcm.h> typedef void (*update_func) (void *, size_t, const uint8_t *); typedef void (*digest_func) (void *, size_t, uint8_t *); @@ -56,6 +57,19 @@ struct md5_sha1_ctx { struct sha1_ctx sha1; }; +struct gmac_ctx { + unsigned int pos; + uint8_t buffer[GCM_BLOCK_SIZE]; + struct gcm_key key; + struct gcm_ctx ctx; + nettle_cipher_func *encrypt; + union { + struct aes128_ctx aes128; + struct aes192_ctx aes192; + struct aes256_ctx aes256; + } cipher; +}; + struct nettle_hash_ctx { union { struct md5_ctx md5; @@ -100,6 +114,7 @@ struct nettle_mac_ctx { struct umac128_ctx umac128; struct cmac_aes128_ctx cmac128; struct cmac_aes256_ctx cmac256; + struct gmac_ctx gmac; } ctx; void *ctx_ptr; @@ -143,6 +158,88 @@ _wrap_cmac256_set_key(void *ctx, size_t len, const uint8_t * key) cmac_aes256_set_key(ctx, key); } +static void +_wrap_gmac_aes128_set_key(void *_ctx, size_t len, const uint8_t * key) +{ + struct gmac_ctx *ctx = _ctx; + + if (unlikely(len != 16)) + abort(); + aes128_set_encrypt_key(&ctx->cipher.aes128, key); + gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt); + ctx->pos = 0; +} + +static void +_wrap_gmac_aes192_set_key(void *_ctx, size_t len, const uint8_t * key) +{ + struct gmac_ctx *ctx = _ctx; + + if (unlikely(len != 24)) + abort(); + aes192_set_encrypt_key(&ctx->cipher.aes192, key); + gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt); + ctx->pos = 0; +} + +static void +_wrap_gmac_aes256_set_key(void *_ctx, size_t len, const uint8_t * key) +{ + struct gmac_ctx *ctx = _ctx; + + if (unlikely(len != 32)) + abort(); + aes256_set_encrypt_key(&ctx->cipher.aes256, key); + gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt); + ctx->pos = 0; +} + +static void _wrap_gmac_set_nonce(void *_ctx, size_t nonce_length, const uint8_t *nonce) +{ + struct gmac_ctx *ctx = _ctx; + + gcm_set_iv(&ctx->ctx, &ctx->key, nonce_length, nonce); +} + +static void _wrap_gmac_update(void *_ctx, size_t length, const uint8_t *data) +{ + struct gmac_ctx *ctx = _ctx; + + if (ctx->pos + length < GCM_BLOCK_SIZE) { + memcpy(&ctx->buffer[ctx->pos], data, length); + ctx->pos += length; + return; + } + + if (ctx->pos) { + memcpy(&ctx->buffer[ctx->pos], data, GCM_BLOCK_SIZE - ctx->pos); + gcm_update(&ctx->ctx, &ctx->key, GCM_BLOCK_SIZE, ctx->buffer); + data += GCM_BLOCK_SIZE - ctx->pos; + length -= GCM_BLOCK_SIZE - ctx->pos; + } + + if (length >= GCM_BLOCK_SIZE) { + gcm_update(&ctx->ctx, &ctx->key, + length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE, + data); + data += length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE; + length %= GCM_BLOCK_SIZE; + } + + memcpy(ctx->buffer, data, length); + ctx->pos = length; +} + +static void _wrap_gmac_digest(void *_ctx, size_t length, uint8_t *digest) +{ + struct gmac_ctx *ctx = _ctx; + + if (ctx->pos) + gcm_update(&ctx->ctx, &ctx->key, ctx->pos, ctx->buffer); + gcm_digest(&ctx->ctx, &ctx->key, &ctx->cipher, ctx->encrypt, length, digest); + ctx->pos = 0; +} + static int _mac_ctx_init(gnutls_mac_algorithm_t algo, struct nettle_mac_ctx *ctx) { @@ -246,6 +343,33 @@ static int _mac_ctx_init(gnutls_mac_algorithm_t algo, ctx->ctx_ptr = &ctx->ctx.cmac256; ctx->length = CMAC128_DIGEST_SIZE; break; + case GNUTLS_MAC_AES_GMAC_128: + ctx->set_key = _wrap_gmac_aes128_set_key; + ctx->set_nonce = _wrap_gmac_set_nonce; + ctx->update = _wrap_gmac_update; + ctx->digest = _wrap_gmac_digest; + ctx->ctx_ptr = &ctx->ctx.gmac; + ctx->length = GCM_DIGEST_SIZE; + ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes128_encrypt; + break; + case GNUTLS_MAC_AES_GMAC_192: + ctx->set_key = _wrap_gmac_aes192_set_key; + ctx->set_nonce = _wrap_gmac_set_nonce; + ctx->update = _wrap_gmac_update; + ctx->digest = _wrap_gmac_digest; + ctx->ctx_ptr = &ctx->ctx.gmac; + ctx->length = GCM_DIGEST_SIZE; + ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes192_encrypt; + break; + case GNUTLS_MAC_AES_GMAC_256: + ctx->set_key = _wrap_gmac_aes256_set_key; + ctx->set_nonce = _wrap_gmac_set_nonce; + ctx->update = _wrap_gmac_update; + ctx->digest = _wrap_gmac_digest; + ctx->ctx_ptr = &ctx->ctx.gmac; + ctx->length = GCM_DIGEST_SIZE; + ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes256_encrypt; + break; default: gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; @@ -267,9 +391,13 @@ static int wrap_nettle_mac_fast(gnutls_mac_algorithm_t algo, if (ret < 0) return gnutls_assert_val(ret); - if (ctx.set_nonce) - ctx.set_nonce(&ctx, nonce_size, nonce); ctx.set_key(&ctx, key_size, key); + if (ctx.set_nonce) { + if (nonce == NULL || nonce_size == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + ctx.set_nonce(&ctx, nonce_size, nonce); + } ctx.update(&ctx, text_size, text); ctx.digest(&ctx, ctx.length, digest); @@ -289,6 +417,11 @@ static int wrap_nettle_mac_exists(gnutls_mac_algorithm_t algo) case GNUTLS_MAC_SHA512: case GNUTLS_MAC_UMAC_96: case GNUTLS_MAC_UMAC_128: + case GNUTLS_MAC_AES_CMAC_128: + case GNUTLS_MAC_AES_CMAC_256: + case GNUTLS_MAC_AES_GMAC_128: + case GNUTLS_MAC_AES_GMAC_192: + case GNUTLS_MAC_AES_GMAC_256: #if ENABLE_GOST case GNUTLS_MAC_GOSTR_94: case GNUTLS_MAC_STREEBOG_256: @@ -355,7 +488,10 @@ wrap_nettle_mac_set_nonce(void *_ctx, const void *nonce, size_t noncelen) struct nettle_mac_ctx *ctx = _ctx; if (ctx->set_nonce == NULL) - return GNUTLS_E_INVALID_REQUEST; + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + if (nonce == NULL || noncelen == 0) + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); ctx->set_nonce(ctx->ctx_ptr, noncelen, nonce); diff --git a/tests/gnutls_hmac_fast.c b/tests/gnutls_hmac_fast.c index 604ffcd396..67b10d6283 100644 --- a/tests/gnutls_hmac_fast.c +++ b/tests/gnutls_hmac_fast.c @@ -81,6 +81,57 @@ void doit(void) } } + err = + gnutls_hmac_fast(GNUTLS_MAC_AES_GMAC_128, "keykeykeykeykeyk", 16, "abcdefghabc", 8, + digest); + if (err >= 0) + fail("gnutls_hmac_fast(GMAC-128) succeeded unexpectedly: %d\n", err); + else if (err != GNUTLS_E_INVALID_REQUEST) + fail("gnutls_hmac_fast(GMAC-128) failure: %d\n", err); + else if (debug) + success("gnutls_hmac_fast(GMAC-128) OK\n"); + + err = + gnutls_hmac_fast(GNUTLS_MAC_AES_GMAC_192, "keykeykeykeykeykeykeykey", 24, + "abcdefghabc", 8, + digest); + if (err >= 0) + fail("gnutls_hmac_fast(GMAC-192) succeeded unexpectedly: %d\n", err); + else if (err != GNUTLS_E_INVALID_REQUEST) + fail("gnutls_hmac_fast(GMAC-192) failure: %d\n", err); + else if (debug) + success("gnutls_hmac_fast(GMAC-192) OK\n"); + + err = + gnutls_hmac_fast(GNUTLS_MAC_AES_GMAC_256, "keykeykeykeykeykeykeykeykeykeyke", 32, + "abcdefghabc", 8, + digest); + if (err >= 0) + fail("gnutls_hmac_fast(GMAC-256) succeeded unexpectedly: %d\n", err); + else if (err != GNUTLS_E_INVALID_REQUEST) + fail("gnutls_hmac_fast(GMAC-256) failure: %d\n", err); + else if (debug) + success("gnutls_hmac_fast(GMAC-256) OK\n"); + + err = + gnutls_hmac_fast(GNUTLS_MAC_UMAC_96, "keykeykeykeykeyk", 16, "abcdefghabc", 8, + digest); + if (err >= 0) + fail("gnutls_hmac_fast(UMAC-96) succeeded unexpectedly: %d\n", err); + else if (err != GNUTLS_E_INVALID_REQUEST) + fail("gnutls_hmac_fast(UMAC-96) failure: %d\n", err); + else if (debug) + success("gnutls_hmac_fast(UMAC-96) OK\n"); + + err = + gnutls_hmac_fast(GNUTLS_MAC_UMAC_128, "keykeykeykeykeyk", 16, "abcdefghabc", 8, + digest); + if (err >= 0) + fail("gnutls_hmac_fast(UMAC-128) succeeded unexpectedly: %d\n", err); + else if (err != GNUTLS_E_INVALID_REQUEST) + fail("gnutls_hmac_fast(UMAC-128) failure: %d\n", err); + else if (debug) + success("gnutls_hmac_fast(UMAC-128) OK\n"); gnutls_global_deinit(); } |