Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions include/cose/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,63 @@ void cose_crypto_keypair_ecdsa(cose_key_t *key, cose_curve_t curve);
* @return Signature size
*/
size_t cose_crypto_sig_size_ed25519(void);

/** @} */

/**
* @name HKDF related functions
*
* @{
*/

/** @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
* @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
*/
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
Expand Down
9 changes: 9 additions & 0 deletions include/cose/crypto/selectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

/** @} */
1 change: 1 addition & 0 deletions include/cose/crypto/sodium.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extern "C" {
*/
#define HAVE_ALGO_CHACHA20POLY1305
#define HAVE_ALGO_EDDSA
#define HAVE_ALGO_HMAC256
/** @} */

#ifdef __cplusplus
Expand Down
1 change: 1 addition & 0 deletions include/cose_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
53 changes: 53 additions & 0 deletions src/cose_hkdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 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"

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:
(void)alg;
return false;
}
}

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:
(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;
}
}
52 changes: 52 additions & 0 deletions src/crypt/sodium.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <sodium/crypto_aead_chacha20poly1305.h>
#include <sodium/crypto_sign.h>
#include <sodium/randombytes.h>
#include <sodium/crypto_auth_hmacsha256.h>
#include <stdint.h>
#include <stdlib.h>

Expand Down Expand Up @@ -111,3 +112,54 @@ 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,
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 < 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;
}

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_HKDFSHA256 */
80 changes: 80 additions & 0 deletions tests/hkdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include <cose/test.h>

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <cose/crypto.h>

#include "CUnit/CUnit.h"

void test_hkdf_vectors_hmac256(void) {
uint8_t out[100];
uint8_t 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(salt, salt_len, ikm, ikm_len, info, info_len, out, out_len, COSE_ALGO_HMAC256);
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);
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);
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);
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);
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);
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);
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
{
.f = test_hkdf_vectors_hmac256,
.n = "HKDF test vectors for HMAC 256/256",
},
#endif
{
.f = test_is_hkdf,
.n = "cose_crypto_is_hkdf",
},
{
.f = NULL,
.n = NULL,
},
};
8 changes: 8 additions & 0 deletions tests/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);

Expand Down