Skip to content

Commit

Permalink
Merge pull request #120 from fjmolinas/pr_hkdf
Browse files Browse the repository at this point in the history
cose: add HKDF (HMAC256)
  • Loading branch information
bergzand authored Feb 24, 2022
2 parents c55f97a + bc04bb7 commit 195259f
Show file tree
Hide file tree
Showing 10 changed files with 420 additions and 0 deletions.
62 changes: 62 additions & 0 deletions include/cose/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,68 @@ 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 alg the algorithm to be checked
*
* @return true if alg can be used with 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 salt salt for key generation. Can be empty
* @param salt_len salt length
* @param ikm input key material
* @param ikm_length input key material length
* @param info info for derived key
* @param info_length info for derived key length
* @param[out] out output buffer for derived key
* @param out_length dervied key length
* @param alg HKDF algorithm to use
*
* @return COSE_OK on successful key derivations
* @return COSE_ERR_NOTIMPLEMENTED if the alg is unsupported
* @return COSE_ERR_INVALID_PARAM on invalid salt length
* @return COSE_ERR_CRYPTO otherwise
*/
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 SHA256 HKDF (HMAC based key derivation function)
*
* @param salt salt for key generation. Can be empty
* @param salt_len salt length
* @param ikm input key material
* @param ikm_length input key material length
* @param info info for derived key
* @param info_length info for derived key length
* @param[out] out output buffer for derived key
* @param out_length dervied key length
*
* @return COSE_OK on successful key derivations
* @return COSE_ERR_INVALID_PARAM on invalid salt length
* @return COSE_ERR_CRYPTO otherwise
*/
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
13 changes: 13 additions & 0 deletions include/cose/crypto/selectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@
#define CRYPTO_HACL_INCLUDE_CHACHAPOLY
#endif
/** @} */

/**
*
* @name HKDF SHA256 selector
*/
#if defined(CRYPTO_SODIUM)
#define CRYPTO_SODIUM_INCLUDE_HKDFSHA256
#elif defined(CRYPTO_TINYCRYPT)
#if __has_include (<tinycrypt/hkdf.h>)
#define CRYPTO_TINYCRYPT_INCLUDE_HKDFSHA256
#endif
#endif

#endif /* COSE_CRYPTO_SELECTORS_H */

#if defined(HAVE_ALGO_AES128GCM) || \
Expand Down
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
3 changes: 3 additions & 0 deletions include/cose/crypto/tinycrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ extern "C" {
#define HAVE_CURVE_P256 /**< EC NIST p256 curve support */

#define HAVE_ALGO_AESCCM
#if __has_include (<tinycrypt/hkdf.h>)
#define HAVE_ALGO_HMAC256
#endif

#define HAVE_ALGO_AESCCM_16_64_128 /**< AES CCM mode support with 16 bit length, 64 bit tag 128 bit key */
#define HAVE_ALGO_AESCCM_16_128_128 /**< AES CCM mode support with 16 bit length, 128 bit tag 128 bit key */
Expand Down
1 change: 1 addition & 0 deletions include/cose_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,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_AESCCM_16_64_128 = 10, /**< AES-CCM w/ 128-bit key, 64-bit tag and 13-byte nonce */
COSE_ALGO_AESCCM_16_64_256 = 11, /**< AES-CCM w/ 256-bit key, 64-bit tag and 13-byte nonce */
Expand Down
51 changes: 51 additions & 0 deletions src/cose_hkdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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;
}
}
55 changes: 55 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 @@ -92,3 +93,57 @@ 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);
if (salt) {
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);
}
if (info) {
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 */
26 changes: 26 additions & 0 deletions src/crypt/tinycrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
#include <tinycrypt/ecc_dh.h>
#include <tinycrypt/ecc_dsa.h>
#include <tinycrypt/sha256.h>
#if __has_include (<tinycrypt/hkdf.h>)
#include <tinycrypt/hkdf.h>
#endif

extern cose_crypt_rng cose_crypt_get_random;
extern void *cose_crypt_rng_arg;
Expand Down Expand Up @@ -188,3 +191,26 @@ int cose_crypto_verify_ecdsa(const cose_key_t *key, const uint8_t *sign, size_t
int res = uECC_verify(pubkey, hash, sizeof(hash), (uint8_t*)sign, uECC_secp256r1());
return res ? COSE_OK : COSE_ERR_CRYPTO;
}

#ifdef CRYPTO_TINYCRYPT_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[TC_SHA256_DIGEST_SIZE];

int ret = tc_hkdf_extract(ikm, ikm_length, salt, salt_len, prk);

if (ret != TC_CRYPTO_SUCCESS) {
return COSE_ERR_CRYPTO;
}

ret = tc_hkdf_expand(prk, info, info_length, out_length, out);

if (ret != TC_CRYPTO_SUCCESS) {
return COSE_ERR_CRYPTO;
}
return COSE_OK;
}
#endif /* CRYPTO_TINYCRYPT_INCLUDE_HKDFSHA256 */
Loading

0 comments on commit 195259f

Please sign in to comment.