hkdf.c (1477B)
1 #include "hkdf.h" 2 3 #include <assert.h> 4 5 size_t 6 hkdf_digest_size(struct hmac_hash const *hash, size_t rounds) 7 { 8 return hash->digest_size * rounds; 9 } 10 11 size_t 12 hkdf_max_digest_size(struct hmac_hash const *hash) 13 { 14 return hkdf_digest_size(hash, HKDF_MAX_ROUNDS); 15 } 16 17 void 18 hkdf(struct hmac_hash const *hash, void *restrict hash_ctx, 19 void const *restrict key, size_t key_len, 20 void const *salt, size_t salt_len, 21 void const *info, size_t info_len, 22 void *restrict digest, size_t rounds) 23 { 24 // we must allow at least 1 round of hmac 25 assert(rounds); 26 27 // bound output key material length 28 if (HKDF_MAX_ROUNDS < rounds) 29 rounds = HKDF_MAX_ROUNDS; 30 31 struct hmac_ctx hmac; 32 33 // generate pseudorandom key 34 hmac_gen_iv_block(&hmac, hash, hash_ctx, salt, salt_len); 35 hmac_init(&hmac); 36 hmac_push(&hmac, key, key_len); 37 hmac_dgst(&hmac, digest); 38 39 // expand prk into outpt key material 40 hmac_gen_iv_block(&hmac, hash, hash_ctx, digest, hash->digest_size); 41 42 unsigned char *base = digest; 43 size_t block_len = hash->digest_size; 44 45 for (size_t i = 0; i < rounds; i++) { 46 unsigned char *dst = base + (i * block_len); 47 unsigned char *src = dst - block_len; 48 49 // hkdf expects ctr to start from 01 50 unsigned char ctr = (i + 1) & 0xff; 51 52 // merge zero previous material on round 1 53 size_t merged_len = i ? block_len : 0; 54 55 hmac_init(&hmac); 56 hmac_push(&hmac, src, merged_len); 57 hmac_push(&hmac, info, info_len); 58 hmac_push(&hmac, &ctr, 1); 59 60 hmac_dgst(&hmac, dst); 61 } 62 }