2 * Copyright (c) 2014-2020 Samsung Electronics Co., Ltd. All rights reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
19 #include <openssl/rand.h>
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/sha.h>
24 #include <key-provider.h>
25 #include <ckm/ckm-zero-memory.h>
29 #include <crypto-backend.h>
30 #ifdef SE_BACKEND_ENABLED
31 #include <se-backend/internals.h>
37 constexpr int PBKDF2_ITERATIONS = 4096;
38 constexpr uint32_t KEYCOMPONENT_VERSION = 2;
39 constexpr int OPENSSL_ENGINE_ERROR = -4;
40 constexpr int AUTHENTICATION_ERROR = -5;
43 RawBuffer toRawBuffer(const T &data)
46 const unsigned char *ptr = reinterpret_cast<const unsigned char *>(&data);
47 output.assign(ptr, ptr + sizeof(T));
51 // You cannot use toRawBuffer template with pointers
53 RawBuffer toRawBuffer(T *)
55 class NoPointerAllowed {
62 int encryptAes256Gcm(const unsigned char *plaintext,
63 int plaintext_len, const unsigned char *key, const unsigned char *iv,
64 unsigned char *ciphertext, unsigned char *tag)
67 int ciphertext_len = 0;
69 auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
71 return OPENSSL_ENGINE_ERROR;
73 if (!EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
74 return OPENSSL_ENGINE_ERROR;
76 if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, MAX_IV_SIZE, NULL))
77 return OPENSSL_ENGINE_ERROR;
79 if (!EVP_EncryptInit_ex(ctx.get(), NULL, NULL, key, iv))
80 return OPENSSL_ENGINE_ERROR;
82 if (!EVP_EncryptUpdate(ctx.get(), ciphertext, &len, plaintext, plaintext_len))
83 return OPENSSL_ENGINE_ERROR;
87 if (!EVP_EncryptFinal_ex(ctx.get(), ciphertext + len, &len))
88 return OPENSSL_ENGINE_ERROR;
90 ciphertext_len += len;
92 if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, MAX_IV_SIZE, tag))
93 return OPENSSL_ENGINE_ERROR;
95 return ciphertext_len;
98 int decryptAes256Gcm(const unsigned char *ciphertext,
99 int ciphertext_len, unsigned char *tag, const unsigned char *key,
100 const unsigned char *iv, unsigned char *plaintext)
102 auto decrypt = [&](size_t iv_len){
107 auto ctx = uptr<EVP_CIPHER_CTX_free>(EVP_CIPHER_CTX_new());
109 return OPENSSL_ENGINE_ERROR;
111 if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL, NULL, NULL))
112 return OPENSSL_ENGINE_ERROR;
114 if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
115 return OPENSSL_ENGINE_ERROR;
117 if (!EVP_DecryptInit_ex(ctx.get(), NULL, NULL, key, iv))
118 return OPENSSL_ENGINE_ERROR;
120 if (!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext, ciphertext_len))
121 return OPENSSL_ENGINE_ERROR;
125 if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, MAX_IV_SIZE, tag))
126 return OPENSSL_ENGINE_ERROR;
128 if (!(ret = EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)))
129 return AUTHENTICATION_ERROR;
132 plaintext_len += len;
133 return plaintext_len;
139 auto ret = decrypt(MAX_IV_SIZE);
140 if (ret == AUTHENTICATION_ERROR)
141 ret = decrypt(12); // retry with truncated IV
146 typedef std::array<uint8_t, MAX_KEY_SIZE> KeyData;
148 KeyData PBKDF(const std::string& pass, const unsigned char *salt, int saltlen)
151 if (!PKCS5_PBKDF2_HMAC_SHA1(pass.c_str(),
158 ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR");
163 // derives a key used for DomainKEK encryption (aka PKEK1) from random salt & user password
164 KeyData makePKEK1(const DomainKEKInfo& domainKEKInfo, const Password &password)
166 std::string concatPasswordClient(password.c_str());
167 concatPasswordClient += std::string(domainKEKInfo.client);
169 if (domainKEKInfo.version != KEYCOMPONENT_VERSION)
170 ThrowErr(Exc::InternalError, "It's not expected version");
173 if (domainKEKInfo.backend == (int)CryptoBackend::SecureElement) {
174 #if SE_BACKEND_ENABLED
175 salt = Crypto::SE::Internals::encryptWithDbpKey((unsigned char*)domainKEKInfo.salt,
177 (unsigned char*)domainKEKInfo.iv,
180 ThrowErr(Exc::InternalError, "It's not expected backend");
182 } else if (domainKEKInfo.backend == (int)CryptoBackend::OpenSSL) {
183 salt = RawBuffer(domainKEKInfo.salt, domainKEKInfo.salt + MAX_SALT_SIZE);
185 ThrowErr(Exc::InternalError, "It's not expected backend");
188 return PBKDF(concatPasswordClient, salt.data(), salt.size());
191 // derives a key (PKEK2) from DomainKEK and custom client string (may be a client id or uid)
192 KeyData makePKEK2(const uint8_t *domainKEK, const std::string &client)
194 return PBKDF(client, domainKEK, MAX_SALT_SIZE);
197 void unwrapDomainKEK(const RawBuffer &wrappedDomainKEKbuffer,
198 const Password &password,
199 DomainKEKAndInfo &domainKEK)
201 DomainKEKAndInfo wrappedDomainKEK(wrappedDomainKEKbuffer);
202 KeyData PKEK1 = makePKEK1(wrappedDomainKEK.info, password);
205 if (0 > (keyLength = decryptAes256Gcm(wrappedDomainKEK.key,
206 wrappedDomainKEK.info.keyLength,
207 wrappedDomainKEK.info.tag,
209 wrappedDomainKEK.info.iv,
211 ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed");
213 domainKEK.setKeyInfo(wrappedDomainKEK.info);
214 domainKEK.info.keyLength = static_cast<uint32_t>(keyLength);
217 RawBuffer wrapDomainKEK(DomainKEKAndInfo &domainKEK, const Password &password)
219 KeyData PKEK1 = makePKEK1(domainKEK.info, password);
221 DomainKEKAndInfo wrappedDomainKEK;
222 wrappedDomainKEK.setKeyInfo(domainKEK.info);
225 if (0 > (wrappedLength = encryptAes256Gcm(domainKEK.key,
226 domainKEK.info.keyLength,
229 wrappedDomainKEK.key,
230 wrappedDomainKEK.info.tag)))
231 ThrowErr(Exc::InternalError, "DomainKEK encryption failed");
233 wrappedDomainKEK.info.keyLength = static_cast<uint32_t>(wrappedLength);
234 return toRawBuffer(wrappedDomainKEK);
238 bool randomize(uint8_t (&array)[N])
240 return RAND_bytes(array, N) == 1;
243 } // anonymous namespace
245 KeyProvider::KeyProvider() :
247 m_isInitialized(false)
249 LogDebug("Created empty KeyProvider");
252 KeyProvider::KeyProvider(
253 const RawBuffer &domainKEKInWrapForm,
254 const Password &password) :
255 m_domainKEK(new DomainKEKAndInfo()),
256 m_isInitialized(true)
258 if (domainKEKInWrapForm.size() != sizeof(DomainKEKAndInfo)) {
259 LogWarning("Input size:" << domainKEKInWrapForm.size()
260 << " Expected: " << sizeof(DomainKEKAndInfo));
261 LogWarning("Buffer doesn't have proper size to store DomainKEKAndInfo in KeyProvider"
263 m_isInitialized = false;
267 unwrapDomainKEK(domainKEKInWrapForm, password, *m_domainKEK);
270 KeyProvider &KeyProvider::operator=(KeyProvider &&second)
272 LogDebug("Moving KeyProvider");
277 m_isInitialized = second.m_isInitialized;
278 m_domainKEK = second.m_domainKEK;
279 second.m_isInitialized = false;
280 second.m_domainKEK = NULL;
284 KeyProvider::KeyProvider(KeyProvider &&second)
286 LogDebug("Moving KeyProvider");
287 m_isInitialized = second.m_isInitialized;
288 m_domainKEK = second.m_domainKEK;
289 second.m_isInitialized = false;
290 second.m_domainKEK = NULL;
293 bool KeyProvider::isInitialized() const
295 return m_isInitialized;
298 RawBuffer KeyProvider::getPureDomainKEK() const
300 if (!m_isInitialized)
301 ThrowErr(Exc::InternalError, "Object not initialized!");
304 return RawBuffer(m_domainKEK->key, m_domainKEK->key + m_domainKEK->info.keyLength);
307 RawBuffer KeyProvider::getWrappedDomainKEK(const Password &password) const
309 if (!m_isInitialized)
310 ThrowErr(Exc::InternalError, "Object not initialized!");
312 return wrapDomainKEK(*m_domainKEK, password);
315 RawBuffer KeyProvider::getPureDEK(const RawBuffer &wrappedDEKbuffer) const
317 if (!m_isInitialized)
318 ThrowErr(Exc::InternalError, "Object not initialized!");
320 if (wrappedDEKbuffer.size() != sizeof(DEKAndInfo)) {
321 LogError("input size:" << wrappedDEKbuffer.size() << " Expected: " << sizeof(DEKAndInfo));
323 ThrowErr(Exc::InternalError,
324 "buffer doesn't have proper size to store KeyAndInfo in KeyProvider::getPureDEK");
328 DEKAndInfo wrappedDEK(wrappedDEKbuffer);
330 KeyData PKEK2 = makePKEK2(m_domainKEK->key, wrappedDEK.info.client);
333 if (0 > (keyLength = decryptAes256Gcm(wrappedDEK.key,
334 wrappedDEK.info.keyLength,
339 ThrowErr(Exc::InternalError, "UnwrapDEK Failed in KeyProvider::getPureDEK");
341 DEK.info.keyLength = static_cast<uint32_t>(keyLength);
343 LogDebug("getPureDEK SUCCESS");
344 return RawBuffer(DEK.key, DEK.key + DEK.info.keyLength);
347 RawBuffer KeyProvider::generateDEK(const std::string &client) const
349 if (!m_isInitialized)
350 ThrowErr(Exc::InternalError, "Object not initialized!");
352 DEKAndInfo wrappedDEK;
353 std::string resized_client;
355 if (client.length() < MAX_CLIENT_ID_SIZE)
356 resized_client = client;
358 resized_client = client.substr(0, MAX_CLIENT_ID_SIZE - 1);
360 uint8_t DEK[MAX_KEY_SIZE];
362 if (!randomize(DEK) || !randomize(wrappedDEK.info.iv))
363 ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR");
365 KeyData PKEK2 = makePKEK2(m_domainKEK->key, resized_client);
367 int wrappedKeyLength;
368 if (0 > (wrappedKeyLength = encryptAes256Gcm(DEK,
373 wrappedDEK.info.tag)))
374 ThrowErr(Exc::InternalError, "GenerateDEK Failed in KeyProvider::generateDEK");
376 wrappedDEK.info.keyLength = static_cast<uint32_t>(wrappedKeyLength);
377 wrappedDEK.setKeyInfoClient(resized_client);
379 LogDebug("GenerateDEK Success");
380 return toRawBuffer(wrappedDEK);
383 void KeyProvider::migrateDomainKEK(const RawBuffer &wrappedDomainKEKbuffer,
384 const Password &password)
386 DEKAndInfo wrappedOldDomainKEK(wrappedDomainKEKbuffer);
388 std::string concatPasswordClient(password.c_str());
389 concatPasswordClient += std::string(wrappedOldDomainKEK.info.client);
391 KeyData PKEK1 = PBKDF(concatPasswordClient, wrappedOldDomainKEK.info.salt, MAX_SALT_SIZE);
394 if (0 > (keyLength = decryptAes256Gcm(wrappedOldDomainKEK.key,
395 wrappedOldDomainKEK.info.keyLength,
396 wrappedOldDomainKEK.info.tag,
398 wrappedOldDomainKEK.info.iv,
400 ThrowErr(Exc::AuthenticationFailed, "DomainKEK decryption failed");
402 DomainKEKInfo info(wrappedOldDomainKEK.info);
403 info.version = KEYCOMPONENT_VERSION;
404 info.backend = static_cast<uint32_t>(CryptoBackend::OpenSSL);
405 #ifdef SE_BACKEND_ENABLED
406 info.backend = static_cast<uint32_t>(CryptoBackend::SecureElement);
408 m_domainKEK->setKeyInfo(info);
410 m_domainKEK->info.keyLength = static_cast<uint32_t>(keyLength);
411 m_isInitialized = true;
412 LogDebug("Migrate DomainKEK Success");
415 RawBuffer KeyProvider::generateDomainKEK(const std::string &user, const Password &userPassword)
417 DomainKEKAndInfo domainKEK;
419 if (!randomize(domainKEK.info.salt) ||
420 !randomize(domainKEK.key) ||
421 !randomize(domainKEK.info.iv)) {
422 ThrowErr(Exc::InternalError, "OPENSSL_ENGINE_ERROR");
425 domainKEK.info.version = KEYCOMPONENT_VERSION;
426 domainKEK.info.backend = static_cast<uint32_t>(CryptoBackend::OpenSSL);
427 #ifdef SE_BACKEND_ENABLED
428 domainKEK.info.backend = static_cast<uint32_t>(CryptoBackend::SecureElement);
430 domainKEK.info.keyLength = sizeof(domainKEK.key);
431 domainKEK.setKeyInfoClient(user);
433 return wrapDomainKEK(domainKEK, userPassword);