Modify encryption scheme
[platform/core/security/key-manager.git] / src / manager / service / crypto-logic.cpp
index a9d8d63..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,87 +84,39 @@ 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 SafeBuffer &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(SafeBuffer &data, const int dataSize)
-{
-    SafeBuffer 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(SafeBuffer &data, SafeBuffer &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);
-}
-
-SafeBuffer CryptoLogic::encryptData(
-    const SafeBuffer &data,
-    const SafeBuffer &key,
-    const SafeBuffer &iv) const
-{
-    Crypto::Cipher::AesCbcEncryption enc(key, iv);
-    SafeBuffer result = enc.Append(data);
-    SafeBuffer tmp = enc.Finalize();
-    std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
-    return result;
+    m_keyMap[smackLabel] = applicationKey;
 }
 
-SafeBuffer CryptoLogic::decryptData(
-    const SafeBuffer &data,
-    const SafeBuffer &key,
-    const SafeBuffer &iv) const
+void CryptoLogic::removeKey(const Label &smackLabel)
 {
-    Crypto::Cipher::AesCbcDecryption dec(key, iv);
-    SafeBuffer result = dec.Append(data);
-    SafeBuffer tmp = dec.Finalize();
-    std::copy(tmp.begin(), tmp.end(), std::back_inserter(result));
-    return result;
+    m_keyMap.erase(smackLabel);
 }
 
-SafeBuffer CryptoLogic::passwordToKey(
-    const std::string &password,
-    const SafeBuffer &salt,
+RawBuffer CryptoLogic::passwordToKey(
+    const Password &password,
+    const RawBuffer &salt,
     size_t keySize) const
 {
-    SafeBuffer result(keySize);
+    RawBuffer result(keySize);
 
     if (1 != PKCS5_PBKDF2_HMAC_SHA1(
                 password.c_str(),
@@ -145,94 +127,94 @@ SafeBuffer CryptoLogic::passwordToKey(
                 result.size(),
                 result.data()))
     {
-        ThrowMsg(Exception::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
+        ThrowErr(Exc::InternalError, "PCKS5_PKKDF_HMAC_SHA1 failed.");
     }
+
     return result;
 }
 
-SafeBuffer CryptoLogic::generateRandIV() const {
-    SafeBuffer civ(EVP_MAX_IV_LENGTH);
+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;
-        SafeBuffer key;
-        SafeBuffer result1;
-        SafeBuffer result2;
+        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;
-        SafeBuffer key;
-        SafeBuffer digest, dataDigest;
+        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,82 +222,77 @@ 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());
     }
 }
 
-void CryptoLogic::encBase64(SafeBuffer &data)
+void CryptoLogic::encBase64(RawBuffer &data)
 {
     Base64Encoder benc;
-    SafeBuffer encdata;
+    RawBuffer encdata;
 
     benc.append(data);
     benc.finalize();
     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);
 }
 
-void CryptoLogic::decBase64(SafeBuffer &data)
+void CryptoLogic::decBase64(RawBuffer &data)
 {
     Base64Decoder bdec;
-    SafeBuffer decdata;
+    RawBuffer decdata;
 
     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);
 }
 
-bool CryptoLogic::equalDigests(SafeBuffer &dig1, SafeBuffer &dig2)
+bool CryptoLogic::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
 {
     unsigned int dlen = Digest().length();