2 * Copyright (c) 2016 - 2019 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
18 * @author Kyungwook Tak (k.tak@samsung.com)
20 * @brief Decrypt old secure-storage data for migration
22 #include <ss-crypto.h>
27 #include <openssl/sha.h>
28 #include <openssl/evp.h>
29 #include <openssl/hmac.h>
31 #include <dpl/log/log.h>
33 // lengths defined as macro to be used independent to type (size_t, unsigned int, int)
36 #define IV_SIZE KEY_SIZE
42 RawBuffer _get_key(const std::string &id)
44 unsigned char salt[SALT_SIZE];
46 ::memset(salt, 0xFF, SALT_SIZE);
48 RawBuffer duk(KEY_SIZE);
50 if (::PKCS5_PBKDF2_HMAC_SHA1(id.c_str(), id.length(), salt, SALT_SIZE, 1, duk.size(),
52 LogError("Failed to pkcs5_pkbdf_hmac_sha1.");
59 RawBuffer _get_iv(const RawBuffer &src)
61 RawBuffer iv(SHA_DIGEST_LENGTH);
63 unsigned int ivlen = 0;
65 if (::EVP_Digest(src.data(), src.size(), iv.data(), &ivlen, ::EVP_sha1(), nullptr)
67 LogError("Failed to get iv");
71 if (ivlen < IV_SIZE) {
72 LogError("Invalid iv size: " << ivlen);
81 RawBuffer _decrypt(const RawBuffer &key, const RawBuffer &iv, const RawBuffer &ciphertext)
83 auto algo = ::EVP_aes_128_cbc();
84 auto block_size = ::EVP_CIPHER_block_size(algo);
85 int tmp_len = (ciphertext.size() / block_size + 1) * block_size;
87 if (key.size() != KEY_SIZE) {
88 LogError("Invalid key size: " << key.size() << ", expected: " << KEY_SIZE);
92 if (iv.size() != IV_SIZE) {
93 LogError("Invalid iv size: " << iv.size() << ", expected: " << IV_SIZE);
97 RawBuffer plaintext(tmp_len, 0);
99 std::unique_ptr<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX *)> ctxptr(
100 ::EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
102 if (ctxptr == nullptr)
103 throw std::bad_alloc();
105 auto ctx = ctxptr.get();
107 int ec = ::EVP_CIPHER_CTX_set_padding(ctx, 1);
109 LogError("Failed to evp ctx set padding. ec: " << ec);
113 ec = ::EVP_CipherInit(ctx, algo, key.data(), iv.data(), 0 /* decrypt flag */);
115 LogError("Failed to evp cipher init. ec: " << ec);
119 int plaintext_len = 0;
120 ec = ::EVP_CipherUpdate(ctx, plaintext.data(), &plaintext_len,
121 ciphertext.data(), ciphertext.size());
123 LogError("Failed to evp cipher update. ec: " << ec);
128 ec = EVP_CipherFinal(ctx, plaintext.data() + plaintext_len, &final_len);
130 LogError("Failed to evp cipher final. ec: " << ec);
134 plaintext_len += final_len;
136 plaintext.resize(plaintext_len);
141 } // namespace anonymous
143 namespace SsMigration {
145 RawBuffer decrypt(const std::string &seed, const RawBuffer &ciphertext)
147 auto key = _get_key(seed);
148 auto iv = _get_iv(key);
150 return _decrypt(key, iv, ciphertext);
153 } // namespace SsMigration