xref: /aosp_15_r20/external/tink/cc/subtle/hkdf.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang // Copyright 2017 Google Inc.
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang //     http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang 
17*e7b1675dSTing-Kang Chang #include "tink/subtle/hkdf.h"
18*e7b1675dSTing-Kang Chang 
19*e7b1675dSTing-Kang Chang #include <cstdint>
20*e7b1675dSTing-Kang Chang #include <string>
21*e7b1675dSTing-Kang Chang 
22*e7b1675dSTing-Kang Chang #include "absl/algorithm/container.h"
23*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
24*e7b1675dSTing-Kang Chang #include "absl/strings/string_view.h"
25*e7b1675dSTing-Kang Chang #include "absl/types/span.h"
26*e7b1675dSTing-Kang Chang #include "openssl/evp.h"
27*e7b1675dSTing-Kang Chang // BoringSSL and OpenSSL have incompatible ways to compute HKDF: BoringSSL
28*e7b1675dSTing-Kang Chang // provides a one-shot API HKDF, while OpenSSL doesn't make that API public, but
29*e7b1675dSTing-Kang Chang // instead provides this functionality over the EVP interface, which in turn
30*e7b1675dSTing-Kang Chang // doesn't provide means to compute HKDF in BoringSSL. As a consequence, we need
31*e7b1675dSTing-Kang Chang // to selectively include the correct header and use different implementations.
32*e7b1675dSTing-Kang Chang #ifdef OPENSSL_IS_BORINGSSL
33*e7b1675dSTing-Kang Chang #include "openssl/base.h"
34*e7b1675dSTing-Kang Chang #include "openssl/hkdf.h"
35*e7b1675dSTing-Kang Chang #else
36*e7b1675dSTing-Kang Chang #include "openssl/kdf.h"
37*e7b1675dSTing-Kang Chang #endif
38*e7b1675dSTing-Kang Chang #include "tink/internal/md_util.h"
39*e7b1675dSTing-Kang Chang #include "tink/internal/ssl_unique_ptr.h"
40*e7b1675dSTing-Kang Chang #include "tink/subtle/common_enums.h"
41*e7b1675dSTing-Kang Chang #include "tink/subtle/subtle_util.h"
42*e7b1675dSTing-Kang Chang #include "tink/util/secret_data.h"
43*e7b1675dSTing-Kang Chang #include "tink/util/status.h"
44*e7b1675dSTing-Kang Chang #include "tink/util/statusor.h"
45*e7b1675dSTing-Kang Chang 
46*e7b1675dSTing-Kang Chang namespace crypto {
47*e7b1675dSTing-Kang Chang namespace tink {
48*e7b1675dSTing-Kang Chang namespace subtle {
49*e7b1675dSTing-Kang Chang namespace {
50*e7b1675dSTing-Kang Chang 
51*e7b1675dSTing-Kang Chang // Compute HKDF using `evp_md` hashing, key `ikm`, salt `salt` and info `info`.
52*e7b1675dSTing-Kang Chang // The result is written to `key`.
SslHkdf(const EVP_MD * evp_md,absl::string_view ikm,absl::string_view salt,absl::string_view info,absl::Span<uint8_t> out_key)53*e7b1675dSTing-Kang Chang util::Status SslHkdf(const EVP_MD *evp_md, absl::string_view ikm,
54*e7b1675dSTing-Kang Chang                      absl::string_view salt, absl::string_view info,
55*e7b1675dSTing-Kang Chang                      absl::Span<uint8_t> out_key) {
56*e7b1675dSTing-Kang Chang   const uint8_t *ikm_ptr = reinterpret_cast<const uint8_t *>(ikm.data());
57*e7b1675dSTing-Kang Chang   const uint8_t *salt_ptr = reinterpret_cast<const uint8_t *>(salt.data());
58*e7b1675dSTing-Kang Chang   const uint8_t *info_ptr = reinterpret_cast<const uint8_t *>(info.data());
59*e7b1675dSTing-Kang Chang #ifdef OPENSSL_IS_BORINGSSL
60*e7b1675dSTing-Kang Chang   if (HKDF(out_key.data(), out_key.size(), evp_md, ikm_ptr, ikm.size(),
61*e7b1675dSTing-Kang Chang            salt_ptr, salt.size(), info_ptr, info.size()) != 1) {
62*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInternal, "HKDF failed");
63*e7b1675dSTing-Kang Chang   }
64*e7b1675dSTing-Kang Chang   return util::OkStatus();
65*e7b1675dSTing-Kang Chang #else
66*e7b1675dSTing-Kang Chang   internal::SslUniquePtr<EVP_PKEY_CTX> pctx(
67*e7b1675dSTing-Kang Chang       EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, /*e=*/nullptr));
68*e7b1675dSTing-Kang Chang   if (pctx == nullptr || EVP_PKEY_derive_init(pctx.get()) <= 0 ||
69*e7b1675dSTing-Kang Chang       EVP_PKEY_CTX_set_hkdf_md(pctx.get(), evp_md) <= 0 ||
70*e7b1675dSTing-Kang Chang       EVP_PKEY_CTX_set1_hkdf_salt(pctx.get(), salt_ptr, salt.size()) <= 0 ||
71*e7b1675dSTing-Kang Chang       EVP_PKEY_CTX_set1_hkdf_key(pctx.get(), ikm_ptr, ikm.size()) <= 0 ||
72*e7b1675dSTing-Kang Chang       EVP_PKEY_CTX_add1_hkdf_info(pctx.get(), info_ptr, info.size()) <= 0) {
73*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInternal,
74*e7b1675dSTing-Kang Chang                         "EVP_PKEY_CTX setup failed");
75*e7b1675dSTing-Kang Chang   }
76*e7b1675dSTing-Kang Chang   size_t output_length = out_key.size();
77*e7b1675dSTing-Kang Chang   if (EVP_PKEY_derive(pctx.get(), out_key.data(), &output_length) <= 0) {
78*e7b1675dSTing-Kang Chang     return util::Status(absl::StatusCode::kInternal, "HKDF failed");
79*e7b1675dSTing-Kang Chang   }
80*e7b1675dSTing-Kang Chang   return util::OkStatus();
81*e7b1675dSTing-Kang Chang #endif
82*e7b1675dSTing-Kang Chang }
83*e7b1675dSTing-Kang Chang 
84*e7b1675dSTing-Kang Chang }  // namespace
85*e7b1675dSTing-Kang Chang 
ComputeHkdf(HashType hash,const util::SecretData & ikm,absl::string_view salt,absl::string_view info,size_t out_len)86*e7b1675dSTing-Kang Chang util::StatusOr<util::SecretData> Hkdf::ComputeHkdf(HashType hash,
87*e7b1675dSTing-Kang Chang                                                    const util::SecretData &ikm,
88*e7b1675dSTing-Kang Chang                                                    absl::string_view salt,
89*e7b1675dSTing-Kang Chang                                                    absl::string_view info,
90*e7b1675dSTing-Kang Chang                                                    size_t out_len) {
91*e7b1675dSTing-Kang Chang   util::StatusOr<const EVP_MD *> evp_md = internal::EvpHashFromHashType(hash);
92*e7b1675dSTing-Kang Chang   if (!evp_md.ok()) {
93*e7b1675dSTing-Kang Chang     return evp_md.status();
94*e7b1675dSTing-Kang Chang   }
95*e7b1675dSTing-Kang Chang 
96*e7b1675dSTing-Kang Chang   util::SecretData out_key(out_len);
97*e7b1675dSTing-Kang Chang   util::Status result =
98*e7b1675dSTing-Kang Chang       SslHkdf(*evp_md, util::SecretDataAsStringView(ikm), salt, info,
99*e7b1675dSTing-Kang Chang               absl::MakeSpan(out_key.data(), out_key.size()));
100*e7b1675dSTing-Kang Chang   if (!result.ok()) {
101*e7b1675dSTing-Kang Chang     return result;
102*e7b1675dSTing-Kang Chang   }
103*e7b1675dSTing-Kang Chang   return out_key;
104*e7b1675dSTing-Kang Chang }
105*e7b1675dSTing-Kang Chang 
ComputeHkdf(HashType hash,absl::string_view ikm,absl::string_view salt,absl::string_view info,size_t out_len)106*e7b1675dSTing-Kang Chang util::StatusOr<std::string> Hkdf::ComputeHkdf(HashType hash,
107*e7b1675dSTing-Kang Chang                                               absl::string_view ikm,
108*e7b1675dSTing-Kang Chang                                               absl::string_view salt,
109*e7b1675dSTing-Kang Chang                                               absl::string_view info,
110*e7b1675dSTing-Kang Chang                                               size_t out_len) {
111*e7b1675dSTing-Kang Chang   util::StatusOr<const EVP_MD *> evp_md = internal::EvpHashFromHashType(hash);
112*e7b1675dSTing-Kang Chang   if (!evp_md.ok()) {
113*e7b1675dSTing-Kang Chang     return evp_md.status();
114*e7b1675dSTing-Kang Chang   }
115*e7b1675dSTing-Kang Chang   std::string out_key;
116*e7b1675dSTing-Kang Chang   ResizeStringUninitialized(&out_key, out_len);
117*e7b1675dSTing-Kang Chang   util::Status result = SslHkdf(
118*e7b1675dSTing-Kang Chang       *evp_md, ikm, salt, info,
119*e7b1675dSTing-Kang Chang       absl::MakeSpan(reinterpret_cast<uint8_t *>(&out_key[0]), out_key.size()));
120*e7b1675dSTing-Kang Chang   if (!result.ok()) {
121*e7b1675dSTing-Kang Chang     return result;
122*e7b1675dSTing-Kang Chang   }
123*e7b1675dSTing-Kang Chang   return out_key;
124*e7b1675dSTing-Kang Chang }
125*e7b1675dSTing-Kang Chang 
ComputeEciesHkdfSymmetricKey(HashType hash,absl::string_view kem_bytes,const util::SecretData & shared_secret,absl::string_view salt,absl::string_view info,size_t out_len)126*e7b1675dSTing-Kang Chang util::StatusOr<util::SecretData> Hkdf::ComputeEciesHkdfSymmetricKey(
127*e7b1675dSTing-Kang Chang     HashType hash, absl::string_view kem_bytes,
128*e7b1675dSTing-Kang Chang     const util::SecretData &shared_secret, absl::string_view salt,
129*e7b1675dSTing-Kang Chang     absl::string_view info, size_t out_len) {
130*e7b1675dSTing-Kang Chang   util::SecretData ikm(kem_bytes.size() + shared_secret.size());
131*e7b1675dSTing-Kang Chang   absl::c_copy(kem_bytes, ikm.begin());
132*e7b1675dSTing-Kang Chang   absl::c_copy(shared_secret, ikm.begin() + kem_bytes.size());
133*e7b1675dSTing-Kang Chang   return Hkdf::ComputeHkdf(hash, ikm, salt, info, out_len);
134*e7b1675dSTing-Kang Chang }
135*e7b1675dSTing-Kang Chang 
136*e7b1675dSTing-Kang Chang }  // namespace subtle
137*e7b1675dSTing-Kang Chang }  // namespace tink
138*e7b1675dSTing-Kang Chang }  // namespace crypto
139