Fix build for 64-bit architectures.
[platform/core/security/key-manager.git] / src / manager / crypto / sw-backend / kbkdf.cpp
1 /* Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved
2  *
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
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
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
14  */
15 /*
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
20  * */
21
22 #include <stdexcept>
23 #include <endian.h>
24 #include <algorithm>
25
26 #include <openssl/hmac.h>
27
28 #include <generic-backend/exception.h>
29
30 #include "kbkdf.h"
31
32
33 namespace CKM
34 {
35
36 namespace {
37
38 class HmacPrf : public Prf {
39 public:
40         explicit HmacPrf(const RawBuffer& keyInput, const EVP_MD* md) {
41                 ctx = HMAC_CTX_new();
42                 if (ctx == NULL)
43                         ThrowErr(Exc::Crypto::InternalError, "HMAC_CTX_new failed");
44
45                 if (HMAC_Init_ex(ctx, keyInput.data(), keyInput.size(),  md, NULL) != 1) {
46                         HMAC_CTX_free(ctx);
47                         ThrowErr(Exc::Crypto::InternalError, "HMAC_Init failed");
48                 }
49
50                 outputSize = HMAC_size(ctx);
51         }
52
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");
56         }
57
58         RawBuffer Finalize() override {
59                 RawBuffer output(outputSize);
60                 unsigned size;
61                 if (HMAC_Final(ctx, output.data(), &size) != 1)
62                         ThrowErr(Exc::Crypto::InternalError, "HMAC_Final failed");
63
64                 if (size != outputSize)
65                         ThrowErr(Exc::Crypto::InternalError, "size != outputSize");
66
67                 return output;
68         }
69
70         void Reset() override {
71                 if (HMAC_Init_ex(ctx, nullptr, 0, nullptr, nullptr) !=1)
72                         ThrowErr(Exc::Crypto::InternalError, "HMAC_Init (reset) failed");
73         }
74
75         size_t OutputBits() const override {
76                 return outputSize * 8;
77         }
78
79         ~HmacPrf() {
80                 HMAC_CTX_free(ctx);
81         }
82
83 private:
84         HMAC_CTX* ctx;
85         size_t outputSize;
86 };
87
88 unsigned char ZERO = 0;
89
90 void addInteger(Prf& prf, size_t value, size_t lenBits)
91 {
92         auto beValue = htobe32(value);
93         auto ucValue = reinterpret_cast<const unsigned char*>(&beValue);
94         prf.Update(&ucValue[(32 - lenBits)/8], lenBits/8);
95 }
96
97 template <typename F>
98 RawBuffer deriveKbkdfInternal(Prf& prf,
99                               size_t lengthBits,
100                               KbkdfCounterLocation counterLocation,
101                               size_t rlenBits,
102                               F fixedInput)
103 {
104         RawBuffer keyOutput;
105
106         size_t length = lengthBits/8;
107
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.");
112
113         RawBuffer output;
114         output.reserve(length);
115
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();
123
124                 size_t toWrite = std::min(chunk.size(), length - output.size());
125
126                 output.insert(output.end(), chunk.begin(), chunk.begin() + toWrite);
127
128                 prf.Reset();
129         }
130
131         return output;
132 }
133
134 } // anonymous
135
136 RawBuffer deriveKbkdfHmac(const RawBuffer& keyInput,
137                           size_t lengthBits,
138                           const EVP_MD* md,
139                           KbkdfCounterLocation counterLocation,
140                           size_t rlenBits,
141                           size_t llenBits,
142                           const RawBuffer& label,
143                           const RawBuffer& context,
144                           bool useSeparator)
145 {
146         HmacPrf localPrf(keyInput, md);
147
148         return deriveKbkdfInternal(
149                         localPrf,
150                         lengthBits,
151                         counterLocation,
152                         rlenBits,
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());
160                                 if (llenBits > 0)
161                                         addInteger(prf, lengthBits, llenBits);
162                         });
163 }
164
165 RawBuffer deriveKbkdfHmac(const RawBuffer& keyInput,
166                           size_t lengthBits,
167                           const EVP_MD* md,
168                           KbkdfCounterLocation counterLocation,
169                           size_t rlenBits,
170                           const RawBuffer& fixed)
171 {
172         HmacPrf prf(keyInput, md);
173
174         return deriveKbkdfInternal(
175                         prf,
176                         lengthBits,
177                         counterLocation,
178                         rlenBits,
179                         [&fixed](Prf& prf, size_t){
180                                 prf.Update(fixed.data(), fixed.size());
181                         });
182 }
183
184 } // namespace CKM