2 * Copyright (c) 2016 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 int tmp_len = (ciphertext.size() / algo->block_size + 1) * algo->block_size;
86 if (key.size() != KEY_SIZE) {
87 LogError("Invalid key size: " << key.size() << ", expected: " << KEY_SIZE);
91 if (iv.size() != IV_SIZE) {
92 LogError("Invalid iv size: " << iv.size() << ", expected: " << IV_SIZE);
96 RawBuffer plaintext(tmp_len, 0);
98 std::unique_ptr<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX *)> ctxptr(
99 ::EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
101 if (ctxptr == nullptr)
102 throw std::bad_alloc();
104 auto ctx = ctxptr.get();
106 int ec = ::EVP_CIPHER_CTX_set_padding(ctx, 1);
108 LogError("Failed to evp ctx set padding. ec: " << ec);
112 ec = ::EVP_CipherInit(ctx, algo, key.data(), iv.data(), 0 /* decrypt flag */);
114 LogError("Failed to evp cipher init. ec: " << ec);
118 int plaintext_len = 0;
119 ec = ::EVP_CipherUpdate(ctx, plaintext.data(), &plaintext_len,
120 ciphertext.data(), ciphertext.size());
122 LogError("Failed to evp cipher update. ec: " << ec);
127 ec = EVP_CipherFinal(ctx, plaintext.data() + plaintext_len, &final_len);
129 LogError("Failed to evp cipher final. ec: " << ec);
133 plaintext_len += final_len;
135 plaintext.resize(plaintext_len);
140 } // namespace anonymous
142 namespace SsMigration {
144 RawBuffer decrypt(const std::string &seed, const RawBuffer &ciphertext)
146 auto key = _get_key(seed);
147 auto iv = _get_iv(key);
149 return _decrypt(key, iv, ciphertext);
152 } // namespace SsMigration