1 /* Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License
16 * KBKDF HMAC implementation based on:
17 * - https://csrc.nist.gov/publications/detail/sp/800-108/rev-1/final
18 * - Openssl 3.0 KBKDF HMAC implementation (as a reference)
19 * - Openssl 1.1 HMAC API
26 #include <openssl/hmac.h>
28 #include <generic-backend/exception.h>
38 class HmacPrf : public Prf {
40 explicit HmacPrf(const RawBuffer& keyInput, const EVP_MD* md) {
43 ThrowErr(Exc::Crypto::InternalError, "HMAC_CTX_new failed");
45 if (HMAC_Init_ex(ctx, keyInput.data(), keyInput.size(), md, NULL) != 1) {
47 ThrowErr(Exc::Crypto::InternalError, "HMAC_Init failed");
50 outputSize = HMAC_size(ctx);
53 void Update(const unsigned char* data, size_t size) override {
54 if (HMAC_Update(ctx, data, size) != 1)
55 ThrowErr(Exc::Crypto::InternalError, "HMAC_Update failed");
58 RawBuffer Finalize() override {
59 RawBuffer output(outputSize);
61 if (HMAC_Final(ctx, output.data(), &size) != 1)
62 ThrowErr(Exc::Crypto::InternalError, "HMAC_Final failed");
64 if (size != outputSize)
65 ThrowErr(Exc::Crypto::InternalError, "size != outputSize");
70 void Reset() override {
71 if (HMAC_Init_ex(ctx, nullptr, 0, nullptr, nullptr) !=1)
72 ThrowErr(Exc::Crypto::InternalError, "HMAC_Init (reset) failed");
75 size_t OutputBits() const override {
76 return outputSize * 8;
88 unsigned char ZERO = 0;
90 void addInteger(Prf& prf, size_t value, size_t lenBits)
92 auto beValue = htobe32(value);
93 auto ucValue = reinterpret_cast<const unsigned char*>(&beValue);
94 prf.Update(&ucValue[(32 - lenBits)/8], lenBits/8);
98 RawBuffer deriveKbkdfInternal(Prf& prf,
100 KbkdfCounterLocation counterLocation,
106 size_t length = lengthBits/8;
108 size_t n = lengthBits/prf.OutputBits();
109 if (n > (1ULL << rlenBits) -1)
110 ThrowErr(Exc::Crypto::InternalError,
111 "PRF output length can't be represented with ", rlenBits, " bits.");
114 output.reserve(length);
116 for (size_t counter = 1; output.size() < length; counter++) {
117 if (counterLocation == KbkdfCounterLocation::BEFORE_FIXED)
118 addInteger(prf, counter, rlenBits);
119 fixedInput(prf, counter);
120 if (counterLocation == KbkdfCounterLocation::AFTER_FIXED)
121 addInteger(prf, counter, rlenBits);
122 auto chunk = prf.Finalize();
124 size_t toWrite = std::min(chunk.size(), length - output.size());
126 output.insert(output.end(), chunk.begin(), chunk.begin() + toWrite);
136 RawBuffer deriveKbkdfHmac(const RawBuffer& keyInput,
139 KbkdfCounterLocation counterLocation,
142 const RawBuffer& label,
143 const RawBuffer& context,
146 HmacPrf localPrf(keyInput, md);
148 return deriveKbkdfInternal(
153 [&](Prf& prf, size_t counter){
154 prf.Update(label.data(), label.size());
155 if (counterLocation == KbkdfCounterLocation::MIDDLE_FIXED)
156 addInteger(prf, counter, rlenBits); // skip separator in middle fixed mode
157 else if (useSeparator)
158 prf.Update(&ZERO, 1);
159 prf.Update(context.data(), context.size());
161 addInteger(prf, lengthBits, llenBits);
165 RawBuffer deriveKbkdfHmac(const RawBuffer& keyInput,
168 KbkdfCounterLocation counterLocation,
170 const RawBuffer& fixed)
172 HmacPrf prf(keyInput, md);
174 return deriveKbkdfInternal(
179 [&fixed](Prf& prf, size_t){
180 prf.Update(fixed.data(), fixed.size());