Skip to content

Commit c3dbe18

Browse files
tniessenRafaelGSS
authored andcommitted
crypto: simplify control flow in HKDF
Unify the implementation and perform the same OpenSSL calls regardless of whether the key and/or salt are empty. This simplifies the code and improves coverage. Refs: #44201 PR-URL: #44272 Reviewed-By: Filip Skokan <[email protected]>
1 parent e001aaf commit c3dbe18

File tree

1 file changed

+26
-40
lines changed

1 file changed

+26
-40
lines changed

src/crypto/crypto_hkdf.cc

+26-40
Original file line numberDiff line numberDiff line change
@@ -112,47 +112,33 @@ bool HKDFTraits::DeriveBits(
112112
// TODO(panva): Once support for OpenSSL 1.1.1 is dropped the whole
113113
// of HKDFTraits::DeriveBits can be refactored to use
114114
// EVP_KDF which does handle zero length key.
115-
if (params.key->GetSymmetricKeySize() != 0) {
116-
if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(),
117-
EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND) ||
118-
!EVP_PKEY_CTX_set1_hkdf_salt(
119-
ctx.get(), params.salt.data<unsigned char>(), params.salt.size()) ||
120-
!EVP_PKEY_CTX_set1_hkdf_key(ctx.get(),
121-
reinterpret_cast<const unsigned char*>(
122-
params.key->GetSymmetricKey()),
123-
params.key->GetSymmetricKeySize())) {
124-
return false;
125-
}
115+
116+
std::string_view salt;
117+
if (params.salt.size() != 0) {
118+
salt = {params.salt.data<char>(), params.salt.size()};
126119
} else {
127-
// Workaround for EVP_PKEY_derive HKDF not handling zero length keys.
128-
unsigned char temp_key[EVP_MAX_MD_SIZE];
129-
unsigned int len = sizeof(temp_key);
130-
if (params.salt.size() != 0) {
131-
if (HMAC(params.digest,
132-
params.salt.data(),
133-
params.salt.size(),
134-
nullptr,
135-
0,
136-
temp_key,
137-
&len) == nullptr) {
138-
return false;
139-
}
140-
} else {
141-
char salt[EVP_MAX_MD_SIZE] = {0};
142-
if (HMAC(params.digest,
143-
salt,
144-
EVP_MD_size(params.digest),
145-
nullptr,
146-
0,
147-
temp_key,
148-
&len) == nullptr) {
149-
return false;
150-
}
151-
}
152-
if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) ||
153-
!EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), temp_key, len)) {
154-
return false;
155-
}
120+
static const char default_salt[EVP_MAX_MD_SIZE] = {0};
121+
salt = {default_salt, static_cast<unsigned>(EVP_MD_size(params.digest))};
122+
}
123+
124+
// We do not use EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND and instead implement
125+
// the extraction step ourselves because EVP_PKEY_derive does not handle
126+
// zero-length keys, which are required for Web Crypto.
127+
unsigned char pseudorandom_key[EVP_MAX_MD_SIZE];
128+
unsigned int prk_len = sizeof(pseudorandom_key);
129+
if (HMAC(
130+
params.digest,
131+
salt.data(),
132+
salt.size(),
133+
reinterpret_cast<const unsigned char*>(params.key->GetSymmetricKey()),
134+
params.key->GetSymmetricKeySize(),
135+
pseudorandom_key,
136+
&prk_len) == nullptr) {
137+
return false;
138+
}
139+
if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) ||
140+
!EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), pseudorandom_key, prk_len)) {
141+
return false;
156142
}
157143

158144
size_t length = params.length;

0 commit comments

Comments
 (0)