Adapt key-manager to work with OpenSSL 1.1 preserving 1.0 compatibility
[platform/core/security/key-manager.git] / src / manager / service / ss-crypto.cpp
1 /*
2  *  Copyright (c) 2016 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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
15  *
16  *
17  * @file        ss-crypto.cpp
18  * @author      Kyungwook Tak (k.tak@samsung.com)
19  * @version     1.0
20  * @brief       Decrypt old secure-storage data for migration
21  */
22 #include <ss-crypto.h>
23
24 #include <memory>
25 #include <cstring>
26
27 #include <openssl/sha.h>
28 #include <openssl/evp.h>
29 #include <openssl/hmac.h>
30
31 #include <dpl/log/log.h>
32
33 // lengths defined as macro to be used independent to type (size_t, unsigned int, int)
34 #define SALT_SIZE 32
35 #define KEY_SIZE 16
36 #define IV_SIZE KEY_SIZE
37
38 namespace CKM {
39
40 namespace {
41
42 RawBuffer _get_key(const std::string &id)
43 {
44         unsigned char salt[SALT_SIZE];
45
46         ::memset(salt, 0xFF, SALT_SIZE);
47
48         RawBuffer duk(KEY_SIZE);
49
50         if (::PKCS5_PBKDF2_HMAC_SHA1(id.c_str(), id.length(), salt, SALT_SIZE, 1, duk.size(),
51                         duk.data()) != 1) {
52                 LogError("Failed to pkcs5_pkbdf_hmac_sha1.");
53                 return RawBuffer();
54         }
55
56         return duk;
57 }
58
59 RawBuffer _get_iv(const RawBuffer &src)
60 {
61         RawBuffer iv(SHA_DIGEST_LENGTH);
62
63         unsigned int ivlen = 0;
64
65         if (::EVP_Digest(src.data(), src.size(), iv.data(), &ivlen, ::EVP_sha1(), nullptr)
66                         != 1) {
67                 LogError("Failed to get iv");
68                 return RawBuffer();
69         }
70
71         if (ivlen < IV_SIZE) {
72                 LogError("Invalid iv size: " << ivlen);
73                 return RawBuffer();
74         }
75
76         iv.resize(IV_SIZE);
77
78         return iv;
79 }
80
81 RawBuffer _decrypt(const RawBuffer &key, const RawBuffer &iv, const RawBuffer &ciphertext)
82 {
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;
86
87         if (key.size() != KEY_SIZE) {
88                 LogError("Invalid key size: " << key.size() << ", expected: " << KEY_SIZE);
89                 return RawBuffer();
90         }
91
92         if (iv.size() != IV_SIZE) {
93                 LogError("Invalid iv size: " << iv.size() << ", expected: " << IV_SIZE);
94                 return RawBuffer();
95         }
96
97         RawBuffer plaintext(tmp_len, 0);
98
99         std::unique_ptr<EVP_CIPHER_CTX, void(*)(EVP_CIPHER_CTX *)> ctxptr(
100                         ::EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);
101
102         if (ctxptr == nullptr)
103                 throw std::bad_alloc();
104
105         auto ctx = ctxptr.get();
106
107         int ec = ::EVP_CIPHER_CTX_set_padding(ctx, 1);
108         if (ec != 1) {
109                 LogError("Failed to evp ctx set padding. ec: " << ec);
110                 return RawBuffer();
111         }
112
113         ec = ::EVP_CipherInit(ctx, algo, key.data(), iv.data(), 0 /* decrypt flag */);
114         if (ec != 1) {
115                 LogError("Failed to evp cipher init. ec: " << ec);
116                 return RawBuffer();
117         }
118
119         int plaintext_len = 0;
120         ec = ::EVP_CipherUpdate(ctx, plaintext.data(), &plaintext_len,
121                         ciphertext.data(), ciphertext.size());
122         if (ec != 1) {
123                 LogError("Failed to evp cipher update. ec: " << ec);
124                 return RawBuffer();
125         }
126
127         int final_len = 0;
128         ec = EVP_CipherFinal(ctx, plaintext.data() + plaintext_len, &final_len);
129         if (ec != 1) {
130                 LogError("Failed to evp cipher final. ec: " << ec);
131                 return RawBuffer();
132         }
133
134         plaintext_len += final_len;
135
136         plaintext.resize(plaintext_len);
137
138         return plaintext;
139 }
140
141 } // namespace anonymous
142
143 namespace SsMigration {
144
145 RawBuffer decrypt(const std::string &seed, const RawBuffer &ciphertext)
146 {
147         auto key = _get_key(seed);
148         auto iv = _get_iv(key);
149
150         return _decrypt(key, iv, ciphertext);
151 }
152
153 } // namespace SsMigration
154
155 } // namespace CKM