Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
kcenon::network::protocols::quic::hkdf Class Reference

HKDF (HMAC-based Key Derivation Function) utilities (RFC 5869) More...

#include <crypto.h>

Collaboration diagram for kcenon::network::protocols::quic::hkdf:
Collaboration graph

Static Public Member Functions

static auto extract (std::span< const uint8_t > salt, std::span< const uint8_t > ikm) -> Result< std::array< uint8_t, secret_size > >
 HKDF-Extract function.
 
static auto expand (std::span< const uint8_t > prk, std::span< const uint8_t > info, size_t length) -> Result< std::vector< uint8_t > >
 HKDF-Expand function.
 
static auto expand_label (std::span< const uint8_t > secret, const std::string &label, std::span< const uint8_t > context, size_t length) -> Result< std::vector< uint8_t > >
 HKDF-Expand-Label function (TLS 1.3 style)
 

Detailed Description

HKDF (HMAC-based Key Derivation Function) utilities (RFC 5869)

Used for deriving QUIC keys from secrets.

Definition at line 59 of file crypto.h.

Member Function Documentation

◆ expand()

auto kcenon::network::protocols::quic::hkdf::expand ( std::span< const uint8_t > prk,
std::span< const uint8_t > info,
size_t length ) -> Result<std::vector<uint8_t>>
staticnodiscard

HKDF-Expand function.

Parameters
prkPseudorandom key from Extract
infoContext and application specific information
lengthDesired output length
Returns
Output keying material (OKM) or error

Definition at line 128 of file crypto.cpp.

132{
133 std::vector<uint8_t> okm(length);
134
135 EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
136 if (!pctx)
137 {
139 -1, "Failed to create HKDF context", "quic::hkdf");
140 }
141
142 int ret = EVP_PKEY_derive_init(pctx);
143 if (ret <= 0)
144 {
145 EVP_PKEY_CTX_free(pctx);
147 -1, "HKDF derive init failed", "quic::hkdf", get_openssl_error_string());
148 }
149
150 ret = EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256());
151 if (ret <= 0)
152 {
153 EVP_PKEY_CTX_free(pctx);
155 -1, "HKDF set md failed", "quic::hkdf", get_openssl_error_string());
156 }
157
158 ret = EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
159 if (ret <= 0)
160 {
161 EVP_PKEY_CTX_free(pctx);
163 -1, "HKDF set mode failed", "quic::hkdf", get_openssl_error_string());
164 }
165
166 ret = EVP_PKEY_CTX_set1_hkdf_key(pctx, prk.data(),
167 static_cast<int>(prk.size()));
168 if (ret <= 0)
169 {
170 EVP_PKEY_CTX_free(pctx);
172 -1, "HKDF set key failed", "quic::hkdf", get_openssl_error_string());
173 }
174
175 ret = EVP_PKEY_CTX_add1_hkdf_info(pctx, info.data(),
176 static_cast<int>(info.size()));
177 if (ret <= 0)
178 {
179 EVP_PKEY_CTX_free(pctx);
181 -1, "HKDF set info failed", "quic::hkdf", get_openssl_error_string());
182 }
183
184 ret = EVP_PKEY_derive(pctx, okm.data(), &length);
185 EVP_PKEY_CTX_free(pctx);
186
187 if (ret <= 0)
188 {
190 -1, "HKDF expand failed", "quic::hkdf", get_openssl_error_string());
191 }
192
193 okm.resize(length);
194 return ok(std::move(okm));
195}
@ error
Black hole detected, reset to base.
VoidResult ok()

References kcenon::network::protocols::quic::error, and kcenon::network::ok().

Here is the call graph for this function:

◆ expand_label()

auto kcenon::network::protocols::quic::hkdf::expand_label ( std::span< const uint8_t > secret,
const std::string & label,
std::span< const uint8_t > context,
size_t length ) -> Result<std::vector<uint8_t>>
staticnodiscard

HKDF-Expand-Label function (TLS 1.3 style)

Parameters
secretSecret to expand
labelLabel string (without "tls13 " prefix)
contextContext data (usually empty for QUIC)
lengthDesired output length
Returns
Output keying material or error

Definition at line 197 of file crypto.cpp.

