2 * Copyright (c) 2014 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.
16 * @file crypto-logic.cpp
17 * @author Sebastian Grabowski (s.grabowski@samsung.com)
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief Crypto module implementation.
31 #include <openssl/evp.h>
32 #include <openssl/rand.h>
34 #include <ckm/ckm-error.h>
36 #include <dpl/log/log.h>
40 #include <crypto-logic.h>
42 #include <generic-backend/exception.h>
43 #include <sw-backend/internals.h>
49 const static int AES_CBC_KEY_SIZE = 32;
50 const static int AES_GCM_TAG_SIZE = 16;
52 // Encryption scheme flags (enable/disable specific encryption type, multiple choice)
53 const int ENCR_BASE64 = 1 << 0;
54 const int ENCR_APPKEY = 1 << 1;
55 const int ENCR_PASSWORD = 1 << 2;
57 // Encryption order flags (single choice)
58 const int ENCR_ORDER_OFFSET = 24;
59 const int ENCR_ORDER_FILTER = INT_MAX << ENCR_ORDER_OFFSET; // 0xff000000
60 const int ENCR_ORDER_CLEAR = ~ENCR_ORDER_FILTER; // 0x00ffffff
62 * ENCR_ORDER_V1 - v1 encryption order. Token returned from store is encrypted with app key and
63 * optionally by custom user password. In such form it is stored in db.
65 const int ENCR_ORDER_V1 = CryptoLogic::ENCRYPTION_V1 << ENCR_ORDER_OFFSET;
67 * ENCR_ORDER_V2 - v2 encryption order. Stored data is optionally encrypted by store with
68 * user password. Returned token is encrypted with app key and stored in db.
70 const int ENCR_ORDER_V2 = CryptoLogic::ENCRYPTION_V2 << ENCR_ORDER_OFFSET;
72 } // anonymous namespace
74 CryptoLogic::CryptoLogic() {}
76 CryptoLogic::CryptoLogic(CryptoLogic &&second) {
77 m_keyMap = std::move(second.m_keyMap);
80 CryptoLogic& CryptoLogic::operator=(CryptoLogic &&second) {
83 m_keyMap = std::move(second.m_keyMap);
87 bool CryptoLogic::haveKey(const Label &smackLabel)
89 return (m_keyMap.count(smackLabel) > 0);
92 void CryptoLogic::pushKey(const Label &smackLabel,
93 const RawBuffer &applicationKey)
95 if (smackLabel.length() == 0) {
96 ThrowErr(Exc::InternalError, "Empty smack label.");
98 if (applicationKey.size() == 0) {
99 ThrowErr(Exc::InternalError, "Empty application key.");
101 if (haveKey(smackLabel)) {
102 ThrowErr(Exc::InternalError, "Application key for ", smackLabel,
103 "label already exists.");
106 m_keyMap[smackLabel] = applicationKey;
109 void CryptoLogic::removeKey(const Label &smackLabel)
111 m_keyMap.erase(smackLabel);
114 RawBuffer CryptoLogic::passwordToKey(
115 const Password &password,
116 const RawBuffer &salt,
117 size_t keySize) const
119 RawBuffer result(keySize);
121 if (1 != PKCS5_PBKDF2_HMAC_SHA1(
130 ThrowErr(Exc::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
136 RawBuffer CryptoLogic::generateRandIV() const {
137 RawBuffer civ(EVP_MAX_IV_LENGTH);
139 if (1 != RAND_bytes(civ.data(), civ.size())) {
140 ThrowErr(Exc::InternalError, "RAND_bytes failed to generate IV.");
146 void CryptoLogic::encryptRow(DB::Row &row)
154 crow.algorithmType = DBCMAlgType::AES_GCM_256;
155 crow.dataSize = crow.data.size();
157 if (crow.dataSize <= 0) {
158 ThrowErr(Exc::InternalError, "Invalid dataSize.");
161 if (!haveKey(row.ownerLabel)) {
162 ThrowErr(Exc::InternalError, "Missing application key for ",
163 row.ownerLabel, " label.");
166 if (crow.iv.empty()) {
167 crow.iv = generateRandIV();
170 key = m_keyMap[row.ownerLabel];
171 crow.encryptionScheme = ENCR_APPKEY;
173 auto dataPair = Crypto::SW::Internals::encryptDataAesGcm(key, crow.data, crow.iv, AES_GCM_TAG_SIZE);
174 crow.data = dataPair.first;
176 crow.tag = dataPair.second;
178 encBase64(crow.data);
179 crow.encryptionScheme |= ENCR_BASE64;
182 crow.encryptionScheme &= ENCR_ORDER_CLEAR;
183 crow.encryptionScheme |= ENCR_ORDER_V2;
185 row = std::move(crow);
186 } catch(const CKM::Base64Encoder::Exception::Base &e) {
187 ThrowErr(Exc::InternalError, e.GetMessage());
188 } catch(const CKM::Base64Decoder::Exception::Base &e) {
189 ThrowErr(Exc::InternalError, e.GetMessage());
193 int CryptoLogic::getSchemeVersion(int encryptionScheme)
195 return encryptionScheme >> ENCR_ORDER_OFFSET;
198 void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
203 RawBuffer digest, dataDigest;
205 if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
206 ThrowErr(Exc::AuthenticationFailed, "Invalid algorithm type.");
209 if ((row.encryptionScheme & ENCR_PASSWORD) && password.empty()) {
210 ThrowErr(Exc::AuthenticationFailed,
211 "DB row is password protected, but given password is "
215 if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.ownerLabel)) {
216 ThrowErr(Exc::AuthenticationFailed, "Missing application key for ",
217 row.ownerLabel, " label.");
221 if (crow.encryptionScheme & ENCR_BASE64) {
222 decBase64(crow.data);
225 if((crow.encryptionScheme >> ENCR_ORDER_OFFSET) == ENCR_ORDER_V2) {
226 if (crow.encryptionScheme & ENCR_APPKEY) {
227 key = m_keyMap[crow.ownerLabel];
228 crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
231 if (crow.encryptionScheme & ENCR_PASSWORD) {
232 key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
233 crow.data = Crypto::SW::Internals::decryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
236 if (crow.encryptionScheme & ENCR_APPKEY) {
237 key = m_keyMap[crow.ownerLabel];
238 crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
241 if (static_cast<int>(crow.data.size()) < crow.dataSize) {
242 ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
245 if (static_cast<int>(crow.data.size()) > crow.dataSize) {
246 crow.data.resize(crow.dataSize);
249 row = std::move(crow);
250 } catch(const CKM::Base64Encoder::Exception::Base &e) {
251 ThrowErr(Exc::InternalError, e.GetMessage());
252 } catch(const CKM::Base64Decoder::Exception::Base &e) {
253 ThrowErr(Exc::InternalError, e.GetMessage());
254 } catch(const Exc::Exception &e) {
255 ThrowErr(Exc::AuthenticationFailed, e.message());
259 void CryptoLogic::encBase64(RawBuffer &data)
266 encdata = benc.get();
268 if (encdata.size() == 0) {
269 ThrowErr(Exc::InternalError, "Base64Encoder returned empty data.");
272 data = std::move(encdata);
275 void CryptoLogic::decBase64(RawBuffer &data)
282 if (!bdec.finalize()) {
283 ThrowErr(Exc::InternalError, "Failed in Base64Decoder.finalize.");
286 decdata = bdec.get();
288 if (decdata.size() == 0) {
289 ThrowErr(Exc::InternalError, "Base64Decoder returned empty data.");
292 data = std::move(decdata);
295 bool CryptoLogic::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
297 unsigned int dlen = Digest().length();
299 if ((dig1.size() != dlen) || (dig2.size() != dlen))
301 return (dig1 == dig2);