#include <iostream>
#include <fstream>
+#include <utility>
+#include <climits>
+
#include <stdio.h>
#include <string.h>
#include <base64.h>
#include <digest.h>
-#include <crypto.h>
#include <crypto-logic.h>
-#define AES_CBC_KEY_SIZE 32
+#include <generic-backend/exception.h>
+#include <sw-backend/internals.h>
namespace CKM {
-CryptoLogic::CryptoLogic(){}
+namespace {
+
+const static int AES_CBC_KEY_SIZE = 32;
+const static int AES_GCM_TAG_SIZE = 16;
+
+// Encryption scheme flags (enable/disable specific encryption type, multiple choice)
+const int ENCR_BASE64 = 1 << 0;
+const int ENCR_APPKEY = 1 << 1;
+const int ENCR_PASSWORD = 1 << 2;
+
+// Encryption order flags (single choice)
+const int ENCR_ORDER_OFFSET = 24;
+const int ENCR_ORDER_FILTER = INT_MAX << ENCR_ORDER_OFFSET; // 0xff000000
+const int ENCR_ORDER_CLEAR = ~ENCR_ORDER_FILTER; // 0x00ffffff
+/*
+ * ENCR_ORDER_V1 - v1 encryption order. Token returned from store is encrypted with app key and
+ * optionally by custom user password. In such form it is stored in db.
+ */
+const int ENCR_ORDER_V1 = CryptoLogic::ENCRYPTION_V1 << ENCR_ORDER_OFFSET;
+/*
+ * ENCR_ORDER_V2 - v2 encryption order. Stored data is optionally encrypted by store with
+ * user password. Returned token is encrypted with app key and stored in db.
+ */
+const int ENCR_ORDER_V2 = CryptoLogic::ENCRYPTION_V2 << ENCR_ORDER_OFFSET;
+
+} // anonymous namespace
+
+CryptoLogic::CryptoLogic() {}
CryptoLogic::CryptoLogic(CryptoLogic &&second) {
m_keyMap = std::move(second.m_keyMap);
return *this;
}
-bool CryptoLogic::haveKey(const std::string &smackLabel)
+bool CryptoLogic::haveKey(const Label &smackLabel)
{
return (m_keyMap.count(smackLabel) > 0);
}
-void CryptoLogic::pushKey(const std::string &smackLabel,
- const RawBuffer &applicationKey)
+void CryptoLogic::pushKey(const Label &smackLabel,
+ const RawBuffer &applicationKey)
{
if (smackLabel.length() == 0) {
- ThrowMsg(Exception::InternalError, "Empty smack label.");
+ ThrowErr(Exc::InternalError, "Empty smack label.");
}
if (applicationKey.size() == 0) {
- ThrowMsg(Exception::InternalError, "Empty application key.");
+ ThrowErr(Exc::InternalError, "Empty application key.");
}
if (haveKey(smackLabel)) {
- ThrowMsg(Exception::InternalError, "Application key for " << smackLabel
- << "label already exists.");
+ ThrowErr(Exc::InternalError, "Application key for ", smackLabel,
+ "label already exists.");
}
- m_keyMap[smackLabel] = applicationKey;
-}
-RawBuffer CryptoLogic::encryptDataAesCbc(
- const RawBuffer &data,
- const RawBuffer &key,
- const RawBuffer &iv) const
-{
- Crypto::Cipher::AesCbcEncryption enc(key, iv);
- RawBuffer result = enc.Append(data);
- RawBuffer tmp = enc.Finalize();
- std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
- return result;
-}
-
-RawBuffer CryptoLogic::decryptDataAesCbc(
- const RawBuffer &data,
- const RawBuffer &key,
- const RawBuffer &iv) const
-{
- Crypto::Cipher::AesCbcDecryption dec(key, iv);
- RawBuffer result = dec.Append(data);
- RawBuffer tmp = dec.Finalize();
- std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
- return result;
-}
-
-std::pair<RawBuffer,RawBuffer> CryptoLogic::encryptDataAesGcm(
- const RawBuffer &data,
- const RawBuffer &key,
- const RawBuffer &iv) const
-{
- RawBuffer tag(AES_GCM_TAG_SIZE);
- Crypto::Cipher::AesGcmEncryption enc(key, iv);
- RawBuffer result = enc.Append(data);
- RawBuffer tmp = enc.Finalize();
- std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
- if (0 == enc.Control(EVP_CTRL_GCM_GET_TAG, AES_GCM_TAG_SIZE, tag.data())) {
- LogError("Error in aes control function. Get tag failed.");
- ThrowMsg(Exception::EncryptDBRowError, "Error in aes control function. Get tag failed.");
- }
- return std::make_pair(result, tag);
+ m_keyMap[smackLabel] = applicationKey;
}
-RawBuffer CryptoLogic::decryptDataAesGcm(
- const RawBuffer &data,
- const RawBuffer &key,
- const RawBuffer &iv,
- const RawBuffer &tag) const
+void CryptoLogic::removeKey(const Label &smackLabel)
{
- Crypto::Cipher::AesGcmDecryption dec(key, iv);
- if (tag.size() < AES_GCM_TAG_SIZE) {
- LogError("Error in decryptDataAesGcm. Tag is too short.");
- ThrowMsg(Exception::DecryptDBRowError, "Error in decryptDataAesGcm. Tag is too short");
- }
- void *ptr = (void*)tag.data();
- if (0 == dec.Control(EVP_CTRL_GCM_SET_TAG, AES_GCM_TAG_SIZE, ptr)) {
- LogError("Error in aes control function. Set tag failed.");
- ThrowMsg(Exception::DecryptDBRowError, "Error in aes control function. Set tag failed.");
- }
- RawBuffer result = dec.Append(data);
- RawBuffer tmp = dec.Finalize();
- std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
- return result;
+ m_keyMap.erase(smackLabel);
}
RawBuffer CryptoLogic::passwordToKey(
result.size(),
result.data()))
{
- ThrowMsg(Exception::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
+ ThrowErr(Exc::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
}
+
return result;
}
RawBuffer civ(EVP_MAX_IV_LENGTH);
if (1 != RAND_bytes(civ.data(), civ.size())) {
- ThrowMsg(Exception::InternalError,
- "RAND_bytes failed to generate IV.");
+ ThrowErr(Exc::InternalError, "RAND_bytes failed to generate IV.");
}
return civ;
}
-void CryptoLogic::encryptRow(const Password &password, DBRow &row)
+void CryptoLogic::encryptRow(DB::Row &row)
{
try {
- DBRow crow = row;
+ DB::Row crow = row;
RawBuffer key;
RawBuffer result1;
RawBuffer result2;
crow.dataSize = crow.data.size();
if (crow.dataSize <= 0) {
- ThrowMsg(Exception::EncryptDBRowError, "Invalid dataSize.");
+ ThrowErr(Exc::InternalError, "Invalid dataSize.");
}
- if (!haveKey(row.smackLabel)) {
- ThrowMsg(Exception::EncryptDBRowError, "Missing application key for " <<
- row.smackLabel << " label.");
+ if (!haveKey(row.ownerLabel)) {
+ ThrowErr(Exc::InternalError, "Missing application key for ",
+ row.ownerLabel, " label.");
}
if (crow.iv.empty()) {
crow.iv = generateRandIV();
}
- key = m_keyMap[row.smackLabel];
+ key = m_keyMap[row.ownerLabel];
crow.encryptionScheme = ENCR_APPKEY;
- auto dataPair = encryptDataAesGcm(crow.data, key, crow.iv);
+ auto dataPair = Crypto::SW::Internals::encryptDataAesGcm(key, crow.data, crow.iv, AES_GCM_TAG_SIZE);
crow.data = dataPair.first;
- crow.tag = dataPair.second;
- if (!password.empty()) {
- key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
- crow.data = encryptDataAesCbc(crow.data, key, crow.iv);
- crow.encryptionScheme |= ENCR_PASSWORD;
- }
+ crow.tag = dataPair.second;
encBase64(crow.data);
crow.encryptionScheme |= ENCR_BASE64;
encBase64(crow.iv);
- row = crow;
+ crow.encryptionScheme &= ENCR_ORDER_CLEAR;
+ crow.encryptionScheme |= ENCR_ORDER_V2;
+
+ row = std::move(crow);
} catch(const CKM::Base64Encoder::Exception::Base &e) {
- LogDebug("Base64Encoder error: " << e.GetMessage());
- ThrowMsg(Exception::Base64EncoderError, e.GetMessage());
+ ThrowErr(Exc::InternalError, e.GetMessage());
} catch(const CKM::Base64Decoder::Exception::Base &e) {
- LogDebug("Base64Encoder error: " << e.GetMessage());
- ThrowMsg(Exception::Base64DecoderError, e.GetMessage());
- } catch(const CKM::Crypto::Exception::Base &e) {
- LogDebug("Crypto error: " << e.GetMessage());
- ThrowMsg(Exception::EncryptDBRowError, e.GetMessage());
+ ThrowErr(Exc::InternalError, e.GetMessage());
}
}
-void CryptoLogic::decryptRow(const Password &password, DBRow &row)
+int CryptoLogic::getSchemeVersion(int encryptionScheme)
+{
+ return encryptionScheme >> ENCR_ORDER_OFFSET;
+}
+
+void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
{
try {
- DBRow crow = row;
+ DB::Row crow = row;
RawBuffer key;
RawBuffer digest, dataDigest;
if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
- ThrowMsg(Exception::DecryptDBRowError, "Invalid algorithm type.");
+ ThrowErr(Exc::AuthenticationFailed, "Invalid algorithm type.");
}
if ((row.encryptionScheme & ENCR_PASSWORD) && password.empty()) {
- ThrowMsg(Exception::DecryptDBRowError,
+ ThrowErr(Exc::AuthenticationFailed,
"DB row is password protected, but given password is "
"empty.");
}
- if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.smackLabel)) {
- ThrowMsg(Exception::DecryptDBRowError, "Missing application key for " <<
- row.smackLabel << " label.");
+ if ((row.encryptionScheme & ENCR_APPKEY) && !haveKey(row.ownerLabel)) {
+ ThrowErr(Exc::AuthenticationFailed, "Missing application key for ",
+ row.ownerLabel, " label.");
}
decBase64(crow.iv);
decBase64(crow.data);
}
- if (crow.encryptionScheme & ENCR_PASSWORD) {
- key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
- crow.data = decryptDataAesCbc(crow.data, key, crow.iv);
- }
-
- if (crow.encryptionScheme & ENCR_APPKEY) {
- key = m_keyMap[crow.smackLabel];
- crow.data = decryptDataAesGcm(crow.data, key, crow.iv, crow.tag);
+ if((crow.encryptionScheme >> ENCR_ORDER_OFFSET) == ENCR_ORDER_V2) {
+ if (crow.encryptionScheme & ENCR_APPKEY) {
+ key = m_keyMap[crow.ownerLabel];
+ crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
+ }
+ } else {
+ if (crow.encryptionScheme & ENCR_PASSWORD) {
+ key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
+ crow.data = Crypto::SW::Internals::decryptDataAes(AlgoType::AES_CBC, key, crow.data, crow.iv);
+ }
+
+ if (crow.encryptionScheme & ENCR_APPKEY) {
+ key = m_keyMap[crow.ownerLabel];
+ crow.data = Crypto::SW::Internals::decryptDataAesGcm(key, crow.data, crow.iv, crow.tag);
+ }
}
-
if (static_cast<int>(crow.data.size()) < crow.dataSize) {
- ThrowMsg(Exception::DecryptDBRowError,
- "Decrypted row size mismatch");
- LogError("Decryption row size mismatch");
+ ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
}
if (static_cast<int>(crow.data.size()) > crow.dataSize) {
crow.data.resize(crow.dataSize);
}
- row = crow;
+ row = std::move(crow);
} catch(const CKM::Base64Encoder::Exception::Base &e) {
- LogDebug("Base64Encoder error: " << e.GetMessage());
- ThrowMsg(Exception::Base64EncoderError, e.GetMessage());
+ ThrowErr(Exc::InternalError, e.GetMessage());
} catch(const CKM::Base64Decoder::Exception::Base &e) {
- LogDebug("Base64Encoder error: " << e.GetMessage());
- ThrowMsg(Exception::Base64DecoderError, e.GetMessage());
- } catch(const CKM::Crypto::Exception::Base &e) {
- LogDebug("Crypto error: " << e.GetMessage());
- ThrowMsg(Exception::DecryptDBRowError, e.GetMessage());
+ ThrowErr(Exc::InternalError, e.GetMessage());
+ } catch(const Exc::Exception &e) {
+ ThrowErr(Exc::AuthenticationFailed, e.message());
}
}
encdata = benc.get();
if (encdata.size() == 0) {
- ThrowMsg(Exception::Base64EncoderError, "Base64Encoder returned empty data.");
+ ThrowErr(Exc::InternalError, "Base64Encoder returned empty data.");
}
data = std::move(encdata);
bdec.reset();
bdec.append(data);
- if (not bdec.finalize()) {
- ThrowMsg(Exception::Base64DecoderError,
- "Failed in Base64Decoder.finalize.");
+ if (!bdec.finalize()) {
+ ThrowErr(Exc::InternalError, "Failed in Base64Decoder.finalize.");
}
decdata = bdec.get();
if (decdata.size() == 0) {
- ThrowMsg(Exception::Base64DecoderError, "Base64Decoder returned empty data.");
+ ThrowErr(Exc::InternalError, "Base64Decoder returned empty data.");
}
data = std::move(decdata);