From dce3dd8b88e8f3b44ebbef9877ee4074b937452d Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 10:54:37 +0100 Subject: [PATCH 01/23] AES-CCM: Definitions and dispatch Given that AES-CCM comes in various shapes and sizes, the function may still need renaming (not sure whether it makes sense to have it parametrized like AES-GCM), but the constants should be good. --- include/cose/crypto.h | 22 ++++++++++++++++++++++ include/cose_defines.h | 1 + src/cose_crypto.c | 12 ++++++++++++ 3 files changed, 35 insertions(+) diff --git a/include/cose/crypto.h b/include/cose/crypto.h index 158d024..acc904a 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -150,6 +150,8 @@ extern "C" { #define COSE_CRYPTO_AEAD_AES256GCM_NONCEBYTES COSE_CRYPTO_AEAD_AESGCM_NONCEBYTES #define COSE_CRYPTO_AEAD_AES256GCM_ABYTES COSE_CRYPTO_AEAD_AESGCM_ABYTES +#define COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES 16 +#define COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES 8 /** @} */ @@ -233,6 +235,26 @@ int cose_crypto_aead_decrypt_aesgcm(uint8_t *msg, const uint8_t *k, size_t keysize); +int cose_crypto_aead_encrypt_aesccm(uint8_t *c, + size_t *clen, + const uint8_t *msg, + size_t msglen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize); + +int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, + size_t *msglen, + const uint8_t *c, + size_t clen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize); + /** * Generate a symmetric key for AEAD operations */ diff --git a/include/cose_defines.h b/include/cose_defines.h index 84ff534..f226cc4 100644 --- a/include/cose_defines.h +++ b/include/cose_defines.h @@ -160,6 +160,7 @@ typedef enum { COSE_ALGO_A128GCM = 1, /**< AES-GCM mode w/ 128-bit key, 128-bit tag */ COSE_ALGO_A192GCM = 2, /**< AES-GCM mode w/ 192-bit key, 128-bit tag */ COSE_ALGO_A256GCM = 3, /**< AES-GCM mode w/ 256-bit key, 128-bit tag */ + COSE_ALGO_AESCCM_16_64_128 = 10, /**< AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce */ COSE_ALGO_CHACHA20POLY1305 = 24, /**< IETF ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag */ } cose_algo_t; diff --git a/src/cose_crypto.c b/src/cose_crypto.c index 5f67eb4..07ca58f 100644 --- a/src/cose_crypto.c +++ b/src/cose_crypto.c @@ -49,6 +49,10 @@ bool cose_crypto_is_aead(cose_algo_t algo) switch(algo) { case COSE_ALGO_CHACHA20POLY1305: return true; +#ifdef HAVE_ALGO_AESCCM_16_64_128 + case COSE_ALGO_AESCCM_16_64_128: + return true; +#endif default: return false; } @@ -82,6 +86,10 @@ int cose_crypto_aead_encrypt(uint8_t *c, /* NOLINT(readability-non-const-parame #ifdef HAVE_ALGO_AES128GCM case COSE_ALGO_A128GCM: return cose_crypto_aead_encrypt_aesgcm(c, clen, msg, msglen, aad, aadlen, npub, key, COSE_CRYPTO_AEAD_AES128GCM_KEYBYTES); +#endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 + case COSE_ALGO_AESCCM_16_64_128: + return cose_crypto_aead_encrypt_aesccm(c, clen, msg, msglen, aad, aadlen, npub, key, COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES); #endif default: (void)c; @@ -124,6 +132,10 @@ int cose_crypto_aead_decrypt(uint8_t *msg, /* NOLINT(readability-non-const-param #ifdef HAVE_ALGO_AES128GCM case COSE_ALGO_A128GCM: return cose_crypto_aead_decrypt_aesgcm(msg, msglen, c, clen, aad, aadlen, npub, k, COSE_CRYPTO_AEAD_AES128GCM_KEYBYTES); +#endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 + case COSE_ALGO_AESCCM_16_64_128: + return cose_crypto_aead_decrypt_aesccm(msg, msglen, c, clen, aad, aadlen, npub, k, COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES); #endif default: (void)c; From 2faf45bb0e20dc7b5ed51a0cfe70f7ceced88fc3 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 11:20:47 +0100 Subject: [PATCH 02/23] Add glue code for tinyDTLS' AES-CCM-16-64-128 --- include/cose/crypto.h | 3 ++ include/cose/crypto/tinydtls.h | 45 +++++++++++++++++++++++++++ src/crypt/tinydtls.c | 56 ++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 include/cose/crypto/tinydtls.h create mode 100644 src/crypt/tinydtls.c diff --git a/include/cose/crypto.h b/include/cose/crypto.h index acc904a..01fd6f0 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -44,6 +44,9 @@ #if defined(CRYPTO_HACL) #include "cose/crypto/hacl.h" #endif +#if defined(CRYPTO_TINYDTLS) +#include "cose/crypto/tinydtls.h" +#endif #ifdef __cplusplus extern "C" { diff --git a/include/cose/crypto/tinydtls.h b/include/cose/crypto/tinydtls.h new file mode 100644 index 0000000..92da23a --- /dev/null +++ b/include/cose/crypto/tinydtls.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 Freie Universitat Berlin + * Copyright (C) 2018 Inria + * Copyright (C) 2020 Christian Amsüss and Ericsson AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cose_cryto_tinydtls Crypto glue layer, tinydtls definitions + * @ingroup cose_crypto + * + * Crypto function api for glueing tinydtls' AEAD functions. + * @{ + * + * @file + * @brief Crypto function api for glueing tinydtls. + * + * @author Christian Amsüss + */ + +#ifndef COSE_CRYPTO_TINYDTLS_H +#define COSE_CRYPTO_TINYDTLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name list of provided algorithms + * + * @{ + */ +#define HAVE_ALGO_AESCCM_16_64_128 /**< AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @} */ diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c new file mode 100644 index 0000000..6c2577a --- /dev/null +++ b/src/crypt/tinydtls.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 Christian Amsüss and Ericsson AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * Glue layer between libcose and tinydtls + */ + +#include "cose.h" +#include "cose/crypto.h" + +#include /* tinydtls', that is */ + +int cose_crypto_aead_encrypt_aesccm(uint8_t *c, + size_t *clen, + const uint8_t *msg, + size_t msglen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize) +{ + // Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 + int ret = dtls_encrypt(msg, msglen, c, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); + if (ret == msglen + COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { + *clen = ret; + return COSE_OK; + } else { + return COSE_ERR_CRYPTO; + } +} + +int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, + size_t *msglen, + const uint8_t *c, + size_t clen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize) +{ + // Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 + int ret = dtls_decrypt(c, clen, msg, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); + if (ret == clen - COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { + *msglen = ret; + return COSE_OK; + } else { + return COSE_ERR_CRYPTO; + } +} From d2e3d78390494bde9d361793bfb4df394498fb38 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 14:28:42 +0100 Subject: [PATCH 03/23] Avoid sign-mixed comparison ... fixing failure to build with strict RIOT configurations. Checking for <0 before casting to unsigned ensures that all cases are covered; the compiler is invited to do any further optimization. --- src/crypt/tinydtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c index 6c2577a..c98a281 100644 --- a/src/crypt/tinydtls.c +++ b/src/crypt/tinydtls.c @@ -27,7 +27,7 @@ int cose_crypto_aead_encrypt_aesccm(uint8_t *c, { // Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 int ret = dtls_encrypt(msg, msglen, c, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); - if (ret == msglen + COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { + if (ret >= 0 && (size_t)ret == msglen + COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { *clen = ret; return COSE_OK; } else { @@ -47,7 +47,7 @@ int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, { // Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 int ret = dtls_decrypt(c, clen, msg, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); - if (ret == clen - COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { + if (ret >= 0 && (size_t)ret == clen - COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { *msglen = ret; return COSE_OK; } else { From cb4264e633fad47b255f4fa38af11f05df0948d4 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 15:00:09 +0100 Subject: [PATCH 04/23] fixup! AES-CCM: Definitions and dispatch --- include/cose/crypto.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/cose/crypto.h b/include/cose/crypto.h index 01fd6f0..5878234 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -155,6 +155,7 @@ extern "C" { #define COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES 16 #define COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES 8 +#define COSE_CRYPTO_AEAD_AESCCM_16_64_128_NONCEBYTES 13 /** @} */ From d65716eb806852a741a37dbe0c1bb80eebca25c4 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 16:09:21 +0100 Subject: [PATCH 05/23] void-cast sign/verify arguments in default handler In scenarios where no signature algorithms are present (like when using only a backend that can do AEAD), this prevents "unused parameter" compiler errors. --- src/cose_crypto.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cose_crypto.c b/src/cose_crypto.c index 07ca58f..a6331f2 100644 --- a/src/cose_crypto.c +++ b/src/cose_crypto.c @@ -181,6 +181,11 @@ int cose_crypto_sign(const cose_key_t *key, uint8_t *sign, size_t *signlen, uint break; #endif default: + (void)key; + (void)sign; + (void)signlen; + (void)msg; + (void)msglen; return COSE_ERR_NOTIMPLEMENTED; } return 0; @@ -204,6 +209,11 @@ int cose_crypto_verify(const cose_key_t *key, const uint8_t *sign, size_t signle break; #endif default: + (void)key; + (void)sign; + (void)signlen; + (void)msg; + (void)msglen; return COSE_ERR_NOTIMPLEMENTED; } return 0; From 5d1ec74490bde32a661c0ebd3936371691a14795 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 18:38:48 +0100 Subject: [PATCH 06/23] tests: Don't attempt to sign when no algorithms are available Following the precendent in suit.c that already uses that condition. --- tests/sign.c | 11 ++++++++--- tests/suit.c | 8 +++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/sign.c b/tests/sign.c index 597d4d4..beece81 100644 --- a/tests/sign.c +++ b/tests/sign.c @@ -20,9 +20,6 @@ #include "CUnit/Basic.h" #include "CUnit/Automated.h" -static char kid[] = "koen@example.org"; -static char kid2[] = "koen@example.net"; - #ifdef HAVE_ALGO_EDDSA #define TEST_CRYPTO_SIGN_PUBLICKEYBYTES COSE_CRYPTO_SIGN_ED25519_PUBLICKEYBYTES #define TEST_CRYPTO_SIGN_SECRETKEYBYTES COSE_CRYPTO_SIGN_ED25519_SECRETKEYBYTES @@ -31,6 +28,11 @@ static char kid2[] = "koen@example.net"; #define TEST_CRYPTO_SIGN_SECRETKEYBYTES COSE_CRYPTO_SIGN_P521_SECRETKEYBYTES #endif +#if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) + +static char kid[] = "koen@example.org"; +static char kid2[] = "koen@example.net"; + static unsigned char pkx1[TEST_CRYPTO_SIGN_PUBLICKEYBYTES]; static unsigned char pky1[TEST_CRYPTO_SIGN_PUBLICKEYBYTES]; static unsigned char sk1[TEST_CRYPTO_SIGN_SECRETKEYBYTES]; @@ -486,8 +488,10 @@ void test_sign8(void) verification = cose_sign_verify(&verify, &vsignature, &key, ver_buf, sizeof(ver_buf)); CU_ASSERT_NOT_EQUAL(verification, COSE_OK); } +#endif const test_t tests_sign[] = { +#if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) { .f = test_sign1, .n = "Sign with 1 sig", @@ -520,6 +524,7 @@ const test_t tests_sign[] = { .f = test_sign8, .n = "Sign with aad test", }, +#endif { .f = NULL, .n = NULL, diff --git a/tests/suit.c b/tests/suit.c index c5da4cf..5f3e567 100644 --- a/tests/suit.c +++ b/tests/suit.c @@ -20,8 +20,6 @@ #include "CUnit/Basic.h" #include "CUnit/Automated.h" -static uint8_t buf[2048]; - #ifdef HAVE_ALGO_EDDSA static const unsigned char cose_suit[] = { 0xd8, 0x62, 0x84, 0x44, 0xa1, 0x03, 0x18, 0x2a, 0xa0, 0x58, 0xcd, 0x8a, @@ -115,9 +113,12 @@ static unsigned char pk_y[COSE_CRYPTO_SIGN_P521_PUBLICKEYBYTES] = { #define COSE_ALGO COSE_ALGO_ES256 #define COSE_CURVE COSE_EC_CURVE_P256 - #endif +#if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) + +static uint8_t buf[2048]; + static const uint8_t keyid[] = "Something@somewhere"; static void print_bytestr(const uint8_t *bytes, size_t len) @@ -159,6 +160,7 @@ void test_suit1(void) CU_ASSERT(res); CU_ASSERT_EQUAL(memcmp(kid, keyid, sizeof(keyid) - 1), 0); } +#endif const test_t tests_suit[] = { #if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) From aa03794bae94fe0c58bd8e2ae16b0a3b49d2f02a Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 20:35:59 +0100 Subject: [PATCH 07/23] tinydtls: Add test integration Along with its Makefile, tinydtls also needs a minimal configuration header as it might be output by a configure script (but its complexity is low enough that a static file does just as well for our purposes, and is much less of a hassle). For AES-CCM, a single encrypt-decrypt test is run, based on the Packet Vector 1 of . --- Makefile | 3 + makefiles/tinydtls.mk | 14 +++++ makefiles/tinydtls_config/dtls_config.h | 10 ++++ tests/crypto.c | 75 +++++++++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 makefiles/tinydtls.mk create mode 100644 makefiles/tinydtls_config/dtls_config.h diff --git a/Makefile b/Makefile index 1e95084..879d2dd 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,9 @@ endif ifneq (,$(filter c25519,$(CRYPTO))) include $(MK_DIR)/c25519.mk endif +ifneq (,$(filter tinydtls,$(CRYPTO))) + include $(MK_DIR)/tinydtls.mk +endif CFLAGS += $(CFLAGS_CRYPTO) diff --git a/makefiles/tinydtls.mk b/makefiles/tinydtls.mk new file mode 100644 index 0000000..f24c0a2 --- /dev/null +++ b/makefiles/tinydtls.mk @@ -0,0 +1,14 @@ +TINYDTLS_DIR ?= ../tinydtls +TINYDTLS_CONFIGDIR ?= makefiles/tinydtls_config/ +CFLAGS += -DCRYPTO_TINYDTLS +CRYPTOSRC += $(SRC_DIR)/crypt/tinydtls.c +CFLAGS_CRYPTO += -I$(TINYDTLS_DIR) +CFLAGS_CRYPTO += -I$(TINYDTLS_CONFIGDIR) +CRYPTOOBJS += $(TINYDTLS_DIR)/crypto.o +CRYPTOOBJS += $(TINYDTLS_DIR)/aes/rijndael.o +CRYPTOOBJS += $(TINYDTLS_DIR)/aes/rijndael_wrap.o +CRYPTOOBJS += $(TINYDTLS_DIR)/hmac.o +CRYPTOOBJS += $(TINYDTLS_DIR)/ccm.o +CRYPTOOBJS += $(TINYDTLS_DIR)/sha2/sha2.o +CRYPTOOBJS += $(TINYDTLS_DIR)/netq.o +$(CRYPTOOBJS): CFLAGS += -Wno-old-style-declaration -Wno-empty-body diff --git a/makefiles/tinydtls_config/dtls_config.h b/makefiles/tinydtls_config/dtls_config.h new file mode 100644 index 0000000..b787a93 --- /dev/null +++ b/makefiles/tinydtls_config/dtls_config.h @@ -0,0 +1,10 @@ +// Not that we'd need *that* code, but if neither ECC nro PSK is defined, +// there's empty unions and such (and newer verisons of the library complain +// more explicitly) +#define DTLS_PSK + +// Similarly, without a SHA algorithm, there's unused variables and such +#define WITH_SHA256 + +// Without, we get a #warning that is escalated to an #error by -Werror +#define HAVE_ASSERT_H diff --git a/tests/crypto.c b/tests/crypto.c index 601f373..1e990d5 100644 --- a/tests/crypto.c +++ b/tests/crypto.c @@ -186,6 +186,75 @@ void test_crypto_aes256(void) } #endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 +// Values from https://www.rfc-editor.org/rfc/rfc3610.html#section-8 +static const uint8_t aesccm1_key[16] = { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, +}; + +static const uint8_t aesccm1_nonce[13] = { + 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, +}; + +static const uint8_t aesccm1_input[31] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e +}; + +static const uint8_t aesccm1_output[39] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x58, 0x8c, 0x97, 0x9a, + 0x61, 0xc6, 0x63, 0xd2, 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, 0xe8, 0xd1, 0x2c, 0xfd, + 0xf9, 0x26, 0xe0, +}; + +// The input and output packets in the RFC's test vectors are shown in +// concatenated form AAD || cleartext and AAD || ciphertext || tag, +// respectively; this plucks them apart. + +static const uint8_t *aesccm1_aad = &aesccm1_input[0]; +static const size_t aesccm1_aad_len = 8; + +static const uint8_t *aesccm1_plaintext = &aesccm1_input[aesccm1_aad_len]; +static const size_t aesccm1_plaintext_len = sizeof(aesccm1_input) - aesccm1_aad_len; + +static const uint8_t *aesccm1_ciphertext = &aesccm1_output[aesccm1_aad_len]; +static const size_t aesccm1_ciphertext_len = sizeof(aesccm1_output) - aesccm1_aad_len; + +void test_crypto_aesccm_vector(void) +{ + unsigned char ciphertext[aesccm1_ciphertext_len]; + unsigned char plaintext[aesccm1_plaintext_len]; + + size_t cipherlen = 0; + size_t msglen = 0; + /* Generate key */ + cose_crypto_aead_encrypt( + ciphertext, &cipherlen, + aesccm1_plaintext, aesccm1_plaintext_len, + aesccm1_aad, aesccm1_aad_len, + NULL, aesccm1_nonce, + aesccm1_key, + COSE_ALGO_AESCCM_16_64_128 + ); + CU_ASSERT_EQUAL(aesccm1_ciphertext_len, cipherlen); + CU_ASSERT_EQUAL(memcmp(ciphertext, aesccm1_ciphertext, aesccm1_ciphertext_len), 0); + CU_ASSERT_EQUAL( + cose_crypto_aead_decrypt( + plaintext, &msglen, + ciphertext, cipherlen, + aesccm1_aad, aesccm1_aad_len, + aesccm1_nonce, + aesccm1_key, + COSE_ALGO_AESCCM_16_64_128 + ), + 0 ); + CU_ASSERT_EQUAL(msglen, aesccm1_plaintext_len); + CU_ASSERT_EQUAL(memcmp(aesccm1_plaintext, plaintext, aesccm1_plaintext_len), 0); +} +#endif + const test_t tests_crypto[] = { #ifdef HAVE_ALGO_EDDSA { @@ -220,6 +289,12 @@ const test_t tests_crypto[] = { .f = test_crypto_aes256, .n = "AEAD aes256gcm encrypt/decrypt", }, +#endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 + { + .f = test_crypto_aesccm_vector, + .n = "AEAD Chacha20poly1305 encrypt/decrypt with IETF test vector", + }, #endif { .f = NULL, From cd4c910b89d370afdb5aa6ffd5e9f95f5d0f2c9b Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 20:39:46 +0100 Subject: [PATCH 08/23] Run tests for tinydtls in CI --- .cirrus.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.cirrus.yml b/.cirrus.yml index d4208ba..9d95240 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -69,6 +69,11 @@ build_task: - apt install -y unzip - wget https://www.dlbeer.co.nz/downloads/c25519-2017-10-05.zip -O ../c25519.zip - bash -c 'cd .. && unzip c25519.zip' + - name: tinydtls + env: + CRYPTO: tinydtls + crypto_script: + - git clone https://github.com/eclipse/tinydtls.git ../tinydtls -b develop test_script: - ls -al - pwd From f9da347cd6f686530e4ab334115129847cc899a6 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 20:43:13 +0100 Subject: [PATCH 09/23] CI: Insall gcc-dev library available on buster Since the silkeh/clang images use Debian buster now, libgcc-6-dev is not available any more; replacing with the latest that is. --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index 9d95240..3b35df2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -19,7 +19,7 @@ build_task: MBEDTLS_LIB: /usr/lib/x86_64-linux-gnu/libmbedcrypto.so install_script: - apt update - - apt install -y libgcc-6-dev build-essential pkg-config libcunit1-dev wget libsodium-dev libmbedtls-dev ca-certificates + - apt install -y libgcc-8-dev build-essential pkg-config libcunit1-dev wget libsodium-dev libmbedtls-dev ca-certificates - git clone https://github.com/intel/tinycbor/ ../tinycbor - bash -c "cd ../tinycbor && make -j" - git clone https://github.com/bergzand/nanocbor/ ../nanocbor From c09e819e8c78dae788b27fa8c6c0d727854c8ba4 Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 14 Jan 2020 20:52:56 +0100 Subject: [PATCH 10/23] tinydtls tests: Fixes for Clang Clang is a bit stricter when it comes to static arrays with the size of a static const, replacing with defined expressions. The removed allowed compiler warnings were only relevant to the older released versions of tinydtls ("master") branch, which was never used in a committed version of this port -- but the new ones are required for Clang and do not disturb GCC operation. --- makefiles/tinydtls.mk | 2 +- tests/crypto.c | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/makefiles/tinydtls.mk b/makefiles/tinydtls.mk index f24c0a2..8401ff9 100644 --- a/makefiles/tinydtls.mk +++ b/makefiles/tinydtls.mk @@ -11,4 +11,4 @@ CRYPTOOBJS += $(TINYDTLS_DIR)/hmac.o CRYPTOOBJS += $(TINYDTLS_DIR)/ccm.o CRYPTOOBJS += $(TINYDTLS_DIR)/sha2/sha2.o CRYPTOOBJS += $(TINYDTLS_DIR)/netq.o -$(CRYPTOOBJS): CFLAGS += -Wno-old-style-declaration -Wno-empty-body +$(CRYPTOOBJS): CFLAGS += -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-function diff --git a/tests/crypto.c b/tests/crypto.c index 1e990d5..129aeea 100644 --- a/tests/crypto.c +++ b/tests/crypto.c @@ -214,44 +214,44 @@ static const uint8_t aesccm1_output[39] = { // respectively; this plucks them apart. static const uint8_t *aesccm1_aad = &aesccm1_input[0]; -static const size_t aesccm1_aad_len = 8; +#define AESCCM1_AAD_LEN 8 -static const uint8_t *aesccm1_plaintext = &aesccm1_input[aesccm1_aad_len]; -static const size_t aesccm1_plaintext_len = sizeof(aesccm1_input) - aesccm1_aad_len; +static const uint8_t *aesccm1_plaintext = &aesccm1_input[AESCCM1_AAD_LEN]; +#define AESCCM1_PLAINTEXT_LEN (sizeof(aesccm1_input) - AESCCM1_AAD_LEN) -static const uint8_t *aesccm1_ciphertext = &aesccm1_output[aesccm1_aad_len]; -static const size_t aesccm1_ciphertext_len = sizeof(aesccm1_output) - aesccm1_aad_len; +static const uint8_t *aesccm1_ciphertext = &aesccm1_output[AESCCM1_AAD_LEN]; +#define AESCCM1_CIPHERTEXT_LEN (sizeof(aesccm1_output) - AESCCM1_AAD_LEN) void test_crypto_aesccm_vector(void) { - unsigned char ciphertext[aesccm1_ciphertext_len]; - unsigned char plaintext[aesccm1_plaintext_len]; + unsigned char ciphertext[AESCCM1_CIPHERTEXT_LEN]; + unsigned char plaintext[AESCCM1_PLAINTEXT_LEN]; size_t cipherlen = 0; size_t msglen = 0; /* Generate key */ cose_crypto_aead_encrypt( ciphertext, &cipherlen, - aesccm1_plaintext, aesccm1_plaintext_len, - aesccm1_aad, aesccm1_aad_len, + aesccm1_plaintext, AESCCM1_PLAINTEXT_LEN, + aesccm1_aad, AESCCM1_AAD_LEN, NULL, aesccm1_nonce, aesccm1_key, COSE_ALGO_AESCCM_16_64_128 ); - CU_ASSERT_EQUAL(aesccm1_ciphertext_len, cipherlen); - CU_ASSERT_EQUAL(memcmp(ciphertext, aesccm1_ciphertext, aesccm1_ciphertext_len), 0); + CU_ASSERT_EQUAL(AESCCM1_CIPHERTEXT_LEN, cipherlen); + CU_ASSERT_EQUAL(memcmp(ciphertext, aesccm1_ciphertext, AESCCM1_CIPHERTEXT_LEN), 0); CU_ASSERT_EQUAL( cose_crypto_aead_decrypt( plaintext, &msglen, ciphertext, cipherlen, - aesccm1_aad, aesccm1_aad_len, + aesccm1_aad, AESCCM1_AAD_LEN, aesccm1_nonce, aesccm1_key, COSE_ALGO_AESCCM_16_64_128 ), 0 ); - CU_ASSERT_EQUAL(msglen, aesccm1_plaintext_len); - CU_ASSERT_EQUAL(memcmp(aesccm1_plaintext, plaintext, aesccm1_plaintext_len), 0); + CU_ASSERT_EQUAL(msglen, AESCCM1_PLAINTEXT_LEN); + CU_ASSERT_EQUAL(memcmp(aesccm1_plaintext, plaintext, AESCCM1_PLAINTEXT_LEN), 0); } #endif From 522d91853439946c8524bc481aa20b78778882c5 Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 26 Feb 2020 14:01:09 +0100 Subject: [PATCH 11/23] fixup! tinydtls: Add test integration --- makefiles/tinydtls_config/dtls_config.h | 10 +++++----- tests/crypto.c | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/makefiles/tinydtls_config/dtls_config.h b/makefiles/tinydtls_config/dtls_config.h index b787a93..d6e8e53 100644 --- a/makefiles/tinydtls_config/dtls_config.h +++ b/makefiles/tinydtls_config/dtls_config.h @@ -1,10 +1,10 @@ -// Not that we'd need *that* code, but if neither ECC nro PSK is defined, -// there's empty unions and such (and newer verisons of the library complain -// more explicitly) +/* Not that we'd need *that* code, but if neither ECC nro PSK is defined, + * there's empty unions and such (and newer verisons of the library complain + * more explicitly) */ #define DTLS_PSK -// Similarly, without a SHA algorithm, there's unused variables and such +/* Similarly, without a SHA algorithm, there's unused variables and such */ #define WITH_SHA256 -// Without, we get a #warning that is escalated to an #error by -Werror +/* Without, we get a #warning that is escalated to an #error by -Werror */ #define HAVE_ASSERT_H diff --git a/tests/crypto.c b/tests/crypto.c index 129aeea..6d192c8 100644 --- a/tests/crypto.c +++ b/tests/crypto.c @@ -187,7 +187,7 @@ void test_crypto_aes256(void) #endif #ifdef HAVE_ALGO_AESCCM_16_64_128 -// Values from https://www.rfc-editor.org/rfc/rfc3610.html#section-8 +/* Values from https://www.rfc-editor.org/rfc/rfc3610.html#section-8 */ static const uint8_t aesccm1_key[16] = { 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, }; @@ -209,9 +209,9 @@ static const uint8_t aesccm1_output[39] = { 0xf9, 0x26, 0xe0, }; -// The input and output packets in the RFC's test vectors are shown in -// concatenated form AAD || cleartext and AAD || ciphertext || tag, -// respectively; this plucks them apart. +/* The input and output packets in the RFC's test vectors are shown in + * concatenated form AAD || cleartext and AAD || ciphertext || tag, + * respectively; this plucks them apart. */ static const uint8_t *aesccm1_aad = &aesccm1_input[0]; #define AESCCM1_AAD_LEN 8 From 79870611be5fd0ed299143c028cffd67a5cf6d9a Mon Sep 17 00:00:00 2001 From: chrysn Date: Wed, 26 Feb 2020 14:02:20 +0100 Subject: [PATCH 12/23] fixup! Add glue code for tinyDTLS' AES-CCM-16-64-128 --- src/crypt/tinydtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c index c98a281..34e4bad 100644 --- a/src/crypt/tinydtls.c +++ b/src/crypt/tinydtls.c @@ -25,7 +25,7 @@ int cose_crypto_aead_encrypt_aesccm(uint8_t *c, const uint8_t *k, size_t keysize) { - // Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 + /* Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 */ int ret = dtls_encrypt(msg, msglen, c, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); if (ret >= 0 && (size_t)ret == msglen + COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { *clen = ret; @@ -45,7 +45,7 @@ int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, const uint8_t *k, size_t keysize) { - // Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 + /* Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 */ int ret = dtls_decrypt(c, clen, msg, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); if (ret >= 0 && (size_t)ret == clen - COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { *msglen = ret; From a3ea7be5fa2683d392b965476dc7b303255ccb55 Mon Sep 17 00:00:00 2001 From: chrysn Date: Sun, 8 Nov 2020 04:52:38 +0100 Subject: [PATCH 13/23] tinydtls: Update to tinydtls 0.9 API The compatibility API's behavior changed in https://github.com/eclipse/tinydtls/pull/34; this picks the parameters that work for AES-CCM-16-64-128. --- src/crypt/tinydtls.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c index 34e4bad..2800d85 100644 --- a/src/crypt/tinydtls.c +++ b/src/crypt/tinydtls.c @@ -25,8 +25,8 @@ int cose_crypto_aead_encrypt_aesccm(uint8_t *c, const uint8_t *k, size_t keysize) { - /* Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 */ - int ret = dtls_encrypt(msg, msglen, c, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); + const dtls_ccm_params_t params = { npub, 8, 2 }; + int ret = dtls_encrypt_params(¶ms, msg, msglen, c, (uint8_t*)k, keysize, aad, aadlen); if (ret >= 0 && (size_t)ret == msglen + COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { *clen = ret; return COSE_OK; @@ -45,8 +45,8 @@ int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, const uint8_t *k, size_t keysize) { - /* Casts: discarding const -- see https://github.com/eclipse/tinydtls/issues/25 */ - int ret = dtls_decrypt(c, clen, msg, (uint8_t*)npub, (uint8_t*)k, keysize, aad, aadlen); + const dtls_ccm_params_t params = { npub, 8, 2 }; + int ret = dtls_decrypt_params(¶ms, c, clen, msg, (uint8_t*)k, keysize, aad, aadlen); if (ret >= 0 && (size_t)ret == clen - COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { *msglen = ret; return COSE_OK; From 4c659e74932c9a15d85f0b335b09ba5e90dacdd1 Mon Sep 17 00:00:00 2001 From: Marco vR Date: Mon, 28 Oct 2019 23:01:22 +0100 Subject: [PATCH 14/23] Add support for HKDF (HMAC256) --- Makefile | 5 ++++ include/cose/crypto.h | 42 ++++++++++++++++++++++++++++++ include/cose/crypto/sodium.h | 1 + include/cose_defines.h | 1 + src/cose_crypto.c | 20 +++++++++++++++ src/crypt/sodium.c | 50 ++++++++++++++++++++++++++++++++++++ tests/hkdf.c | 43 +++++++++++++++++++++++++++++++ 7 files changed, 162 insertions(+) create mode 100644 tests/hkdf.c diff --git a/Makefile b/Makefile index 1e95084..aaa4db7 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,8 @@ LDFLAGS += $(LDFLAGS_CRYPTO) lib: $(BIN_DIR)/libcose.so +hkdf-test: $(BIN_DIR)/hkdf-test + prepare: @mkdir -p $(OBJ_DIR) @mkdir -p $(OBJ_DIR)/crypt @@ -89,6 +91,9 @@ $(BIN_DIR)/test: $(OBJS) $(OTESTS) prepare $(BIN_DIR)/libcose.so: $(OBJS) prepare $(CC) $(CFLAGS) $(OBJS) -o $@ -Wl,$(LIB_NANOCBOR) -shared +$(BIN_DIR)/hkdf-test: $(OBJS) $(OBJ_DIR)/tests/hkdf.o prepare + $(CC) $(CFLAGS) $(OBJS) $(OBJ_DIR)/tests/hkdf.o -o $@ -Wl,$(LIB_NANOCBOR) -lsodium + test: $(BIN_DIR)/test LD_LIBRARY_PATH=$(LIB_TINYCBOR_PATH) $< diff --git a/include/cose/crypto.h b/include/cose/crypto.h index 158d024..68e6ca3 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -303,6 +303,48 @@ void cose_crypto_keypair_ecdsa(cose_key_t *key, cose_curve_t curve); * @return Signature size */ size_t cose_crypto_sig_size_ed25519(void); + +/** @brief Derive a key using HKDF (HMAC based key derivation function) + * + * @param[in] salt Salt for key generation. Can be empty + * @param[in] salt_len Length of @p salt + * @param[in] ikm key material + * @param[in] ikm_length Length of @p ikm + * @param[in] info Info for for derived key + * @param[in] info_length Length of @p info + * @param[out] out Output buffer where the key is written to + * @param[in] out_length Length of @p out + * @param[in] alg HKDF algorithm to use + */ +int cose_crypto_hkdf_derive(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_length, + const uint8_t *info, + size_t info_length, + uint8_t *out, + size_t out_length, cose_algo_t alg); + +/** @brief Derive a key using HMAC256 + * + * @param[in] salt Salt for key generation. Can be empty + * @param[in] salt_len Length of @p salt + * @param[in] ikm key material + * @param[in] ikm_length Length of @p ikm + * @param[in] info Info for for derived key + * @param[in] info_length Length of @p info + * @param[out] out Output buffer where the key is written to + * @param[in] out_length Length of @p out + * @param[in] alg HKDF algorithm to use + */ +int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_length, + const uint8_t *info, + size_t info_length, + uint8_t *out, + size_t out_length); /** @} */ #ifdef __cplusplus diff --git a/include/cose/crypto/sodium.h b/include/cose/crypto/sodium.h index 31014b7..1739e1c 100644 --- a/include/cose/crypto/sodium.h +++ b/include/cose/crypto/sodium.h @@ -34,6 +34,7 @@ extern "C" { */ #define HAVE_ALGO_CHACHA20POLY1305 #define HAVE_ALGO_EDDSA +#define HAVE_ALGO_HMAC256 /** @} */ #ifdef __cplusplus diff --git a/include/cose_defines.h b/include/cose_defines.h index 84ff534..a3bf2f5 100644 --- a/include/cose_defines.h +++ b/include/cose_defines.h @@ -160,6 +160,7 @@ typedef enum { COSE_ALGO_A128GCM = 1, /**< AES-GCM mode w/ 128-bit key, 128-bit tag */ COSE_ALGO_A192GCM = 2, /**< AES-GCM mode w/ 192-bit key, 128-bit tag */ COSE_ALGO_A256GCM = 3, /**< AES-GCM mode w/ 256-bit key, 128-bit tag */ + COSE_ALGO_HMAC256 = 5, /**< HMAC w/ SHA-256 */ COSE_ALGO_CHACHA20POLY1305 = 24, /**< IETF ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag */ } cose_algo_t; diff --git a/src/cose_crypto.c b/src/cose_crypto.c index 5f67eb4..4e9dcef 100644 --- a/src/cose_crypto.c +++ b/src/cose_crypto.c @@ -219,3 +219,23 @@ size_t cose_crypto_sig_size(const cose_key_t *key) } return 0; } + +int cose_crypto_hkdf_derive(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_length, + const uint8_t *info, + size_t info_length, + uint8_t *out, + size_t out_length, cose_algo_t alg) { + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch(alg) { +#ifdef HAVE_ALGO_HMAC256 + case COSE_ALGO_HMAC256: + return cose_crypto_hkdf_derive_sha256(salt, salt_len, ikm, + ikm_length, info, info_length, out, out_length); +#endif + default: + return COSE_ERR_NOTIMPLEMENTED; + } +} diff --git a/src/crypt/sodium.c b/src/crypt/sodium.c index 92303d1..8c91a4e 100644 --- a/src/crypt/sodium.c +++ b/src/crypt/sodium.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -110,4 +111,53 @@ size_t cose_crypto_sig_size_ed25519(void) { return crypto_sign_BYTES; } + +int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_length, + const uint8_t *info, + size_t info_length, + uint8_t *out, + size_t out_length) +{ + uint8_t prk[crypto_auth_hmacsha256_KEYBYTES]; + + if (salt_len == crypto_auth_hmacsha256_KEYBYTES) { + crypto_auth_hmacsha256(prk, ikm, ikm_length, salt); + } else if (salt_len == 0) { + uint8_t padding[crypto_auth_hmacsha256_KEYBYTES]; + memset(padding, 0, crypto_auth_hmacsha256_KEYBYTES); + crypto_auth_hmacsha256(prk, ikm, ikm_length, padding); + } else { + return COSE_ERR_INVALID_PARAM; + } + + uint8_t slice[crypto_auth_hmacsha256_BYTES]; + size_t slice_len = crypto_auth_hmacsha256_BYTES; + uint8_t counter[1] = {0x01}; + crypto_auth_hmacsha256_state state; + size_t rounds = out_length / crypto_auth_hmacsha256_BYTES; + if (out_length % crypto_auth_hmacsha256_BYTES > 0) { + rounds++; + } + for (size_t i = 0; i < rounds; ++i) { + size_t offset = i * crypto_auth_hmacsha256_BYTES; + *counter = i + 1; + crypto_auth_hmacsha256_init(&state, prk, crypto_auth_hmacsha256_KEYBYTES); + if (i > 0) { + crypto_auth_hmacsha256_update(&state, slice, slice_len); + } + crypto_auth_hmacsha256_update(&state, info, info_length); + crypto_auth_hmacsha256_update(&state, counter, 1); + crypto_auth_hmacsha256_final(&state, slice); + if (i + 1 == rounds) { + slice_len = out_length - offset; + } + memcpy(out + offset, slice, slice_len); + } + + return COSE_OK; +} + #endif /* CRYPTO_SODIUM_INCLUDE_ED25519 */ diff --git a/tests/hkdf.c b/tests/hkdf.c new file mode 100644 index 0000000..165416e --- /dev/null +++ b/tests/hkdf.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include + +int test() { + uint8_t out[100]; + uint8_t h_salt[] = "1234567890abcdefghijklmnopqrstuv"; + uint8_t ikm[] = "abcdefghijklmnopqrst"; + uint8_t info[] = "HKDF TEST"; + size_t salt_len = 32; + size_t ikm_len = 20; + size_t info_len = 9; + + uint8_t expected[] = "\x20\xb5\x23\xe5\x51\x29\xf1\xdb\x54\xfe\xa4\xbd\x60\x84\xf2\x74\xb5\xc9\xcd\x91\xf1\xde\xc7\x3b\x37\xa8\xd4\x8d\x5d\xeb\xc5\xf3\x06\xa1\x10\x90\x05\x88\x5b\x38\x40\x2f\x6d\x86\x49\xd1\x0e\x44\x55\x76\xfb\xb9\x3d\x1d\x42\xa9\x06\x96\xe9\x40\x7f\xd8\x79\xe4\xad\x6e\xae\xc8\x81\x93\x41\xa7\x06\x35\xf4\xd0\x53\x62\xb5\xce\x18\x3b\x98\xc5\xf6\x92\x02\xb2\xe8\x7e\xc1\xfd\x45\xf9\x48\x1c\x39\x0a\xa7\x4f"; + uint8_t expected_nosalt[] = "\x4e\xc9\x5f\x9d\xa4\x02\x4d\x42\xe9\xd8\xce\x26\x1e\x9d\xc1\xaa\xd9\x35\x04\xbb\x02\xe3\xf5\x84\x31\x45\x78\x60\x47\xf3\xc4\x22\x23\x6e\x60\x5c\x92\xf6\xaa\x44\x2f\xf3\xa2\x4e\x26\x3b\xf4\xa9\x57\x89\xa7\xe9\x51\x75\xb1\x5d\xa3\x6f\x31\xc5\xc2\xf8\x93\xfd\x80\x65\x54\x7b\xde\xa5\x04\xe9\x33\x57\x0f\x33\x13\x96\x70\x46\x2d\xdf\x57\xb4\xe7\x3e\x6c\x06\x36\x79\xa3\x54\xc6\x89\x0d\x51\x2c\x5e\x3b\x3b"; + + size_t out_len = 10; + cose_crypto_hkdf_derive(h_salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + assert(memcmp(out, expected, out_len) == 0); + cose_crypto_hkdf_derive(h_salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + assert(memcmp(out, expected_nosalt, out_len) == 0); + + out_len = 64; + cose_crypto_hkdf_derive(h_salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + assert(memcmp(out, expected, out_len) == 0); + cose_crypto_hkdf_derive(h_salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + assert(memcmp(out, expected_nosalt, out_len) == 0); + + out_len = 100; + cose_crypto_hkdf_derive(h_salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + assert(memcmp(out, expected, out_len) == 0); + cose_crypto_hkdf_derive(h_salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + assert(memcmp(out, expected_nosalt, out_len) == 0); + + return 0; +} + +int main() { + test(); + printf("Success\n"); +} From b89d9052fd3a6ef03f1de0800716265678ebebbe Mon Sep 17 00:00:00 2001 From: Marco vR Date: Thu, 31 Oct 2019 23:27:06 +0100 Subject: [PATCH 15/23] Fix HKDF with short salt --- src/crypt/sodium.c | 3 ++- tests/hkdf.c | 24 +++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/crypt/sodium.c b/src/crypt/sodium.c index 8c91a4e..403c0ce 100644 --- a/src/crypt/sodium.c +++ b/src/crypt/sodium.c @@ -125,9 +125,10 @@ int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, if (salt_len == crypto_auth_hmacsha256_KEYBYTES) { crypto_auth_hmacsha256(prk, ikm, ikm_length, salt); - } else if (salt_len == 0) { + } else if (salt_len < crypto_auth_hmacsha256_KEYBYTES) { uint8_t padding[crypto_auth_hmacsha256_KEYBYTES]; memset(padding, 0, crypto_auth_hmacsha256_KEYBYTES); + memcpy(padding, salt, salt_len); crypto_auth_hmacsha256(prk, ikm, ikm_length, padding); } else { return COSE_ERR_INVALID_PARAM; diff --git a/tests/hkdf.c b/tests/hkdf.c index 165416e..0140972 100644 --- a/tests/hkdf.c +++ b/tests/hkdf.c @@ -6,7 +6,7 @@ int test() { uint8_t out[100]; - uint8_t h_salt[] = "1234567890abcdefghijklmnopqrstuv"; + uint8_t salt[] = "1234567890abcdefghijklmnopqrstuv"; uint8_t ikm[] = "abcdefghijklmnopqrst"; uint8_t info[] = "HKDF TEST"; size_t salt_len = 32; @@ -17,23 +17,33 @@ int test() { uint8_t expected_nosalt[] = "\x4e\xc9\x5f\x9d\xa4\x02\x4d\x42\xe9\xd8\xce\x26\x1e\x9d\xc1\xaa\xd9\x35\x04\xbb\x02\xe3\xf5\x84\x31\x45\x78\x60\x47\xf3\xc4\x22\x23\x6e\x60\x5c\x92\xf6\xaa\x44\x2f\xf3\xa2\x4e\x26\x3b\xf4\xa9\x57\x89\xa7\xe9\x51\x75\xb1\x5d\xa3\x6f\x31\xc5\xc2\xf8\x93\xfd\x80\x65\x54\x7b\xde\xa5\x04\xe9\x33\x57\x0f\x33\x13\x96\x70\x46\x2d\xdf\x57\xb4\xe7\x3e\x6c\x06\x36\x79\xa3\x54\xc6\x89\x0d\x51\x2c\x5e\x3b\x3b"; size_t out_len = 10; - cose_crypto_hkdf_derive(h_salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + cose_crypto_hkdf_derive(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); assert(memcmp(out, expected, out_len) == 0); - cose_crypto_hkdf_derive(h_salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + cose_crypto_hkdf_derive(salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); assert(memcmp(out, expected_nosalt, out_len) == 0); out_len = 64; - cose_crypto_hkdf_derive(h_salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + cose_crypto_hkdf_derive(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); assert(memcmp(out, expected, out_len) == 0); - cose_crypto_hkdf_derive(h_salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + cose_crypto_hkdf_derive(salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); assert(memcmp(out, expected_nosalt, out_len) == 0); out_len = 100; - cose_crypto_hkdf_derive(h_salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + cose_crypto_hkdf_derive(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); assert(memcmp(out, expected, out_len) == 0); - cose_crypto_hkdf_derive(h_salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); + cose_crypto_hkdf_derive(salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); assert(memcmp(out, expected_nosalt, out_len) == 0); + + uint8_t master_secret[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; + uint8_t master_salt[8] = {0x9e, 0x7c, 0xa9, 0x22, 0x23, 0x78, 0x63, 0x40}; + uint8_t skey_info[9] = {0x85, 0x40, 0xf6, 0x0a, 0x63, 0x4b, 0x65, 0x79, 0x10}; + uint8_t expected_key_S[16] = {0xf0, 0x91, 0x0e, 0xd7, 0x29, 0x5e, 0x6a, 0xd4, + 0xb5, 0x4f, 0xc7, 0x93, 0x15, 0x43, 0x02, 0xff}; + cose_crypto_hkdf_derive(master_salt, 8, master_secret, 16, skey_info, 9, out, 16, COSE_ALGO_HMAC256); + assert(memcmp(out, expected_key_S, 16) == 0); + return 0; } From 3ab3aeb0033e8c5041ba6eb08a13c781081834e0 Mon Sep 17 00:00:00 2001 From: chrysn Date: Sat, 19 Dec 2020 16:39:18 +0100 Subject: [PATCH 16/23] HKDF: Port tests into generic test framework --- Makefile | 5 ----- tests/hkdf.c | 40 +++++++++++++++++++++++++--------------- tests/test.c | 8 ++++++++ 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index aaa4db7..1e95084 100644 --- a/Makefile +++ b/Makefile @@ -69,8 +69,6 @@ LDFLAGS += $(LDFLAGS_CRYPTO) lib: $(BIN_DIR)/libcose.so -hkdf-test: $(BIN_DIR)/hkdf-test - prepare: @mkdir -p $(OBJ_DIR) @mkdir -p $(OBJ_DIR)/crypt @@ -91,9 +89,6 @@ $(BIN_DIR)/test: $(OBJS) $(OTESTS) prepare $(BIN_DIR)/libcose.so: $(OBJS) prepare $(CC) $(CFLAGS) $(OBJS) -o $@ -Wl,$(LIB_NANOCBOR) -shared -$(BIN_DIR)/hkdf-test: $(OBJS) $(OBJ_DIR)/tests/hkdf.o prepare - $(CC) $(CFLAGS) $(OBJS) $(OBJ_DIR)/tests/hkdf.o -o $@ -Wl,$(LIB_NANOCBOR) -lsodium - test: $(BIN_DIR)/test LD_LIBRARY_PATH=$(LIB_TINYCBOR_PATH) $< diff --git a/tests/hkdf.c b/tests/hkdf.c index 0140972..6871956 100644 --- a/tests/hkdf.c +++ b/tests/hkdf.c @@ -1,10 +1,13 @@ -#include +#include + #include #include #include #include -int test() { +#include "CUnit/CUnit.h" + +void test_hkdf_vectors_hmac256(void) { uint8_t out[100]; uint8_t salt[] = "1234567890abcdefghijklmnopqrstuv"; uint8_t ikm[] = "abcdefghijklmnopqrst"; @@ -18,36 +21,43 @@ int test() { size_t out_len = 10; cose_crypto_hkdf_derive(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); - assert(memcmp(out, expected, out_len) == 0); + CU_ASSERT_EQUAL(memcmp(out, expected, out_len), 0); cose_crypto_hkdf_derive(salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); - assert(memcmp(out, expected_nosalt, out_len) == 0); + CU_ASSERT_EQUAL(memcmp(out, expected_nosalt, out_len), 0); out_len = 64; cose_crypto_hkdf_derive(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); - assert(memcmp(out, expected, out_len) == 0); + CU_ASSERT_EQUAL(memcmp(out, expected, out_len), 0); cose_crypto_hkdf_derive(salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); - assert(memcmp(out, expected_nosalt, out_len) == 0); + CU_ASSERT_EQUAL(memcmp(out, expected_nosalt, out_len), 0); out_len = 100; cose_crypto_hkdf_derive(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); - assert(memcmp(out, expected, out_len) == 0); + CU_ASSERT_EQUAL(memcmp(out, expected, out_len), 0); cose_crypto_hkdf_derive(salt, 0, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256); - assert(memcmp(out, expected_nosalt, out_len) == 0); + CU_ASSERT_EQUAL(memcmp(out, expected_nosalt, out_len), 0); uint8_t master_secret[16] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}; uint8_t master_salt[8] = {0x9e, 0x7c, 0xa9, 0x22, 0x23, 0x78, 0x63, 0x40}; + /* An example key info map for RFC8613 */ uint8_t skey_info[9] = {0x85, 0x40, 0xf6, 0x0a, 0x63, 0x4b, 0x65, 0x79, 0x10}; uint8_t expected_key_S[16] = {0xf0, 0x91, 0x0e, 0xd7, 0x29, 0x5e, 0x6a, 0xd4, 0xb5, 0x4f, 0xc7, 0x93, 0x15, 0x43, 0x02, 0xff}; cose_crypto_hkdf_derive(master_salt, 8, master_secret, 16, skey_info, 9, out, 16, COSE_ALGO_HMAC256); - assert(memcmp(out, expected_key_S, 16) == 0); - - return 0; + CU_ASSERT_EQUAL(memcmp(out, expected_key_S, 16), 0); } -int main() { - test(); - printf("Success\n"); -} +const test_t tests_hkdf[] = { +#ifdef HAVE_ALGO_HMAC256 + { + .f = test_hkdf_vectors_hmac256, + .n = "HKDF test vectors for HMAC 256/256", + }, +#endif + { + .f = NULL, + .n = NULL, + }, +}; diff --git a/tests/test.c b/tests/test.c index 407b18e..2429e4e 100644 --- a/tests/test.c +++ b/tests/test.c @@ -23,6 +23,7 @@ extern test_t tests_crypto[]; extern test_t tests_sign[]; extern test_t tests_suit[]; extern test_t tests_encrypt[]; +extern test_t tests_hkdf[]; int getrandom(void *arg, unsigned char *buf, size_t bytes) { @@ -86,6 +87,13 @@ int main() } add_tests(pSuite, tests_encrypt); + pSuite = CU_add_suite("Suite_hkdf", NULL, NULL); + if (NULL == pSuite) { + CU_cleanup_registry(); + return CU_get_error(); + } + add_tests(pSuite, tests_hkdf); + srand(time(NULL)); cose_crypt_set_rng(getrandom, NULL); From c162a5f1e22ee27e1ddea7fcc0c59cdc11106881 Mon Sep 17 00:00:00 2001 From: chrysn Date: Sat, 19 Dec 2020 16:51:05 +0100 Subject: [PATCH 17/23] HKDF: Documentation fixes --- include/cose/crypto.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/cose/crypto.h b/include/cose/crypto.h index 68e6ca3..ab00bcf 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -304,6 +304,14 @@ void cose_crypto_keypair_ecdsa(cose_key_t *key, cose_curve_t curve); */ size_t cose_crypto_sig_size_ed25519(void); +/** @} */ + +/** + * @name HKDF related functions + * + * @{ + */ + /** @brief Derive a key using HKDF (HMAC based key derivation function) * * @param[in] salt Salt for key generation. Can be empty @@ -323,7 +331,8 @@ int cose_crypto_hkdf_derive(const uint8_t *salt, const uint8_t *info, size_t info_length, uint8_t *out, - size_t out_length, cose_algo_t alg); + size_t out_length, + cose_algo_t alg); /** @brief Derive a key using HMAC256 * @@ -335,7 +344,6 @@ int cose_crypto_hkdf_derive(const uint8_t *salt, * @param[in] info_length Length of @p info * @param[out] out Output buffer where the key is written to * @param[in] out_length Length of @p out - * @param[in] alg HKDF algorithm to use */ int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, size_t salt_len, From 20e0739be095d667301ee31ad1147d12b044a1d0 Mon Sep 17 00:00:00 2001 From: chrysn Date: Sat, 19 Dec 2020 16:53:12 +0100 Subject: [PATCH 18/23] HKDF: Move code to place consisten twith other crypto parts --- src/cose_crypto.c | 20 -------------------- src/cose_hkdf.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 src/cose_hkdf.c diff --git a/src/cose_crypto.c b/src/cose_crypto.c index 4e9dcef..5f67eb4 100644 --- a/src/cose_crypto.c +++ b/src/cose_crypto.c @@ -219,23 +219,3 @@ size_t cose_crypto_sig_size(const cose_key_t *key) } return 0; } - -int cose_crypto_hkdf_derive(const uint8_t *salt, - size_t salt_len, - const uint8_t *ikm, - size_t ikm_length, - const uint8_t *info, - size_t info_length, - uint8_t *out, - size_t out_length, cose_algo_t alg) { - /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ - switch(alg) { -#ifdef HAVE_ALGO_HMAC256 - case COSE_ALGO_HMAC256: - return cose_crypto_hkdf_derive_sha256(salt, salt_len, ikm, - ikm_length, info, info_length, out, out_length); -#endif - default: - return COSE_ERR_NOTIMPLEMENTED; - } -} diff --git a/src/cose_hkdf.c b/src/cose_hkdf.c new file mode 100644 index 0000000..7619db0 --- /dev/null +++ b/src/cose_hkdf.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 Freie Universitat Berlin + * Copyright (C) 2018 Inria + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#include "cose/crypto.h" + +int cose_crypto_hkdf_derive(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_length, + const uint8_t *info, + size_t info_length, + uint8_t *out, + size_t out_length, cose_algo_t alg) { + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch(alg) { +#ifdef HAVE_ALGO_HMAC256 + case COSE_ALGO_HMAC256: + return cose_crypto_hkdf_derive_sha256(salt, salt_len, ikm, + ikm_length, info, info_length, out, out_length); +#endif + default: + return COSE_ERR_NOTIMPLEMENTED; + } +} From 63d9a1b9a7e23a81ea13b22a0f65e8248605ca02 Mon Sep 17 00:00:00 2001 From: chrysn Date: Sat, 19 Dec 2020 16:59:18 +0100 Subject: [PATCH 19/23] HKDF: Add cose_crypto_is_hkdf function in analogy to cose_crypto_is_aead --- include/cose/crypto.h | 7 +++++++ src/cose_hkdf.c | 13 +++++++++++++ tests/hkdf.c | 17 +++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/include/cose/crypto.h b/include/cose/crypto.h index ab00bcf..0f28684 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -312,6 +312,13 @@ size_t cose_crypto_sig_size_ed25519(void); * @{ */ +/** @brief Decide whether a given algorithm is known and an HKDF algorithm + * + * @param[in] alg The algorithm to be checked + * @return true iff @p alg can be used with @ref cose_crypto_hkdf_derive + */ +bool cose_crypto_is_hkdf(cose_algo_t alg); + /** @brief Derive a key using HKDF (HMAC based key derivation function) * * @param[in] salt Salt for key generation. Can be empty diff --git a/src/cose_hkdf.c b/src/cose_hkdf.c index 7619db0..aaa9936 100644 --- a/src/cose_hkdf.c +++ b/src/cose_hkdf.c @@ -9,6 +9,19 @@ #include "cose/crypto.h" +bool cose_crypto_is_hkdf(cose_algo_t alg) +{ + /* NOLINTNEXTLINE(hicpp-multiway-paths-covered) */ + switch(alg) { +#ifdef HAVE_ALGO_HMAC256 + case COSE_ALGO_HMAC256: + return true; +#endif + default: + return false; + } +} + int cose_crypto_hkdf_derive(const uint8_t *salt, size_t salt_len, const uint8_t *ikm, diff --git a/tests/hkdf.c b/tests/hkdf.c index 6871956..8708bd7 100644 --- a/tests/hkdf.c +++ b/tests/hkdf.c @@ -49,6 +49,19 @@ void test_hkdf_vectors_hmac256(void) { CU_ASSERT_EQUAL(memcmp(out, expected_key_S, 16), 0); } +void test_is_hkdf(void) { + CU_ASSERT_EQUAL(cose_crypto_is_hkdf(COSE_ALGO_NONE), false); + CU_ASSERT_EQUAL(cose_crypto_is_hkdf(COSE_ALGO_CHACHA20POLY1305), false); + bool have_algo_hmac256 = +#ifdef HAVE_ALGO_HMAC256 + true +#else + false +#endif + ; + CU_ASSERT_EQUAL(cose_crypto_is_hkdf(COSE_ALGO_HMAC256), have_algo_hmac256); +} + const test_t tests_hkdf[] = { #ifdef HAVE_ALGO_HMAC256 { @@ -56,6 +69,10 @@ const test_t tests_hkdf[] = { .n = "HKDF test vectors for HMAC 256/256", }, #endif + { + .f = test_is_hkdf, + .n = "cose_crypto_is_hkdf", + }, { .f = NULL, .n = NULL, From 2fa5daf06f5b90aa5d4e63077bff858b6db93602 Mon Sep 17 00:00:00 2001 From: chrysn Date: Mon, 21 Dec 2020 11:35:52 +0100 Subject: [PATCH 20/23] HKDF: Add void casts to pass builds without KDF backend --- src/cose_hkdf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cose_hkdf.c b/src/cose_hkdf.c index aaa9936..cc5cb56 100644 --- a/src/cose_hkdf.c +++ b/src/cose_hkdf.c @@ -18,6 +18,7 @@ bool cose_crypto_is_hkdf(cose_algo_t alg) return true; #endif default: + (void)alg; return false; } } @@ -38,6 +39,15 @@ int cose_crypto_hkdf_derive(const uint8_t *salt, ikm_length, info, info_length, out, out_length); #endif default: + (void)salt; + (void)salt_len; + (void)ikm; + (void)ikm_length; + (void)info; + (void)info_length; + (void)out; + (void)out_length; + (void)alg; return COSE_ERR_NOTIMPLEMENTED; } } From 5162ec797b62c945b224a088bbcca30bd2fa2ed2 Mon Sep 17 00:00:00 2001 From: chrysn Date: Mon, 21 Dec 2020 15:01:07 +0100 Subject: [PATCH 21/23] HKDF: Fix selectors ifdefs, add selector There is no need for a selector on this branch, but one is coming up. --- include/cose/crypto/selectors.h | 9 +++++++++ src/crypt/sodium.c | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/cose/crypto/selectors.h b/include/cose/crypto/selectors.h index 960cc42..237fe22 100644 --- a/include/cose/crypto/selectors.h +++ b/include/cose/crypto/selectors.h @@ -48,6 +48,15 @@ #define CRYPTO_HACL_INCLUDE_CHACHAPOLY #endif /** @} */ + +/** + * + * @name HKDF SHA256 selector + */ +#ifdef CRYPTO_SODIUM +#define CRYPTO_SODIUM_INCLUDE_HKDFSHA256 +#endif + #endif /* COSE_CRYPTO_SELECTORS_H */ /** @} */ diff --git a/src/crypt/sodium.c b/src/crypt/sodium.c index 403c0ce..e31e66c 100644 --- a/src/crypt/sodium.c +++ b/src/crypt/sodium.c @@ -111,7 +111,9 @@ size_t cose_crypto_sig_size_ed25519(void) { return crypto_sign_BYTES; } +#endif /* CRYPTO_SODIUM_INCLUDE_ED25519 */ +#ifdef CRYPTO_SODIUM_INCLUDE_HKDFSHA256 int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, size_t salt_len, const uint8_t *ikm, @@ -160,5 +162,4 @@ int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, return COSE_OK; } - -#endif /* CRYPTO_SODIUM_INCLUDE_ED25519 */ +#endif /* CRYPTO_SODIUM_INCLUDE_HKDFSHA256 */ From 3cc3819bc2174db8161c47adb565252e61b6c89e Mon Sep 17 00:00:00 2001 From: chrysn Date: Mon, 21 Dec 2020 15:24:39 +0100 Subject: [PATCH 22/23] Implement HKDF SHA256 based on tinydtls --- include/cose/crypto/selectors.h | 2 ++ include/cose/crypto/tinydtls.h | 2 ++ src/crypt/tinydtls.c | 55 +++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/include/cose/crypto/selectors.h b/include/cose/crypto/selectors.h index 237fe22..b4b6c56 100644 --- a/include/cose/crypto/selectors.h +++ b/include/cose/crypto/selectors.h @@ -55,6 +55,8 @@ */ #ifdef CRYPTO_SODIUM #define CRYPTO_SODIUM_INCLUDE_HKDFSHA256 +#elif defined(CRYPTO_TINYDTLS) +#define CRYPTO_TINYDTLS_INCLUDE_HKDFSHA256 #endif #endif /* COSE_CRYPTO_SELECTORS_H */ diff --git a/include/cose/crypto/tinydtls.h b/include/cose/crypto/tinydtls.h index 92da23a..1920c19 100644 --- a/include/cose/crypto/tinydtls.h +++ b/include/cose/crypto/tinydtls.h @@ -34,6 +34,8 @@ extern "C" { * @{ */ #define HAVE_ALGO_AESCCM_16_64_128 /**< AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce */ +#define HAVE_ALGO_HMAC256 + /** @} */ #ifdef __cplusplus diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c index 2800d85..a58adc4 100644 --- a/src/crypt/tinydtls.c +++ b/src/crypt/tinydtls.c @@ -13,7 +13,10 @@ #include "cose.h" #include "cose/crypto.h" +#include "cose/crypto/selectors.h" + #include /* tinydtls', that is */ +#include /* tinydtls', that is */ int cose_crypto_aead_encrypt_aesccm(uint8_t *c, size_t *clen, @@ -54,3 +57,55 @@ int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, return COSE_ERR_CRYPTO; } } + +#ifdef CRYPTO_TINYDTLS_INCLUDE_HKDFSHA256 +int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, + size_t salt_len, + const uint8_t *ikm, + size_t ikm_length, + const uint8_t *info, + size_t info_length, + uint8_t *out, + size_t out_length) +{ +#define SHA256_OUTPUT_BYTES 32 + uint8_t prk[SHA256_OUTPUT_BYTES]; + + /* Extract step*/ + { + dtls_hmac_context_t hmac_ctx; + + dtls_hmac_init(&hmac_ctx, salt, salt_len); + dtls_hmac_update(&hmac_ctx, ikm, ikm_length); + dtls_hmac_finalize(&hmac_ctx, prk); + } + + /* Expand step */ + + uint8_t slice[SHA256_OUTPUT_BYTES]; + size_t slice_len = SHA256_OUTPUT_BYTES; + uint8_t counter[1] = {0x01}; + dtls_hmac_context_t state; + size_t rounds = out_length / SHA256_OUTPUT_BYTES; + if (out_length % SHA256_OUTPUT_BYTES > 0) { + rounds++; + } + for (size_t i = 0; i < rounds; ++i) { + size_t offset = i * SHA256_OUTPUT_BYTES; + *counter = i + 1; + dtls_hmac_init(&state, prk, SHA256_OUTPUT_BYTES); + if (i > 0) { + dtls_hmac_update(&state, slice, slice_len); + } + dtls_hmac_update(&state, info, info_length); + dtls_hmac_update(&state, counter, 1); + dtls_hmac_finalize(&state, slice); + if (i + 1 == rounds) { + slice_len = out_length - offset; + } + memcpy(out + offset, slice, slice_len); + } + + return COSE_OK; +} +#endif /* CRYPTO_TINYDTLS_INCLUDE_HKDFSHA256 */ From f4eb5b54c48a2985512bf9e83587bf7b2ec90fb4 Mon Sep 17 00:00:00 2001 From: chrysn Date: Mon, 21 Dec 2020 15:26:34 +0100 Subject: [PATCH 23/23] HKDF: Simplify rounds calculation --- src/crypt/sodium.c | 5 +---- src/crypt/tinydtls.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/crypt/sodium.c b/src/crypt/sodium.c index e31e66c..168d739 100644 --- a/src/crypt/sodium.c +++ b/src/crypt/sodium.c @@ -140,10 +140,7 @@ int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, size_t slice_len = crypto_auth_hmacsha256_BYTES; uint8_t counter[1] = {0x01}; crypto_auth_hmacsha256_state state; - size_t rounds = out_length / crypto_auth_hmacsha256_BYTES; - if (out_length % crypto_auth_hmacsha256_BYTES > 0) { - rounds++; - } + size_t rounds = (out_length + crypto_auth_hmacsha256_BYTES - 1) / crypto_auth_hmacsha256_BYTES; for (size_t i = 0; i < rounds; ++i) { size_t offset = i * crypto_auth_hmacsha256_BYTES; *counter = i + 1; diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c index a58adc4..bd18b57 100644 --- a/src/crypt/tinydtls.c +++ b/src/crypt/tinydtls.c @@ -86,10 +86,7 @@ int cose_crypto_hkdf_derive_sha256(const uint8_t *salt, size_t slice_len = SHA256_OUTPUT_BYTES; uint8_t counter[1] = {0x01}; dtls_hmac_context_t state; - size_t rounds = out_length / SHA256_OUTPUT_BYTES; - if (out_length % SHA256_OUTPUT_BYTES > 0) { - rounds++; - } + size_t rounds = (out_length + SHA256_OUTPUT_BYTES - 1) / SHA256_OUTPUT_BYTES; for (size_t i = 0; i < rounds; ++i) { size_t offset = i * SHA256_OUTPUT_BYTES; *counter = i + 1;