File syn_hkdf.c¶
File List > crypto > syn_hkdf.c
Go to the documentation of this file
#include "syn_hkdf.h"
#include <string.h>
void syn_hkdf_extract(const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len,
uint8_t prk_out[SYN_SHA256_DIGEST_SIZE])
{
static const uint8_t zero_salt[SYN_SHA256_DIGEST_SIZE] = {0};
if (prk_out == NULL) {
return;
}
if (salt == NULL || salt_len == 0) {
salt = zero_salt;
salt_len = SYN_SHA256_DIGEST_SIZE;
}
if (ikm == NULL && ikm_len > 0) {
ikm_len = 0;
}
syn_hmac_sha256(salt, salt_len, ikm, ikm_len, prk_out);
}
bool syn_hkdf_expand(const uint8_t *prk, size_t prk_len, const uint8_t *info, size_t info_len,
uint8_t *okm_out, size_t okm_len)
{
if (prk == NULL || okm_out == NULL || prk_len < SYN_SHA256_DIGEST_SIZE) {
return false;
}
if (okm_len == 0 || okm_len > (255U * SYN_SHA256_DIGEST_SIZE)) {
return false;
}
if (info == NULL && info_len > 0) {
info_len = 0;
}
uint8_t t[SYN_SHA256_DIGEST_SIZE];
size_t t_len = 0;
size_t written = 0;
uint8_t counter = 1;
while (written < okm_len) {
SYN_HMAC_SHA256 hmac;
syn_hmac_sha256_init(&hmac, prk, prk_len);
if (counter > 1) {
syn_hmac_sha256_update(&hmac, t, t_len);
}
if (info_len > 0) {
syn_hmac_sha256_update(&hmac, info, info_len);
}
syn_hmac_sha256_update(&hmac, &counter, 1);
syn_hmac_sha256_final(&hmac, t);
t_len = SYN_SHA256_DIGEST_SIZE;
size_t todo = okm_len - written;
if (todo > SYN_SHA256_DIGEST_SIZE) {
todo = SYN_SHA256_DIGEST_SIZE;
}
memcpy(okm_out + written, t, todo);
written += todo;
counter++;
}
return true;
}
bool syn_hkdf(const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len,
const uint8_t *info, size_t info_len, uint8_t *okm_out, size_t okm_len)
{
uint8_t prk[SYN_SHA256_DIGEST_SIZE];
syn_hkdf_extract(salt, salt_len, ikm, ikm_len, prk);
return syn_hkdf_expand(prk, sizeof(prk), info, info_len, okm_out, okm_len);
}
bool syn_hkdf_expand_label(const uint8_t *secret, size_t secret_len, const char *label,
size_t label_len, const uint8_t *context, size_t context_len,
uint8_t *out, size_t out_len)
{
if (secret == NULL || label == NULL || out == NULL || out_len == 0) {
return false;
}
static const char prefix[] = "tls13 ";
size_t prefix_len = 6;
size_t full_label_len = prefix_len + label_len;
if (full_label_len > 255) {
return false;
}
if (context == NULL && context_len > 0) {
context_len = 0;
}
if (context_len > 255) {
return false;
}
/* HkdfLabel structure buffer:
* uint16 length (2B) + uint8 label_len (1B) + label (full_label_len) +
* uint8 context_len (1B) + context (context_len)
*/
uint8_t hkdf_label[512];
size_t offset = 0;
hkdf_label[offset++] = (uint8_t)((out_len >> 8) & 0xFF);
hkdf_label[offset++] = (uint8_t)(out_len & 0xFF);
hkdf_label[offset++] = (uint8_t)full_label_len;
memcpy(hkdf_label + offset, prefix, prefix_len);
offset += prefix_len;
memcpy(hkdf_label + offset, label, label_len);
offset += label_len;
hkdf_label[offset++] = (uint8_t)context_len;
if (context_len > 0) {
memcpy(hkdf_label + offset, context, context_len);
offset += context_len;
}
return syn_hkdf_expand(secret, secret_len, hkdf_label, offset, out, out_len);
}
/* ── HKDF-SHA384 ─────────────────────────────────────────────────────────── */
void syn_hkdf_sha384_extract(const uint8_t *salt, size_t salt_len, const uint8_t *ikm,
size_t ikm_len, uint8_t prk_out[SYN_SHA384_DIGEST_SIZE])
{
static const uint8_t zero_salt[SYN_SHA384_DIGEST_SIZE] = {0};
if (prk_out == NULL) {
return;
}
if (salt == NULL || salt_len == 0U) {
salt = zero_salt;
salt_len = SYN_SHA384_DIGEST_SIZE;
}
if (ikm == NULL && ikm_len > 0U) {
ikm_len = 0U;
}
syn_hmac_sha384(salt, salt_len, ikm, ikm_len, prk_out);
}
bool syn_hkdf_sha384_expand(const uint8_t *prk, size_t prk_len, const uint8_t *info,
size_t info_len, uint8_t *okm_out, size_t okm_len)
{
if (prk == NULL || okm_out == NULL || prk_len < SYN_SHA384_DIGEST_SIZE) {
return false;
}
if (okm_len == 0U || okm_len > (255U * SYN_SHA384_DIGEST_SIZE)) {
return false;
}
if (info == NULL && info_len > 0U) {
info_len = 0U;
}
uint8_t t[SYN_SHA384_DIGEST_SIZE];
size_t t_len = 0U;
size_t written = 0U;
uint8_t counter = 1U;
while (written < okm_len) {
SYN_HMAC_SHA384 hmac;
syn_hmac_sha384_init(&hmac, prk, prk_len);
if (counter > 1U) {
syn_hmac_sha384_update(&hmac, t, t_len);
}
if (info_len > 0U) {
syn_hmac_sha384_update(&hmac, info, info_len);
}
syn_hmac_sha384_update(&hmac, &counter, 1U);
syn_hmac_sha384_final(&hmac, t);
t_len = SYN_SHA384_DIGEST_SIZE;
size_t todo = okm_len - written;
if (todo > SYN_SHA384_DIGEST_SIZE) {
todo = SYN_SHA384_DIGEST_SIZE;
}
memcpy(okm_out + written, t, todo);
written += todo;
counter++;
}
return true;
}
bool syn_hkdf_sha384(const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len,
const uint8_t *info, size_t info_len, uint8_t *okm_out, size_t okm_len)
{
uint8_t prk[SYN_SHA384_DIGEST_SIZE];
syn_hkdf_sha384_extract(salt, salt_len, ikm, ikm_len, prk);
return syn_hkdf_sha384_expand(prk, sizeof(prk), info, info_len, okm_out, okm_len);
}
bool syn_hkdf_sha384_expand_label(const uint8_t *secret, size_t secret_len, const char *label,
size_t label_len, const uint8_t *context, size_t context_len,
uint8_t *out, size_t out_len)
{
if (secret == NULL || label == NULL || out == NULL || out_len == 0U) {
return false;
}
static const char prefix[] = "tls13 ";
size_t prefix_len = 6U;
size_t full_label_len = prefix_len + label_len;
if (full_label_len > 255U) {
return false;
}
if (context == NULL && context_len > 0U) {
context_len = 0U;
}
if (context_len > 255U) {
return false;
}
uint8_t hkdf_label[512];
size_t offset = 0U;
hkdf_label[offset++] = (uint8_t)((out_len >> 8U) & 0xFFU);
hkdf_label[offset++] = (uint8_t)(out_len & 0xFFU);
hkdf_label[offset++] = (uint8_t)full_label_len;
memcpy(hkdf_label + offset, prefix, prefix_len);
offset += prefix_len;
memcpy(hkdf_label + offset, label, label_len);
offset += label_len;
hkdf_label[offset++] = (uint8_t)context_len;
if (context_len > 0U) {
memcpy(hkdf_label + offset, context, context_len);
offset += context_len;
}
return syn_hkdf_sha384_expand(secret, secret_len, hkdf_label, offset, out, out_len);
}
/* ── HKDF-SHA512 ─────────────────────────────────────────────────────────── */
void syn_hkdf_sha512_extract(const uint8_t *salt, size_t salt_len, const uint8_t *ikm,
size_t ikm_len, uint8_t prk_out[SYN_SHA512_DIGEST_SIZE])
{
static const uint8_t zero_salt[SYN_SHA512_DIGEST_SIZE] = {0};
if (prk_out == NULL) {
return;
}
if (salt == NULL || salt_len == 0U) {
salt = zero_salt;
salt_len = SYN_SHA512_DIGEST_SIZE;
}
if (ikm == NULL && ikm_len > 0U) {
ikm_len = 0U;
}
syn_hmac_sha512(salt, salt_len, ikm, ikm_len, prk_out);
}
bool syn_hkdf_sha512_expand(const uint8_t *prk, size_t prk_len, const uint8_t *info,
size_t info_len, uint8_t *okm_out, size_t okm_len)
{
if (prk == NULL || okm_out == NULL || prk_len < SYN_SHA512_DIGEST_SIZE) {
return false;
}
if (okm_len == 0U || okm_len > (255U * SYN_SHA512_DIGEST_SIZE)) {
return false;
}
if (info == NULL && info_len > 0U) {
info_len = 0U;
}
uint8_t t[SYN_SHA512_DIGEST_SIZE];
size_t t_len = 0U;
size_t written = 0U;
uint8_t counter = 1U;
while (written < okm_len) {
SYN_HMAC_SHA512 hmac;
syn_hmac_sha512_init(&hmac, prk, prk_len);
if (counter > 1U) {
syn_hmac_sha512_update(&hmac, t, t_len);
}
if (info_len > 0U) {
syn_hmac_sha512_update(&hmac, info, info_len);
}
syn_hmac_sha512_update(&hmac, &counter, 1U);
syn_hmac_sha512_final(&hmac, t);
t_len = SYN_SHA512_DIGEST_SIZE;
size_t todo = okm_len - written;
if (todo > SYN_SHA512_DIGEST_SIZE) {
todo = SYN_SHA512_DIGEST_SIZE;
}
memcpy(okm_out + written, t, todo);
written += todo;
counter++;
}
return true;
}
bool syn_hkdf_sha512(const uint8_t *salt, size_t salt_len, const uint8_t *ikm, size_t ikm_len,
const uint8_t *info, size_t info_len, uint8_t *okm_out, size_t okm_len)
{
uint8_t prk[SYN_SHA512_DIGEST_SIZE];
syn_hkdf_sha512_extract(salt, salt_len, ikm, ikm_len, prk);
return syn_hkdf_sha512_expand(prk, sizeof(prk), info, info_len, okm_out, okm_len);
}
bool syn_hkdf_sha512_expand_label(const uint8_t *secret, size_t secret_len, const char *label,
size_t label_len, const uint8_t *context, size_t context_len,
uint8_t *out, size_t out_len)
{
if (secret == NULL || label == NULL || out == NULL || out_len == 0U) {
return false;
}
static const char prefix[] = "tls13 ";
size_t prefix_len = 6U;
size_t full_label_len = prefix_len + label_len;
if (full_label_len > 255U) {
return false;
}
if (context == NULL && context_len > 0U) {
context_len = 0U;
}
if (context_len > 255U) {
return false;
}
uint8_t hkdf_label[512];
size_t offset = 0U;
hkdf_label[offset++] = (uint8_t)((out_len >> 8U) & 0xFFU);
hkdf_label[offset++] = (uint8_t)(out_len & 0xFFU);
hkdf_label[offset++] = (uint8_t)full_label_len;
memcpy(hkdf_label + offset, prefix, prefix_len);
offset += prefix_len;
memcpy(hkdf_label + offset, label, label_len);
offset += label_len;
hkdf_label[offset++] = (uint8_t)context_len;
if (context_len > 0U) {
memcpy(hkdf_label + offset, context, context_len);
offset += context_len;
}
return syn_hkdf_sha512_expand(secret, secret_len, hkdf_label, offset, out, out_len);
}