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.
30 #include <openssl/evp.h>
31 #include <openssl/rand.h>
33 #include <ckm/ckm-error.h>
35 #include <dpl/log/log.h>
39 #include <crypto-logic.h>
41 #include <generic-backend/exception.h>
42 #include <sw-backend/internals.h>
46 const static int AES_CBC_KEY_SIZE = 32;
47 const static int AES_GCM_TAG_SIZE = 16;
49 } // anonymous namespace
53 CryptoLogic::CryptoLogic() {}
55 CryptoLogic::CryptoLogic(CryptoLogic &&second) {
56 m_keyMap = std::move(second.m_keyMap);
59 CryptoLogic& CryptoLogic::operator=(CryptoLogic &&second) {
62 m_keyMap = std::move(second.m_keyMap);
66 bool CryptoLogic::haveKey(const Label &smackLabel)
68 return (m_keyMap.count(smackLabel) > 0);
71 void CryptoLogic::pushKey(const Label &smackLabel,
72 const RawBuffer &applicationKey)
74 if (smackLabel.length() == 0) {
75 ThrowErr(Exc::InternalError, "Empty smack label.");
77 if (applicationKey.size() == 0) {
78 ThrowErr(Exc::InternalError, "Empty application key.");
80 if (haveKey(smackLabel)) {
81 ThrowErr(Exc::InternalError, "Application key for ", smackLabel,
82 "label already exists.");
85 m_keyMap[smackLabel] = applicationKey;
88 void CryptoLogic::removeKey(const Label &smackLabel)
90 m_keyMap.erase(smackLabel);
93 RawBuffer CryptoLogic::passwordToKey(
94 const Password &password,
95 const RawBuffer &salt,
98 RawBuffer result(keySize);
100 if (1 != PKCS5_PBKDF2_HMAC_SHA1(
109 ThrowErr(Exc::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
115 RawBuffer CryptoLogic::generateRandIV() const {
116 RawBuffer civ(EVP_MAX_IV_LENGTH);
118 if (1 != RAND_bytes(civ.data(), civ.size())) {
119 ThrowErr(Exc::InternalError, "RAND_bytes failed to generate IV.");
125 void CryptoLogic::encryptRow(const Password &password, DB::Row &row)
133 crow.algorithmType = DBCMAlgType::AES_GCM_256;
134 crow.dataSize = crow.data.size();
136 if (crow.dataSize <= 0) {
137 ThrowErr(Exc::InternalError, "Invalid dataSize.");
140 if (!haveKey(row.ownerLabel)) {
141 ThrowErr(Exc::InternalError, "Missing application key for ",
142 row.ownerLabel, " label.");
145 if (crow.iv.empty()) {
146 crow.iv = generateRandIV();
149 key = m_keyMap[row.ownerLabel];
150 crow.encryptionScheme = ENCR_APPKEY;
152 auto dataPair = Crypto::SW::Internals::encryptDataAesGcm(key, crow.data, crow.iv, AES_GCM_TAG_SIZE);
153 crow.data = dataPair.first;
155 crow.tag = dataPair.second;
157 #ifdef OPTIONAL_PASSWORD_ENABLE
158 if (!password.empty()) {
159 key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
161 crow.data = Crypto::SW::Internals::encryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
162 crow.encryptionScheme |= ENCR_PASSWORD;
168 encBase64(crow.data);
169 crow.encryptionScheme |= ENCR_BASE64;
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());
180 void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
185 RawBuffer digest, dataDigest;
187 if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
188 ThrowErr(Exc::AuthenticationFailed, "Invalid algorithm type.");
191 if ((row.encryptionScheme & ENCR_PASSWORD) && password.empty()) {
192 ThrowErr(Exc::AuthenticationFailed,
193 "DB row is password protected, but given password is "
197 if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.ownerLabel)) {
198 ThrowErr(Exc::AuthenticationFailed, "Missing application key for ",
199 row.ownerLabel, " label.");
203 if (crow.encryptionScheme & ENCR_BASE64) {
204 decBase64(crow.data);
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);
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);
219 if (static_cast<int>(crow.data.size()) < crow.dataSize) {
220 ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
223 if (static_cast<int>(crow.data.size()) > crow.dataSize) {
224 crow.data.resize(crow.dataSize);
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());
237 void CryptoLogic::encBase64(RawBuffer &data)
244 encdata = benc.get();
246 if (encdata.size() == 0) {
247 ThrowErr(Exc::InternalError, "Base64Encoder returned empty data.");
250 data = std::move(encdata);
253 void CryptoLogic::decBase64(RawBuffer &data)
260 if (!bdec.finalize()) {
261 ThrowErr(Exc::InternalError, "Failed in Base64Decoder.finalize.");
264 decdata = bdec.get();
266 if (decdata.size() == 0) {
267 ThrowErr(Exc::InternalError, "Base64Decoder returned empty data.");
270 data = std::move(decdata);
273 bool CryptoLogic::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
275 unsigned int dlen = Digest().length();
277 if ((dig1.size() != dlen) || (dig2.size() != dlen))
279 return (dig1 == dig2);