Move encrypted/decrypted rows instead of copying
[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 #ifdef OPTIONAL_PASSWORD_ENABLE
158         if (!password.empty()) {
159             key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
160
161             crow.data = Crypto::SW::Internals::encryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
162             crow.encryptionScheme |= ENCR_PASSWORD;
163         }
164 #else
165         (void)password;
166 #endif
167
168         encBase64(crow.data);
169         crow.encryptionScheme |= ENCR_BASE64;
170         encBase64(crow.iv);
171
172         row = std::move(crow);
173     } catch(const CKM::Base64Encoder::Exception::Base &e) {
174         ThrowErr(Exc::InternalError, e.GetMessage());
175     } catch(const CKM::Base64Decoder::Exception::Base &e) {
176         ThrowErr(Exc::InternalError, e.GetMessage());
177     }
178 }
179
180 void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
181 {
182     try {
183         DB::Row crow = row;
184         RawBuffer key;
185         RawBuffer digest, dataDigest;
186
187         if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
188             ThrowErr(Exc::AuthenticationFailed, "Invalid algorithm type.");
189         }
190
191         if ((row.encryptionScheme & ENCR_PASSWORD) && password.empty()) {
192             ThrowErr(Exc::AuthenticationFailed,
193               "DB row is password protected, but given password is "
194               "empty.");
195         }
196
197         if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.ownerLabel)) {
198             ThrowErr(Exc::AuthenticationFailed, "Missing application key for ",
199               row.ownerLabel, " label.");
200         }
201
202         decBase64(crow.iv);
203         if (crow.encryptionScheme & ENCR_BASE64) {
204             decBase64(crow.data);
205         }
206
207 #ifdef OPTIONAL_PASSWORD_ENABLE
208         if (crow.encryptionScheme & ENCR_PASSWORD) {
209             key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
210             crow.data = Crypto::SW::Internals::decryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
211         }
212 #endif
213
214         if (crow.encryptionScheme & ENCR_APPKEY) {
215             key = m_keyMap[crow.ownerLabel];
216             crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
217         }
218
219         if (static_cast<int>(crow.data.size()) < crow.dataSize) {
220             ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
221         }
222
223         if (static_cast<int>(crow.data.size()) > crow.dataSize) {
224             crow.data.resize(crow.dataSize);
225         }
226
227         row = std::move(crow);
228     } catch(const CKM::Base64Encoder::Exception::Base &e) {
229         ThrowErr(Exc::InternalError, e.GetMessage());
230     } catch(const CKM::Base64Decoder::Exception::Base &e) {
231         ThrowErr(Exc::InternalError, e.GetMessage());
232     } catch(const Exc::Exception &e) {
233         ThrowErr(Exc::AuthenticationFailed, e.message());
234     }
235 }
236
237 void CryptoLogic::encBase64(RawBuffer &data)
238 {
239     Base64Encoder benc;
240     RawBuffer encdata;
241
242     benc.append(data);
243     benc.finalize();
244     encdata = benc.get();
245
246     if (encdata.size() == 0) {
247         ThrowErr(Exc::InternalError, "Base64Encoder returned empty data.");
248     }
249
250     data = std::move(encdata);
251 }
252
253 void CryptoLogic::decBase64(RawBuffer &data)
254 {
255     Base64Decoder bdec;
256     RawBuffer decdata;
257
258     bdec.reset();
259     bdec.append(data);
260     if (!bdec.finalize()) {
261         ThrowErr(Exc::InternalError, "Failed in Base64Decoder.finalize.");
262     }
263
264     decdata = bdec.get();
265
266     if (decdata.size() == 0) {
267         ThrowErr(Exc::InternalError, "Base64Decoder returned empty data.");
268     }
269
270     data = std::move(decdata);
271 }
272
273 bool CryptoLogic::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
274 {
275     unsigned int dlen = Digest().length();
276
277     if ((dig1.size() != dlen) || (dig2.size() != dlen))
278         return false;
279     return (dig1 == dig2);
280 }
281
282 } // namespace CKM
283