Modify encryption scheme
[platform/core/security/key-manager.git] / src / manager / service / crypto-logic.cpp
index 4b71210..c7b8786 100644 (file)
@@ -22,6 +22,9 @@
 
 #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);
@@ -54,83 +84,35 @@ CryptoLogic& CryptoLogic::operator=(CryptoLogic &&second) {
     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;
-}
-
-std::size_t CryptoLogic::insertDigest(RawBuffer &data, const int dataSize)
-{
-    RawBuffer digest;
-
-    try {
-        Digest dig;
-        dig.append(data, dataSize);
-        digest = dig.finalize();
-    } catch (Digest::Exception::Base &e) {
-        LogError("Failed to calculate digest in insertDigest: " <<
-                 e.DumpToString());
-        ThrowMsg(Exception::InternalError, e.GetMessage());
-    }
-    data.insert(data.begin(), digest.begin(), digest.end());
-    return digest.size();
-}
 
-void CryptoLogic::removeDigest(RawBuffer &data, RawBuffer &digest)
-{
-    unsigned int dlen = Digest().length();
-
-    if (data.size() < dlen) {
-        ThrowMsg(Exception::InternalError,
-                 "Cannot remove digest: data size mismatch.");
-    }
-
-    digest.assign(data.begin(), data.begin() + dlen);
-    data.erase(data.begin(), data.begin() + dlen);
-}
-
-RawBuffer CryptoLogic::encryptData(
-    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;
+    m_keyMap[smackLabel] = applicationKey;
 }
 
-RawBuffer CryptoLogic::decryptData(
-    const RawBuffer &data,
-    const RawBuffer &key,
-    const RawBuffer &iv) const
+void CryptoLogic::removeKey(const Label &smackLabel)
 {
-    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;
+    m_keyMap.erase(smackLabel);
 }
 
 RawBuffer CryptoLogic::passwordToKey(
-    const std::string &password,
+    const Password &password,
     const RawBuffer &salt,
     size_t keySize) const
 {
@@ -145,8 +127,9 @@ 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;
 }
 
@@ -154,85 +137,84 @@ RawBuffer CryptoLogic::generateRandIV() const {
     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 std::string &password, DBRow &row)
+void CryptoLogic::encryptRow(DB::Row &row)
 {
     try {
-        DBRow crow = row;
+        DB::Row crow = row;
         RawBuffer key;
         RawBuffer result1;
         RawBuffer result2;
 
-        crow.algorithmType = DBCMAlgType::AES_CBC_256;
+        crow.algorithmType = DBCMAlgType::AES_GCM_256;
+        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;
 
-        insertDigest(crow.data, crow.dataSize);
-        crow.data = encryptData(crow.data, key, crow.iv);
+        auto dataPair = Crypto::SW::Internals::encryptDataAesGcm(key, crow.data, crow.iv, AES_GCM_TAG_SIZE);
+        crow.data = dataPair.first;
 
-        if (!password.empty()) {
-            key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
-            crow.data = encryptData(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 std::string &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_CBC_256) {
-            ThrowMsg(Exception::DecryptDBRowError, "Invalid algorithm type.");
+        if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
+            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);
@@ -240,41 +222,37 @@ void CryptoLogic::decryptRow(const std::string &password, DBRow &row)
             decBase64(crow.data);
         }
 
-        if (crow.encryptionScheme & ENCR_PASSWORD) {
-            key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
-            crow.data = decryptData(crow.data, key, crow.iv);
+        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 (crow.encryptionScheme & ENCR_APPKEY) {
-            key = m_keyMap[crow.smackLabel];
-            crow.data = decryptData(crow.data, key, crow.iv);
+        if (static_cast<int>(crow.data.size()) < crow.dataSize) {
+            ThrowErr(Exc::AuthenticationFailed, "Decrypted row size mismatch");
         }
 
-        removeDigest(crow.data, digest);
-
-        if (static_cast<std::size_t>(crow.dataSize) != crow.data.size()) {
-            ThrowMsg(Exception::DecryptDBRowError,
-              "Decrypted db row data size mismatch.");
+        if (static_cast<int>(crow.data.size()) > crow.dataSize) {
+            crow.data.resize(crow.dataSize);
         }
 
-        Digest dig;
-        dig.append(crow.data);
-        dataDigest = dig.finalize();
-
-        if (not equalDigests(digest, dataDigest)) {
-            ThrowMsg(Exception::DecryptDBRowError,
-              "Decrypted db row data digest mismatch.");
-        }
-        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());
     }
 }
 
@@ -288,7 +266,7 @@ void CryptoLogic::encBase64(RawBuffer &data)
     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);
@@ -301,15 +279,14 @@ void CryptoLogic::decBase64(RawBuffer &data)
 
     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);