Modify encryption scheme
[platform/core/security/key-manager.git] / src / manager / service / crypto-logic.cpp
index 8dc4585..c7b8786 100644 (file)
@@ -22,6 +22,9 @@
 
 #include <iostream>
 #include <fstream>
+#include <utility>
+#include <climits>
+
 #include <stdio.h>
 #include <string.h>
 
 #include <digest.h>
 #include <crypto-logic.h>
 
-#include <sw-backend/crypto.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);
@@ -61,82 +90,25 @@ bool CryptoLogic::haveKey(const Label &smackLabel)
 }
 
 void CryptoLogic::pushKey(const Label &smackLabel,
-                            const RawBuffer &applicationKey)
+                          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::SW::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::SW::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::SW::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::SW::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(
@@ -155,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;
 }
 
@@ -164,14 +137,13 @@ 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 Password &password, DB::Row &row)
+void CryptoLogic::encryptRow(DB::Row &row)
 {
     try {
         DB::Row crow = row;
@@ -183,12 +155,12 @@ void CryptoLogic::encryptRow(const Password &password, DB::Row &row)
         crow.dataSize = crow.data.size();
 
         if (crow.dataSize <= 0) {
-            ThrowMsg(Exception::EncryptDBRowError, "Invalid dataSize.");
+            ThrowErr(Exc::InternalError, "Invalid dataSize.");
         }
 
         if (!haveKey(row.ownerLabel)) {
-            ThrowMsg(Exception::EncryptDBRowError, "Missing application key for " <<
-              row.ownerLabel << " label.");
+            ThrowErr(Exc::InternalError, "Missing application key for ",
+              row.ownerLabel, " label.");
         }
 
         if (crow.iv.empty()) {
@@ -198,33 +170,31 @@ void CryptoLogic::encryptRow(const Password &password, DB::Row &row)
         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());
     }
 }
 
+int CryptoLogic::getSchemeVersion(int encryptionScheme)
+{
+    return encryptionScheme >> ENCR_ORDER_OFFSET;
+}
+
 void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
 {
     try {
@@ -233,18 +203,18 @@ void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
         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.ownerLabel)) {
-            ThrowMsg(Exception::DecryptDBRowError, "Missing application key for " <<
-              row.ownerLabel << " label.");
+            ThrowErr(Exc::AuthenticationFailed, "Missing application key for ",
+              row.ownerLabel, " label.");
         }
 
         decBase64(crow.iv);
@@ -252,36 +222,37 @@ void CryptoLogic::decryptRow(const Password &password, DB::Row &row)
             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.ownerLabel];
-            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());
     }
 }
 
@@ -295,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);
@@ -308,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);