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