9f663c8801c6048bf426dc5ff4426cdc3051f830
[platform/core/security/key-manager.git] / src / manager / service / crypto-logic.cpp
1 /*
2  * Copyright (c) 2014 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  * @file        crypto-logic.cpp
17  * @author      Sebastian Grabowski (s.grabowski@samsung.com)
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief       Crypto module implementation.
21  */
22
23 #include <iostream>
24 #include <fstream>
25 #include <utility>
26
27 #include <stdio.h>
28 #include <string.h>
29
30 #include <openssl/evp.h>
31 #include <openssl/rand.h>
32
33 #include <ckm/ckm-error.h>
34
35 #include <dpl/log/log.h>
36
37 #include <base64.h>
38 #include <digest.h>
39 #include <crypto-logic.h>
40
41 #include <generic-backend/exception.h>
42 #include <sw-backend/internals.h>
43
44 namespace {
45
46 const static int AES_CBC_KEY_SIZE = 32;
47 const static int AES_GCM_TAG_SIZE = 16;
48
49 } // anonymous namespace
50
51 namespace CKM {
52
53 CryptoLogic::CryptoLogic() {}
54
55 CryptoLogic::CryptoLogic(CryptoLogic &&second) {
56     m_keyMap = std::move(second.m_keyMap);
57 }
58
59 CryptoLogic& CryptoLogic::operator=(CryptoLogic &&second) {
60     if (this == &second)
61         return *this;
62     m_keyMap = std::move(second.m_keyMap);
63     return *this;
64 }
65
66 bool CryptoLogic::haveKey(const Label &smackLabel)
67 {
68     return (m_keyMap.count(smackLabel) > 0);
69 }
70
71 void CryptoLogic::pushKey(const Label &smackLabel,
72                           const RawBuffer &applicationKey)
73 {
74     if (smackLabel.length() == 0) {
75         ThrowErr(Exc::InternalError, "Empty smack label.");
76     }
77     if (applicationKey.size() == 0) {
78         ThrowErr(Exc::InternalError, "Empty application key.");
79     }
80     if (haveKey(smackLabel)) {
81         ThrowErr(Exc::InternalError, "Application key for ", smackLabel,
82             "label already exists.");
83     }
84
85     m_keyMap[smackLabel] = applicationKey;
86 }
87
88 void CryptoLogic::removeKey(const Label &smackLabel)
89 {
90     m_keyMap.erase(smackLabel);
91 }
92
93 RawBuffer CryptoLogic::passwordToKey(
94     const Password &password,
95     const RawBuffer &salt,
96     size_t keySize) const
97 {
98     RawBuffer result(keySize);
99
100     if (1 != PKCS5_PBKDF2_HMAC_SHA1(
101                 password.c_str(),
102                 password.size(),
103                 salt.data(),
104                 salt.size(),
105                 1024,
106                 result.size(),
107                 result.data()))
108     {
109         ThrowErr(Exc::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
110     }
111
112     return result;
113 }
114
115 RawBuffer CryptoLogic::generateRandIV() const {
116     RawBuffer civ(EVP_MAX_IV_LENGTH);
117
118     if (1 != RAND_bytes(civ.data(), civ.size())) {
119         ThrowErr(Exc::InternalError, "RAND_bytes failed to generate IV.");
120     }
121
122     return civ;
123 }
124
125 void CryptoLogic::encryptRow(const Password &password, DB::Row &row)
126 {
127     try {
128         DB::Row crow = row;
129         RawBuffer key;
130         RawBuffer result1;
131         RawBuffer result2;
132
133         crow.algorithmType = DBCMAlgType::AES_GCM_256;
134         crow.dataSize = crow.data.size();
135
136         if (crow.dataSize <= 0) {
137             ThrowErr(Exc::InternalError, "Invalid dataSize.");
138         }
139
140         if (!haveKey(row.ownerLabel)) {
141             ThrowErr(Exc::InternalError, "Missing application key for ",
142               row.ownerLabel, " label.");
143         }
144
145         if (crow.iv.empty()) {
146             crow.iv = generateRandIV();
147         }
148
149         key = m_keyMap[row.ownerLabel];
150         crow.encryptionScheme = ENCR_APPKEY;
151
152         auto dataPair = Crypto::SW::Internals::encryptDataAesGcm(key, crow.data, crow.iv, AES_GCM_TAG_SIZE);
153         crow.data = dataPair.first;
154
155         crow.tag = dataPair.second;
156
157         if (!password.empty()) {
158             key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
159
160             crow.data = Crypto::SW::Internals::encryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
161             crow.encryptionScheme |= ENCR_PASSWORD;
162         }
163
164         encBase64(crow.data);
165         crow.encryptionScheme |= ENCR_BASE64;
166         encBase64(crow.iv);
167
168         row = std::move(crow);
169     } catch(const CKM::Base64Encoder::Exception::Base &e) {
170         ThrowErr(Exc::InternalError, e.GetMessage());
171     } catch(const CKM::Base64Decoder::Exception::Base &e) {
172         ThrowErr(Exc::InternalError, e.GetMessage());
173     }
174 }
175
176 void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
177 {
178     try {
179         DB::Row crow = row;
180         RawBuffer key;
181         RawBuffer digest, dataDigest;
182
183         if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
184             ThrowErr(Exc::AuthenticationFailed, "Invalid algorithm type.");
185         }
186
187         if ((row.encryptionScheme & ENCR_PASSWORD) && password.empty()) {
188             ThrowErr(Exc::AuthenticationFailed,
189               "DB row is password protected, but given password is "
190               "empty.");
191         }
192
193         if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.ownerLabel)) {
194             ThrowErr(Exc::AuthenticationFailed, "Missing application key for ",
195               row.ownerLabel, " label.");
196         }
197
198         decBase64(crow.iv);
199         if (crow.encryptionScheme & ENCR_BASE64) {
200             decBase64(crow.data);
201         }
202
203         if (crow.encryptionScheme & ENCR_PASSWORD) {
204             key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
205             crow.data = Crypto::SW::Internals::decryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
206         }
207
208         if (crow.encryptionScheme & ENCR_APPKEY) {
209             key = m_keyMap[crow.ownerLabel];
210             crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
211         }
212
213         if (static_cast<int>(crow.data.size()) < crow.dataSize) {
214             ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
215         }
216
217         if (static_cast<int>(crow.data.size()) > crow.dataSize) {
218             crow.data.resize(crow.dataSize);
219         }
220
221         row = std::move(crow);
222     } catch(const CKM::Base64Encoder::Exception::Base &e) {
223         ThrowErr(Exc::InternalError, e.GetMessage());
224     } catch(const CKM::Base64Decoder::Exception::Base &e) {
225         ThrowErr(Exc::InternalError, e.GetMessage());
226     } catch(const Exc::Exception &e) {
227         ThrowErr(Exc::AuthenticationFailed, e.message());
228     }
229 }
230
231 void CryptoLogic::encBase64(RawBuffer &data)
232 {
233     Base64Encoder benc;
234     RawBuffer encdata;
235
236     benc.append(data);
237     benc.finalize();
238     encdata = benc.get();
239
240     if (encdata.size() == 0) {
241         ThrowErr(Exc::InternalError, "Base64Encoder returned empty data.");
242     }
243
244     data = std::move(encdata);
245 }
246
247 void CryptoLogic::decBase64(RawBuffer &data)
248 {
249     Base64Decoder bdec;
250     RawBuffer decdata;
251
252     bdec.reset();
253     bdec.append(data);
254     if (!bdec.finalize()) {
255         ThrowErr(Exc::InternalError, "Failed in Base64Decoder.finalize.");
256     }
257
258     decdata = bdec.get();
259
260     if (decdata.size() == 0) {
261         ThrowErr(Exc::InternalError, "Base64Decoder returned empty data.");
262     }
263
264     data = std::move(decdata);
265 }
266
267 bool CryptoLogic::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
268 {
269     unsigned int dlen = Digest().length();
270
271     if ((dig1.size() != dlen) || (dig2.size() != dlen))
272         return false;
273     return (dig1 == dig2);
274 }
275
276 } // namespace CKM
277