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.
28 #include <openssl/evp.h>
29 #include <openssl/rand.h>
31 #include <ckm/ckm-error.h>
33 #include <dpl/log/log.h>
38 #include <crypto-logic.h>
40 #define AES_CBC_KEY_SIZE 32
44 CryptoLogic::CryptoLogic(){}
46 CryptoLogic::CryptoLogic(CryptoLogic &&second) {
47 m_keyMap = std::move(second.m_keyMap);
50 CryptoLogic& CryptoLogic::operator=(CryptoLogic &&second) {
53 m_keyMap = std::move(second.m_keyMap);
57 bool CryptoLogic::haveKey(const Label &smackLabel)
59 return (m_keyMap.count(smackLabel) > 0);
62 void CryptoLogic::pushKey(const Label &smackLabel,
63 const RawBuffer &applicationKey)
65 if (smackLabel.length() == 0) {
66 ThrowMsg(Exception::InternalError, "Empty smack label.");
68 if (applicationKey.size() == 0) {
69 ThrowMsg(Exception::InternalError, "Empty application key.");
71 if (haveKey(smackLabel)) {
72 ThrowMsg(Exception::InternalError, "Application key for " << smackLabel
73 << "label already exists.");
75 m_keyMap[smackLabel] = applicationKey;
78 void CryptoLogic::removeKey(const Label &smackLabel)
80 m_keyMap.erase(smackLabel);
83 RawBuffer CryptoLogic::encryptDataAesCbc(
84 const RawBuffer &data,
86 const RawBuffer &iv) const
88 Crypto::Cipher::AesCbcEncryption enc(key, iv);
89 RawBuffer result = enc.Append(data);
90 RawBuffer tmp = enc.Finalize();
91 std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
95 RawBuffer CryptoLogic::decryptDataAesCbc(
96 const RawBuffer &data,
98 const RawBuffer &iv) const
100 Crypto::Cipher::AesCbcDecryption dec(key, iv);
101 RawBuffer result = dec.Append(data);
102 RawBuffer tmp = dec.Finalize();
103 std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
107 std::pair<RawBuffer,RawBuffer> CryptoLogic::encryptDataAesGcm(
108 const RawBuffer &data,
109 const RawBuffer &key,
110 const RawBuffer &iv) const
112 RawBuffer tag(AES_GCM_TAG_SIZE);
113 Crypto::Cipher::AesGcmEncryption enc(key, iv);
114 RawBuffer result = enc.Append(data);
115 RawBuffer tmp = enc.Finalize();
116 std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
117 if (0 == enc.Control(EVP_CTRL_GCM_GET_TAG, AES_GCM_TAG_SIZE, tag.data())) {
118 LogError("Error in aes control function. Get tag failed.");
119 ThrowMsg(Exception::EncryptDBRowError, "Error in aes control function. Get tag failed.");
121 return std::make_pair(result, tag);
124 RawBuffer CryptoLogic::decryptDataAesGcm(
125 const RawBuffer &data,
126 const RawBuffer &key,
128 const RawBuffer &tag) const
130 Crypto::Cipher::AesGcmDecryption dec(key, iv);
131 if (tag.size() < AES_GCM_TAG_SIZE) {
132 LogError("Error in decryptDataAesGcm. Tag is too short.");
133 ThrowMsg(Exception::DecryptDBRowError, "Error in decryptDataAesGcm. Tag is too short");
135 void *ptr = (void*)tag.data();
136 if (0 == dec.Control(EVP_CTRL_GCM_SET_TAG, AES_GCM_TAG_SIZE, ptr)) {
137 LogError("Error in aes control function. Set tag failed.");
138 ThrowMsg(Exception::DecryptDBRowError, "Error in aes control function. Set tag failed.");
140 RawBuffer result = dec.Append(data);
141 RawBuffer tmp = dec.Finalize();
142 std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
146 RawBuffer CryptoLogic::passwordToKey(
147 const Password &password,
148 const RawBuffer &salt,
149 size_t keySize) const
151 RawBuffer result(keySize);
153 if (1 != PKCS5_PBKDF2_HMAC_SHA1(
162 ThrowMsg(Exception::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
167 RawBuffer CryptoLogic::generateRandIV() const {
168 RawBuffer civ(EVP_MAX_IV_LENGTH);
170 if (1 != RAND_bytes(civ.data(), civ.size())) {
171 ThrowMsg(Exception::InternalError,
172 "RAND_bytes failed to generate IV.");
178 void CryptoLogic::encryptRow(const Password &password, DB::Row &row)
186 crow.algorithmType = DBCMAlgType::AES_GCM_256;
187 crow.dataSize = crow.data.size();
189 if (crow.dataSize <= 0) {
190 ThrowMsg(Exception::EncryptDBRowError, "Invalid dataSize.");
193 if (!haveKey(row.ownerLabel)) {
194 ThrowMsg(Exception::EncryptDBRowError, "Missing application key for " <<
195 row.ownerLabel << " label.");
198 if (crow.iv.empty()) {
199 crow.iv = generateRandIV();
202 key = m_keyMap[row.ownerLabel];
203 crow.encryptionScheme = ENCR_APPKEY;
205 auto dataPair = encryptDataAesGcm(crow.data, key, crow.iv);
206 crow.data = dataPair.first;
207 crow.tag = dataPair.second;
209 if (!password.empty()) {
210 key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
211 crow.data = encryptDataAesCbc(crow.data, key, crow.iv);
212 crow.encryptionScheme |= ENCR_PASSWORD;
215 encBase64(crow.data);
216 crow.encryptionScheme |= ENCR_BASE64;
220 } catch(const CKM::Base64Encoder::Exception::Base &e) {
221 LogDebug("Base64Encoder error: " << e.GetMessage());
222 ThrowMsg(Exception::Base64EncoderError, e.GetMessage());
223 } catch(const CKM::Base64Decoder::Exception::Base &e) {
224 LogDebug("Base64Encoder error: " << e.GetMessage());
225 ThrowMsg(Exception::Base64DecoderError, e.GetMessage());
226 } catch(const CKM::Crypto::Exception::Base &e) {
227 LogDebug("Crypto error: " << e.GetMessage());
228 ThrowMsg(Exception::EncryptDBRowError, e.GetMessage());
232 void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
237 RawBuffer digest, dataDigest;
239 if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
240 ThrowMsg(Exception::DecryptDBRowError, "Invalid algorithm type.");
243 if ((row.encryptionScheme & ENCR_PASSWORD) && password.empty()) {
244 ThrowMsg(Exception::DecryptDBRowError,
245 "DB row is password protected, but given password is "
249 if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.ownerLabel)) {
250 ThrowMsg(Exception::DecryptDBRowError, "Missing application key for " <<
251 row.ownerLabel << " label.");
255 if (crow.encryptionScheme & ENCR_BASE64) {
256 decBase64(crow.data);
259 if (crow.encryptionScheme & ENCR_PASSWORD) {
260 key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
261 crow.data = decryptDataAesCbc(crow.data, key, crow.iv);
264 if (crow.encryptionScheme & ENCR_APPKEY) {
265 key = m_keyMap[crow.ownerLabel];
266 crow.data = decryptDataAesGcm(crow.data, key, crow.iv, crow.tag);
269 if (static_cast<int>(crow.data.size()) < crow.dataSize) {
270 ThrowMsg(Exception::DecryptDBRowError,
271 "Decrypted row size mismatch");
272 LogError("Decryption row size mismatch");
275 if (static_cast<int>(crow.data.size()) > crow.dataSize) {
276 crow.data.resize(crow.dataSize);
280 } catch(const CKM::Base64Encoder::Exception::Base &e) {
281 LogDebug("Base64Encoder error: " << e.GetMessage());
282 ThrowMsg(Exception::Base64EncoderError, e.GetMessage());
283 } catch(const CKM::Base64Decoder::Exception::Base &e) {
284 LogDebug("Base64Encoder error: " << e.GetMessage());
285 ThrowMsg(Exception::Base64DecoderError, e.GetMessage());
286 } catch(const CKM::Crypto::Exception::Base &e) {
287 LogDebug("Crypto error: " << e.GetMessage());
288 ThrowMsg(Exception::DecryptDBRowError, e.GetMessage());
292 void CryptoLogic::encBase64(RawBuffer &data)
299 encdata = benc.get();
301 if (encdata.size() == 0) {
302 ThrowMsg(Exception::Base64EncoderError, "Base64Encoder returned empty data.");
305 data = std::move(encdata);
308 void CryptoLogic::decBase64(RawBuffer &data)
315 if (not bdec.finalize()) {
316 ThrowMsg(Exception::Base64DecoderError,
317 "Failed in Base64Decoder.finalize.");
320 decdata = bdec.get();
322 if (decdata.size() == 0) {
323 ThrowMsg(Exception::Base64DecoderError, "Base64Decoder returned empty data.");
326 data = std::move(decdata);
329 bool CryptoLogic::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
331 unsigned int dlen = Digest().length();
333 if ((dig1.size() != dlen) || (dig2.size() != dlen))
335 return (dig1 == dig2);