202{
203 // TLS 1.3 HKDF-Expand-Label structure:
204 // struct {
205 // uint16 length;
206 // opaque label<7..255> = "tls13 " + Label;
207 // opaque context<0..255>;
208 // } HkdfLabel;
209
210 const std::string prefix = "tls13 ";
211 std::vector<uint8_t> hkdf_label;
212 hkdf_label.reserve(2 + 1 + prefix.size() + label.size() + 1 + context.size());
213
214 // Length (2 bytes, big-endian)
215 hkdf_label.push_back(static_cast<uint8_t>((length >> 8) & 0xFF));
216 hkdf_label.push_back(static_cast<uint8_t>(length & 0xFF));
217
218 // Label length (1 byte) + "tls13 " + label
219 size_t label_len = prefix.size() + label.size();
220 hkdf_label.push_back(static_cast<uint8_t>(label_len));
221 for (char c : prefix)
222 {
223 hkdf_label.push_back(static_cast<uint8_t>(c));
224 }
225 for (char c : label)
226 {
227 hkdf_label.push_back(static_cast<uint8_t>(c));
228 }
229
230 // Context length (1 byte) + context
231 hkdf_label.push_back(static_cast<uint8_t>(context.size()));
232 hkdf_label.insert(hkdf_label.end(), context.begin(), context.end());
233
234 return expand(secret, hkdf_label, length);
235}
static auto expand(std::span< const uint8_t > prk, std::span< const uint8_t > info, size_t length) -> Result< std::vector< uint8_t > >
HKDF-Expand function.
Definition crypto.cpp:128

Referenced by kcenon::network::protocols::quic::initial_keys::derive(), kcenon::network::protocols::quic::initial_keys::derive_keys(), kcenon::network::protocols::quic::quic_crypto::derive_zero_rtt_keys(), and kcenon::network::protocols::quic::quic_crypto::update_keys().

Here is the caller graph for this function:

◆ extract()

auto kcenon::network::protocols::quic::hkdf::extract ( std::span< const uint8_t > salt,
std::span< const uint8_t > ikm ) -> Result<std::array<uint8_t, secret_size>>
staticnodiscard

HKDF-Extract function.

Parameters
saltSalt value (non-secret random value)
ikmInput keying material
Returns
Pseudorandom key (PRK) or error

Definition at line 56 of file crypto.cpp.

59{
60 std::array<uint8_t, secret_size> prk{};
61 size_t prk_len = prk.size();
62
63 EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
64 if (!pctx)
65 {
67 -1, "Failed to create HKDF context", "quic::hkdf");
68 }
69
70 int ret = EVP_PKEY_derive_init(pctx);
71 if (ret <= 0)
72 {
73 EVP_PKEY_CTX_free(pctx);
75 -1, "HKDF derive init failed", "quic::hkdf", get_openssl_error_string());
76 }
77
78 ret = EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256());
79 if (ret <= 0)
80 {
81 EVP_PKEY_CTX_free(pctx);
83 -1, "HKDF set md failed", "quic::hkdf", get_openssl_error_string());
84 }
85
86 // RFC 5869 permits an absent salt. Normalize it instead of relying on
87 // OpenSSL version-specific handling of a null, zero-length buffer.
88 const std::array<uint8_t, secret_size> zero_salt{};
89 if (salt.empty()) salt = zero_salt;
90 ret = EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt.data(),
91 static_cast<int>(salt.size()));
92 if (ret <= 0)
93 {
94 EVP_PKEY_CTX_free(pctx);
96 -1, "HKDF set salt failed", "quic::hkdf", get_openssl_error_string());
97 }
98
99 ret = EVP_PKEY_CTX_set1_hkdf_key(pctx, ikm.data(),
100 static_cast<int>(ikm.size()));
101 if (ret <= 0)
102 {
103 EVP_PKEY_CTX_free(pctx);
105 -1, "HKDF set key failed", "quic::hkdf", get_openssl_error_string());
106 }
107
108 ret = EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY);
109 if (ret <= 0)
110 {
111 EVP_PKEY_CTX_free(pctx);
113 -1, "HKDF set mode failed", "quic::hkdf", get_openssl_error_string());
114 }
115
116 ret = EVP_PKEY_derive(pctx, prk.data(), &prk_len);
117 EVP_PKEY_CTX_free(pctx);
118
119 if (ret <= 0)
120 {
122 -1, "HKDF extract failed", "quic::hkdf", get_openssl_error_string());
123 }
124
125 return ok(std::move(prk));
126}

References kcenon::network::protocols::quic::error, and kcenon::network::ok().

Referenced by kcenon::network::protocols::quic::initial_keys::derive(), and kcenon::network::protocols::quic::quic_crypto::derive_zero_rtt_keys().

Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following files: