Change AES CBC mode into AES GCM.
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Tue, 9 Sep 2014 11:54:36 +0000 (13:54 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Fri, 12 Sep 2014 12:59:34 +0000 (14:59 +0200)
Change-Id: I1335d6fdb61ca29e8dfcdcd4901b485fb4ebf4ec

src/include/ckm/ckm-type.h
src/manager/common/crypto.h
src/manager/service/ckm-logic.cpp [changed mode: 0755->0644]
src/manager/service/crypto-logic.cpp
src/manager/service/crypto-logic.h
src/manager/service/db-crypto.cpp
src/manager/service/db-row.h
tests/test_db_crypto.cpp

index 75a5338..cac447a 100644 (file)
@@ -91,7 +91,7 @@ enum class RSAPaddingAlgorithm : int {
 
 enum class DBCMAlgType : int {
     NONE,
-    AES_CBC_256,
+    AES_GCM_256,
     COUNT
 };
 
index 0a5e22b..1c6009c 100644 (file)
@@ -27,6 +27,9 @@
 #include <vector>
 #include <dpl/raw-buffer.h>
 
+// TODO move it to static const int
+#define AES_GCM_TAG_SIZE 16
+
 namespace CKM {
 
 namespace Crypto {
@@ -52,6 +55,12 @@ struct Base {
     Base<T>& operator=(const Base&) = delete;
     Base<T>& operator=(Base &&) = delete;
 
+    // Low level api.
+    // Allows various cipher specific parameters to be determined and set.
+    int Control(int type, int arg, void *ptr) {
+        return EVP_CIPHER_CTX_ctrl(m_ctx, type, arg, ptr);
+    }
+
     virtual T Append(const T&) = 0;
     virtual T Finalize() = 0;
     virtual ~Base(){
@@ -124,6 +133,8 @@ public:                                                               \
 
 DEFINE_CIPHER(AesCbcEncryption, RawBuffer, EVP_aes_256_cbc(), true);
 DEFINE_CIPHER(AesCbcDecryption, RawBuffer, EVP_aes_256_cbc(), false);
+DEFINE_CIPHER(AesGcmEncryption, RawBuffer, EVP_aes_256_gcm(), true);
+DEFINE_CIPHER(AesGcmDecryption, RawBuffer, EVP_aes_256_gcm(), false);
 
 #undef DEFINE_CIPHER
 
old mode 100755 (executable)
new mode 100644 (file)
index bedabd7..587d9bb
@@ -215,7 +215,7 @@ int CKMLogic::saveDataHelper(
 
     DBRow row = { alias, cred.smackLabel, policy.restricted,
          policy.extractable, dataType, DBCMAlgType::NONE,
-         0, RawBuffer(), static_cast<int>(key.size()), key };
+         0, RawBuffer(), static_cast<int>(key.size()), key, RawBuffer() };
 
     auto &handler = m_userDataMap[cred.uid];
     DBCrypto::Transaction transaction(&handler.database);
index 11e8c82..26d8917 100644 (file)
@@ -75,54 +75,63 @@ void CryptoLogic::pushKey(const std::string &smackLabel,
     m_keyMap[smackLabel] = applicationKey;
 }
 
-std::size_t CryptoLogic::insertDigest(RawBuffer &data, const int dataSize)
+RawBuffer CryptoLogic::encryptDataAesCbc(
+    const RawBuffer &data,
+    const RawBuffer &key,
+    const RawBuffer &iv) const
 {
-    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();
+    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;
 }
 
-void CryptoLogic::removeDigest(RawBuffer &data, RawBuffer &digest)
+RawBuffer CryptoLogic::decryptDataAesCbc(
+    const RawBuffer &data,
+    const RawBuffer &key,
+    const RawBuffer &iv) const
 {
-    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);
+    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;
 }
 
-RawBuffer CryptoLogic::encryptData(
+std::pair<RawBuffer,RawBuffer> CryptoLogic::encryptDataAesGcm(
     const RawBuffer &data,
     const RawBuffer &key,
     const RawBuffer &iv) const
 {
-    Crypto::Cipher::AesCbcEncryption enc(key, iv);
+    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));
-    return 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);
 }
 
-RawBuffer CryptoLogic::decryptData(
+RawBuffer CryptoLogic::decryptDataAesGcm(
     const RawBuffer &data,
     const RawBuffer &key,
-    const RawBuffer &iv) const
+    const RawBuffer &iv,
+    const RawBuffer &tag) const
 {
-    Crypto::Cipher::AesCbcDecryption dec(key, iv);
+    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));
@@ -169,7 +178,8 @@ void CryptoLogic::encryptRow(const Password &password, DBRow &row)
         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.");
@@ -187,12 +197,13 @@ void CryptoLogic::encryptRow(const Password &password, DBRow &row)
         key = m_keyMap[row.smackLabel];
         crow.encryptionScheme = ENCR_APPKEY;
 
-        insertDigest(crow.data, crow.dataSize);
-        crow.data = encryptData(crow.data, key, crow.iv);
+        auto dataPair = encryptDataAesGcm(crow.data, key, crow.iv);
+        crow.data = dataPair.first;
+        crow.tag = dataPair.second;
 
         if (!password.empty()) {
             key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
-            crow.data = encryptData(crow.data, key, crow.iv);
+            crow.data = encryptDataAesCbc(crow.data, key, crow.iv);
             crow.encryptionScheme |= ENCR_PASSWORD;
         }
 
@@ -220,7 +231,7 @@ void CryptoLogic::decryptRow(const Password &password, DBRow &row)
         RawBuffer key;
         RawBuffer digest, dataDigest;
 
-        if (row.algorithmType != DBCMAlgType::AES_CBC_256) {
+        if (row.algorithmType != DBCMAlgType::AES_GCM_256) {
             ThrowMsg(Exception::DecryptDBRowError, "Invalid algorithm type.");
         }
 
@@ -242,29 +253,24 @@ void CryptoLogic::decryptRow(const Password &password, DBRow &row)
 
         if (crow.encryptionScheme & ENCR_PASSWORD) {
             key = passwordToKey(password, crow.iv, AES_CBC_KEY_SIZE);
-            crow.data = decryptData(crow.data, key, crow.iv);
+            crow.data = decryptDataAesCbc(crow.data, key, crow.iv);
         }
 
         if (crow.encryptionScheme & ENCR_APPKEY) {
             key = m_keyMap[crow.smackLabel];
-            crow.data = decryptData(crow.data, key, crow.iv);
+            crow.data = decryptDataAesGcm(crow.data, key, crow.iv, crow.tag);
         }
 
-        removeDigest(crow.data, digest);
-
-        if (static_cast<std::size_t>(crow.dataSize) != crow.data.size()) {
+        if (static_cast<int>(crow.data.size()) < crow.dataSize) {
             ThrowMsg(Exception::DecryptDBRowError,
-              "Decrypted db row data size mismatch.");
+                "Decrypted row size mismatch");
+            LogError("Decryption row size mismatch");
         }
 
-        Digest dig;
-        dig.append(crow.data);
-        dataDigest = dig.finalize();
-
-        if (not equalDigests(digest, dataDigest)) {
-            ThrowMsg(Exception::DecryptDBRowError,
-              "Decrypted db row data digest mismatch.");
+        if (static_cast<int>(crow.data.size()) > crow.dataSize) {
+            crow.data.resize(crow.dataSize);
         }
+
         row = crow;
     } catch(const CKM::Base64Encoder::Exception::Base &e) {
         LogDebug("Base64Encoder error: " << e.GetMessage());
index 0a98b30..e524766 100644 (file)
@@ -67,21 +67,30 @@ private:
                             const RawBuffer &salt,
                             size_t keySize) const;
 
-    RawBuffer encryptData(
+    RawBuffer encryptDataAesCbc(
         const RawBuffer &data,
         const RawBuffer &key,
         const RawBuffer &iv) const;
 
-    RawBuffer decryptData(
+    RawBuffer decryptDataAesCbc(
         const RawBuffer &data,
         const RawBuffer &key,
         const RawBuffer &iv) const;
 
+    std::pair<RawBuffer, RawBuffer> encryptDataAesGcm(
+        const RawBuffer &data,
+        const RawBuffer &key,
+        const RawBuffer &iv) const;
+
+    RawBuffer decryptDataAesGcm(
+        const RawBuffer &data,
+        const RawBuffer &key,
+        const RawBuffer &iv,
+        const RawBuffer &tag) const;
+
     void decBase64(RawBuffer &data);
     void encBase64(RawBuffer &data);
     bool equalDigests(RawBuffer &dig1, RawBuffer &dig2);
-    std::size_t insertDigest(RawBuffer &data, const int dataSize);
-    void removeDigest(RawBuffer &data, RawBuffer &digest);
 };
 
 } // namespace CKM
index 2507252..09d490e 100644 (file)
@@ -47,6 +47,7 @@ namespace {
             "   iv BLOB NOT NULL,"
             "   dataSize INTEGER NOT NULL,"
             "   data BLOB NOT NULL,"
+            "   tag BLOB NOT NULL,"
             "   PRIMARY KEY(alias, label),"
             "   UNIQUE(alias, restricted)"
             ");";
@@ -58,10 +59,10 @@ namespace {
             "   alias, label, restricted, exportable,"
             //      5           6           7
             "   dataType, algorithmType, encryptionScheme,"
-            //  8       9       10
-            "   iv, dataSize, data) "
+            //  8       9      10   11
+            "   iv, dataSize, data, tag) "
             "VALUES("
-            "   ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
+            "   ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";
 
     const char *select_alias_cmd =
             //                                   1              2                            3
@@ -258,6 +259,7 @@ using namespace DB;
             insertCommand->BindBlob(8, row.iv);
             insertCommand->BindInteger(9, row.dataSize);
             insertCommand->BindBlob(10, row.data);
+            insertCommand->BindBlob(11, row.tag);
 
             insertCommand->Step();
             transaction.commit();
@@ -284,6 +286,7 @@ using namespace DB;
         row.iv = selectCommand->GetColumnBlob(7);
         row.dataSize = selectCommand->GetColumnInteger(8);
         row.data = selectCommand->GetColumnBlob(9);
+        row.tag = selectCommand->GetColumnBlob(10);
         return row;
     }
 
index 0a03e25..ecb1ccd 100644 (file)
@@ -17,7 +17,7 @@ namespace CKM {
         RawBuffer iv;               // encoded in base64
         int dataSize;               // size of information without hash and padding
         RawBuffer data;
+        RawBuffer tag;              // tag for Aes Gcm algorithm
     };
 } // namespace CKM
 
-
index 95bcefa..2f3009c 100644 (file)
@@ -27,7 +27,7 @@ DBRow createDefaultRow(int restricted = restricted_local,
     row.smackLabel = default_label;
     row.exportable = 1;
     row.restricted = restricted;
-    row.algorithmType = DBCMAlgType::AES_CBC_256;
+    row.algorithmType = DBCMAlgType::AES_GCM_256;
     row.dataType = type;
     row.iv = createDefaultPass();
     row.encryptionScheme = 0;