Added initial version of aesCrypt and Digest modules.
authorSebastian Grabowski <s.grabowski@samsung.com>
Mon, 16 Jun 2014 13:33:34 +0000 (15:33 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Fri, 12 Sep 2014 12:58:49 +0000 (14:58 +0200)
Added new classes for handling AES encryption and digest calculation.

Change-Id: Ic538130ff86eb53ee5c0446212e1cf628cca708e

src/manager/CMakeLists.txt
src/manager/common/aesCrypt.cpp [new file with mode: 0644]
src/manager/common/aesCrypt.h [new file with mode: 0644]
src/manager/common/digest.cpp [new file with mode: 0644]
src/manager/common/digest.h [new file with mode: 0644]
src/manager/service/DBCryptoModule.cpp
src/manager/service/DBCryptoModule.h
src/manager/service/ckm-logic.cpp

index 0db7ff3..d8772cd 100644 (file)
@@ -16,6 +16,8 @@ SET(COMMON_PATH ${PROJECT_SOURCE_DIR}/src/manager)
 
 SET(COMMON_SOURCES
     ${COMMON_PATH}/common/base64.cpp
+    ${COMMON_PATH}/common/digest.cpp
+    ${COMMON_PATH}/common/aesCrypt.cpp
     ${COMMON_PATH}/common/protocols.cpp
     ${COMMON_PATH}/common/message-buffer.cpp
     ${COMMON_PATH}/common/smack-check.cpp
diff --git a/src/manager/common/aesCrypt.cpp b/src/manager/common/aesCrypt.cpp
new file mode 100644 (file)
index 0000000..46bcf52
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <features.h>
+
+#include <dpl/log/log.h>
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+#include <aesCrypt.h>
+
+namespace CKM {
+
+CryptoAlgConf::CryptoAlgConf(const EVP_CIPHER *cipher) :
+    m_key(EVP_MAX_KEY_LENGTH),
+    m_salt(PKCS5_SALT_LEN)
+{
+    preinit(cipher);
+}
+
+CryptoAlgConf::CryptoAlgConf(const EVP_CIPHER *cipher, std::string &password) :
+    m_key(EVP_MAX_KEY_LENGTH),
+    m_salt(PKCS5_SALT_LEN)
+{
+    preinit(cipher);
+    if (not password.empty())
+        generateKey(password);
+}
+
+CryptoAlgConf::~CryptoAlgConf()
+{
+}
+
+const EVP_CIPHER *CryptoAlgConf::getCipher(void)
+{
+    return m_cipher;
+}
+
+void CryptoAlgConf::generateKey(std::string &password, bool use_iv)
+{
+    int ret = -1;
+
+    if (password.empty()) {
+        ThrowMsg(Exception::InternalError, "Password is empty.");
+    }
+    if (not use_iv)
+        generateRandIV();
+    ret = PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.length(), NULL, 0,
+                                 m_pkcs5_password_iter, m_keyLen,
+                                 m_key.data());
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "PKCS5_PBKDF2_HMAC_SHA1 has failed.");
+    }
+}
+
+void CryptoAlgConf::generateRandIV()
+{
+    RawBuffer civ(EVP_MAX_IV_LENGTH);
+
+    if (RAND_bytes(civ.data(), civ.size()) != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "RAND_bytes failed to generate IV.");
+    }
+    m_iv = civ;
+}
+
+void CryptoAlgConf::setKey(const RawBuffer &key)
+{
+    if (key.size() != m_keyLen) {
+        ThrowMsg(Exception::InternalError, "Invalid key length.");
+    }
+    m_key = key;
+}
+
+void CryptoAlgConf::setIV(const RawBuffer &iv)
+{
+    if ((iv.size() != m_ivLen) && (iv.size() != 0)) {
+        ThrowMsg(Exception::InternalError, "Invalid IV length.");
+    }
+    m_iv = iv;
+}
+
+void CryptoAlgConf::setSalt(const RawBuffer &salt)
+{
+    if (salt.size() != m_saltLen) {
+        ThrowMsg(Exception::InternalError, "Invalid salt length.");
+    }
+    m_salt = salt;
+}
+
+RawBuffer CryptoAlgConf::getKey()
+{
+    return m_key;
+}
+
+RawBuffer CryptoAlgConf::getIV()
+{
+    return m_iv;
+}
+
+RawBuffer CryptoAlgConf::getSalt()
+{
+    return m_salt;
+}
+
+void CryptoAlgConf::preinit(const EVP_CIPHER *cipher)
+{
+    m_cipher = cipher;
+    if (m_cipher == nullptr)
+        m_cipher = EVP_aes_256_cbc();
+    m_keyLen = EVP_CIPHER_key_length(m_cipher);
+    m_ivLen = EVP_CIPHER_iv_length(m_cipher);
+    m_saltLen = PKCS5_SALT_LEN;
+    m_key.resize(m_keyLen);
+    m_pkcs5_password_iter = 1024;
+    generateRandIV();
+}
+
+std::size_t CryptoAlgConf::maxBufLen(std::size_t len)
+{
+    return len + EVP_CIPHER_block_size(m_cipher);
+}
+
+/******************************************************************************
+ *****************************************************************************/
+
+AesCrypt::AesCrypt(AESCryptMode mode, std::string password) :
+    conf(nullptr, password)
+{
+    m_ctx = nullptr;
+    if ((mode != AESCryptMode::ENCODER) && (mode != AESCryptMode::DECODER)) {
+        ThrowMsg(Exception::InternalError,
+                 "Unknown mode of crypto operations.");
+    } else
+        m_mode = mode;
+    m_initialized = false;
+    m_finalized = false;
+    m_padding = true;
+    if (m_mode == AESCryptMode::ENCODER) {
+        m_fInit = EVP_EncryptInit_ex;
+        m_fUpdate = EVP_EncryptUpdate;
+        m_fFinal = EVP_EncryptFinal_ex;
+    } else {
+        m_fInit = EVP_DecryptInit_ex;
+        m_fUpdate = EVP_DecryptUpdate;
+        m_fFinal = EVP_DecryptFinal_ex;
+    }
+}
+
+AesCrypt::~AesCrypt()
+{
+    EVP_CIPHER_CTX_free(m_ctx);
+}
+
+void AesCrypt::reset()
+{
+    int ret = -1;
+
+    if (m_initialized) {
+        EVP_CIPHER_CTX_free(m_ctx);
+        m_ctx = nullptr;
+    }
+    m_initialized = false;
+    m_finalized = false;
+    m_ctx = EVP_CIPHER_CTX_new();
+    if (m_ctx == nullptr) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed to alloc security context.");
+    }
+    ret = m_fInit(m_ctx, conf.getCipher(), NULL, conf.getKey().data(),
+                  conf.getIV().data());
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed to initialize encryption in openssl.");
+    }
+    if (m_padding)
+        EVP_CIPHER_CTX_set_padding(m_ctx, 1);
+    m_bufWritePos = 0;
+    m_buf.clear();
+    m_initialized = true;
+}
+
+RawBuffer AesCrypt::finalize()
+{
+    int ret = -1;
+    int outlf;
+
+    if (not m_initialized) {
+        ThrowMsg(Exception::InternalError, "Not initialized.");
+    }
+    if (m_finalized) {
+        ThrowMsg(Exception::InternalError, "Already finalized.");
+    }
+    if (m_buf.size() == 0) {
+        ThrowMsg(Exception::InternalError,
+                 "Empty buffor: append() was missing?");
+    }
+    m_buf.resize(conf.maxBufLen(m_bufWritePos));
+    ret = m_fFinal(m_ctx, m_buf.data() + m_bufWritePos, &outlf);
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed to encrypt data in openssl (final)");
+    }
+    m_bufWritePos += outlf;
+    if (0 == m_bufWritePos) {
+        ThrowMsg(Exception::InternalError,
+                 "No output data.");
+    }
+    EVP_CIPHER_CTX_free(m_ctx);
+    m_ctx = nullptr;
+    m_buf.resize(m_bufWritePos);
+    m_initialized = false;
+    m_finalized = true;
+
+    return m_buf;
+}
+
+int AesCrypt::append(const RawBuffer &data)
+{
+    int ret = -1;
+    int outl = -1;
+
+    if (data.size() == 0) {
+        ThrowMsg(Exception::InternalError, "Empty data.");
+    }
+    if (m_finalized) {
+        ThrowMsg(Exception::InternalError, "Already finalized.");
+    }
+    if (not m_initialized)
+        reset();
+
+    m_buf.resize(conf.maxBufLen(data.size()));
+    ret = m_fUpdate(m_ctx, m_buf.data() + m_bufWritePos, &outl, data.data(),
+                    data.size());
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed to encrypt data in openssl");
+    }
+    m_bufWritePos += outl;
+
+    return outl;
+}
+
+RawBuffer AesCrypt::get()
+{
+    if (m_finalized)
+        return m_buf;
+    else
+        return RawBuffer();
+}
+
+AESCryptMode AesCrypt::getMode()
+{
+    return m_mode;
+}
+
+/******************************************************************************
+ *****************************************************************************/
+
+AesEncrypt::AesEncrypt() :
+    AesCrypt(AESCryptMode::ENCODER, "")
+{
+}
+
+AesEncrypt::AesEncrypt(std::string password) :
+    AesCrypt(AESCryptMode::ENCODER, password)
+{
+}
+
+AesEncrypt::~AesEncrypt()
+{
+}
+
+/******************************************************************************
+ *****************************************************************************/
+
+AesDecrypt::AesDecrypt() :
+    AesCrypt(AESCryptMode::DECODER, "")
+{
+}
+
+AesDecrypt::AesDecrypt(std::string password) :
+    AesCrypt(AESCryptMode::DECODER, password)
+{
+}
+
+AesDecrypt::~AesDecrypt()
+{
+}
+
+} // namespace CKM
+
diff --git a/src/manager/common/aesCrypt.h b/src/manager/common/aesCrypt.h
new file mode 100644 (file)
index 0000000..234a257
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <dpl/noncopyable.h>
+#include <dpl/exception.h>
+
+#include <ckm/ckm-type.h>
+
+/*
+ * Taken from openssl/ossl_typ.h
+ */
+struct evp_cipher_st;
+typedef evp_cipher_st EVP_CIPHER;
+struct evp_cipher_ctx_st;
+typedef evp_cipher_ctx_st EVP_CIPHER_CTX;
+struct engine_st;
+typedef engine_st ENGINE;
+
+namespace CKM {
+
+class CryptoAlgConf
+{
+    public:
+        class Exception
+        {
+            public:
+                DECLARE_EXCEPTION_TYPE(CKM::Exception, Base)
+                DECLARE_EXCEPTION_TYPE(Base, InternalError)
+        };
+
+        CryptoAlgConf(const EVP_CIPHER *cipher);
+        CryptoAlgConf(const EVP_CIPHER *cipher, std::string &password);
+        ~CryptoAlgConf();
+
+        const EVP_CIPHER *getCipher(void);
+        void setKey(const RawBuffer &key);
+        void setIV(const RawBuffer &iv);
+        void setSalt(const RawBuffer &salt); // TODO: not used yet
+        RawBuffer getKey(void);
+        RawBuffer getIV(void);
+        RawBuffer getSalt(void);
+        void generateKey(std::string &password, bool use_iv = false);
+        void generateRandIV(void);
+        std::size_t maxBufLen(std::size_t len);
+
+    private:
+        RawBuffer m_key;
+        RawBuffer m_iv;
+        RawBuffer m_salt; // TODO:  not used yet
+        const EVP_CIPHER *m_cipher;
+        std::size_t m_keyLen;
+        std::size_t m_ivLen;
+        std::size_t m_saltLen;
+        int m_pkcs5_password_iter;
+
+        void preinit(const EVP_CIPHER *cipher);
+};
+
+enum class AESCryptMode : int {
+    ENCODER,
+    DECODER
+};
+
+class AesCrypt : public CKM::Noncopyable
+{
+    public:
+        class Exception
+        {
+            public:
+                DECLARE_EXCEPTION_TYPE(CKM::Exception, Base)
+                DECLARE_EXCEPTION_TYPE(Base, InternalError)
+        };
+
+        AesCrypt(AESCryptMode mode, std::string password);
+        ~AesCrypt();
+
+        void reset(void);
+        RawBuffer finalize(void);
+        RawBuffer get(void);
+        int append(const RawBuffer &data);
+        AESCryptMode getMode(void);
+        CryptoAlgConf conf;
+
+    private:
+        EVP_CIPHER_CTX *m_ctx;
+        RawBuffer m_buf;
+        bool m_initialized;
+        bool m_finalized;
+        int m_bufWritePos;
+        AESCryptMode m_mode;
+        bool m_padding;
+
+        int (*m_fInit)(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
+                       ENGINE *impl, const unsigned char *key,
+                       const unsigned char *iv);
+        int (*m_fUpdate)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
+                         const unsigned char *in, int inl);
+        int (*m_fFinal)(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+};
+
+class AesEncrypt : public AesCrypt
+{
+    public:
+        AesEncrypt();
+        AesEncrypt(std::string password);
+        ~AesEncrypt();
+};
+
+class AesDecrypt : public AesCrypt
+{
+    public:
+        AesDecrypt();
+        AesDecrypt(std::string password);
+        ~AesDecrypt();
+};
+
+} // namespace CKM
+
diff --git a/src/manager/common/digest.cpp b/src/manager/common/digest.cpp
new file mode 100644 (file)
index 0000000..0bec6fc
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <dpl/log/log.h>
+
+#include <openssl/evp.h>
+
+#include <digest.h>
+
+namespace CKM {
+
+Digest::Digest() :
+    m_digest(EVP_MAX_MD_SIZE)
+{
+    m_ctx = nullptr;
+    m_md = EVP_sha1();
+    m_initialized = false;
+    m_finalized = false;
+}
+
+Digest::~Digest()
+{
+    EVP_MD_CTX_destroy(m_ctx);
+}
+
+void Digest::reset()
+{
+    int ret = -1;
+
+    if (m_initialized) {
+        EVP_MD_CTX_destroy(m_ctx);
+        m_ctx = nullptr;
+    }
+
+    m_initialized = false;
+    m_finalized = false;
+    m_ctx = EVP_MD_CTX_create();
+    if (m_ctx == nullptr) {
+    }
+
+    ret = EVP_DigestInit_ex(m_ctx, m_md, NULL);
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed to create digest context.");
+    }
+    m_digest.clear();
+    m_digest.resize(EVP_MAX_MD_SIZE);
+    m_initialized = true;
+}
+
+void Digest::append(const RawBuffer &data, std::size_t len)
+{
+    int ret = -1;
+
+    if (data.size() == 0) {
+        ThrowMsg(Exception::InternalError, "Empty data.");
+    }
+    if (0 == len)
+        len = data.size();
+    if (m_finalized) {
+        ThrowMsg(Exception::InternalError, "Already finalized.");
+    }
+    if (not m_initialized)
+        reset();
+    ret = EVP_DigestUpdate(m_ctx, data.data(), len);
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed to calculate digest in openssl.");
+    }
+}
+
+RawBuffer Digest::finalize()
+{
+    int ret = -1;
+    unsigned int dlen;
+
+    if (m_finalized) {
+        ThrowMsg(Exception::InternalError, "Already finalized.");
+    }
+    m_finalized = true;
+    ret = EVP_DigestFinal_ex(m_ctx, m_digest.data(), &dlen);
+    if (ret != 1) {
+        ThrowMsg(Exception::InternalError,
+                 "Failed in digest final in openssl.");
+    }
+    if (dlen != length()) {
+        ThrowMsg(Exception::InternalError, "Invalid digest length.");
+    }
+    if (dlen != EVP_MAX_MD_SIZE)
+        m_digest.resize(dlen);
+    return m_digest;
+}
+
+RawBuffer Digest::get()
+{
+    if (m_finalized)
+        return m_digest;
+    else
+        return RawBuffer();
+}
+
+unsigned int Digest::length()
+{
+    return m_md->md_size;
+}
+
+} // namespace CKM
+
diff --git a/src/manager/common/digest.h b/src/manager/common/digest.h
new file mode 100644 (file)
index 0000000..e890329
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#pragma once
+
+#include <dpl/noncopyable.h>
+#include <dpl/exception.h>
+#include <ckm/ckm-type.h>
+
+/*
+ * Taken from openssl/ossl_typ.h
+ */
+struct env_md_ctx_st;
+typedef env_md_ctx_st EVP_MD_CTX;
+struct env_md_st;
+typedef env_md_st EVP_MD;
+
+namespace CKM {
+
+class Digest : public CKM::Noncopyable
+{
+    public:
+        class Exception
+        {
+            public:
+                DECLARE_EXCEPTION_TYPE(CKM::Exception, Base)
+                DECLARE_EXCEPTION_TYPE(Base, InternalError)
+        };
+        Digest();
+        ~Digest();
+        void append(const RawBuffer &data, std::size_t len = 0);
+        RawBuffer finalize(void);
+        RawBuffer get(void);
+        void reset(void);
+        unsigned int length(void);
+
+    private:
+        EVP_MD_CTX *m_ctx;
+        const EVP_MD *m_md;
+        RawBuffer m_digest;
+        bool m_initialized;
+        bool m_finalized;
+};
+
+} // namespace CKM
+
index c3433f2..a6be10b 100644 (file)
@@ -1,17 +1,28 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
 
 #include <iostream>
 #include <fstream>
 #include <stdio.h>
 #include <string.h>
 
-#include <openssl/bio.h>
-#include <openssl/evp.h>
-#include <openssl/rand.h>
-#include <openssl/sha.h>
-
 #include <dpl/log/log.h>
 #include <base64.h>
 #include <ckm/ckm-error.h>
+#include <digest.h>
 
 #include <DBCryptoModule.h>
 
@@ -20,23 +31,16 @@ namespace CKM {
 DBCryptoModule::DBCryptoModule(){}
 
 DBCryptoModule::DBCryptoModule(DBCryptoModule &&second) {
-    m_domainKEK = std::move(second.m_domainKEK);
     m_keyMap = std::move(second.m_keyMap);
 }
 
 DBCryptoModule& DBCryptoModule::operator=(DBCryptoModule &&second) {
     if (this == &second)
         return *this;
-    m_domainKEK = std::move(second.m_domainKEK);
     m_keyMap = std::move(second.m_keyMap);
     return *this;
 }
 
-DBCryptoModule::DBCryptoModule(RawBuffer &domainKEK)
-{
-    m_domainKEK = domainKEK;
-}
-
 bool DBCryptoModule::haveKey(const std::string &smackLabel)
 {
     return (m_keyMap.count(smackLabel) > 0);
@@ -45,17 +49,14 @@ bool DBCryptoModule::haveKey(const std::string &smackLabel)
 int DBCryptoModule::pushKey(const std::string &smackLabel,
                             const RawBuffer &applicationKey)
 {
-    if (m_domainKEK.size() == 0) {
-        ThrowMsg(Exception::DomainKeyError, "Empty domain key.");
-    }
     if (smackLabel.length() == 0) {
-        ThrowMsg(Exception::SmackLabelError, "Empty smack label.");
+        ThrowMsg(Exception::InternalError, "Empty smack label.");
     }
     if (applicationKey.size() == 0) {
-        ThrowMsg(Exception::AppKeyError, "Empty application key.");
+        ThrowMsg(Exception::InternalError, "Empty application key.");
     }
     if (haveKey(smackLabel)) {
-        ThrowMsg(Exception::AppKeyError, "Application key for " << smackLabel
+        ThrowMsg(Exception::InternalError, "Application key for " << smackLabel
                  << "label already exists.");
     }
     m_keyMap[smackLabel] = applicationKey;
@@ -67,42 +68,39 @@ std::size_t DBCryptoModule::insertDigest(RawBuffer &data, const int dataSize)
     RawBuffer digest;
 
     try {
-        digest = digestData(data, dataSize);
-    } catch (Exception::Base &e) {
+        Digest dig;
+        dig.append(data, dataSize);
+        digest = dig.finalize();
+    } catch (Digest::Exception::Base &e) {
         LogError("Failed to calculate digest in insertDigest: " <<
                  e.DumpToString());
         throw;
     }
-    if (SHA_DIGEST_LENGTH != digest.size()) {
-        ThrowMsg(Exception::DigestError, "Cannot insert digest: size mismatch.");
-    }
     data.insert(data.begin(), digest.begin(), digest.end());
     return digest.size();
 }
 
 void DBCryptoModule::removeDigest(RawBuffer &data, RawBuffer &digest)
 {
-    if (data.size() < SHA_DIGEST_LENGTH) {
-        ThrowMsg(Exception::DigestError, "Cannot remove digest: data size "
-                 "mismatch.");
+    unsigned int dlen = Digest().length();
+
+    if (data.size() < dlen) {
+        ThrowMsg(Exception::InternalError,
+                 "Cannot remove digest: data size mismatch.");
     }
 
-    digest.assign(data.begin(), data.begin() + SHA_DIGEST_LENGTH);
-    data.erase(data.begin(), data.begin() + SHA_DIGEST_LENGTH);
+    digest.assign(data.begin(), data.begin() + dlen);
+    data.erase(data.begin(), data.begin() + dlen);
 }
 
 int DBCryptoModule::encryptRow(const std::string &password, DBRow &row)
 {
     RawBuffer emptyiv;
+    RawBuffer emptykey;
     DBRow crow = row;
-    std::size_t dlen;
-    RawBuffer userkey;
     RawBuffer appkey;
 
     crow.algorithmType = DBCMAlgType::NONE;
-    if (m_domainKEK.size() == 0) {
-        ThrowMsg(Exception::DomainKeyError, "Empty domain key.");
-    }
     if (row.dataSize <= 0) {
         ThrowMsg(Exception::EncryptDBRowError, "Invalid dataSize.");
     }
@@ -114,12 +112,11 @@ int DBCryptoModule::encryptRow(const std::string &password, DBRow &row)
     crow.encryptionScheme = 0;
 
     try {
-        dlen = insertDigest(crow.data, crow.dataSize);
-        cryptAES(crow.data, crow.dataSize + dlen, appkey, emptyiv);
+        insertDigest(crow.data, crow.dataSize);
+        cryptAES(crow.data, appkey, emptyiv, "");
         crow.encryptionScheme |= ENCR_APPKEY;
         if (!password.empty()) {
-            generateKeysFromPassword(password, userkey, crow.iv);
-            cryptAES(crow.data, 0, userkey, crow.iv);
+            crow.iv = cryptAES(crow.data, emptykey, emptyiv, password).getIV();
             crow.encryptionScheme |= ENCR_PASSWORD;
         }
         encBase64(crow.data);
@@ -128,6 +125,9 @@ int DBCryptoModule::encryptRow(const std::string &password, DBRow &row)
     } catch (Exception::Base &e) {
         LogError("Failed to encrypt db row: " << e.DumpToString());
         throw;
+    } catch (AesCrypt::Exception::Base &e) {
+        LogError("Failed to encrypt db row: " << e.DumpToString());
+        throw;
     }
     crow.algorithmType = DBCMAlgType::AES_CBC_256;
     row = crow;
@@ -139,14 +139,11 @@ int DBCryptoModule::decryptRow(const std::string &password, DBRow &row)
 {
     DBRow crow = row;
     RawBuffer appkey;
-    RawBuffer userkey;
+    RawBuffer emptykey;
     RawBuffer dropiv;
     RawBuffer emptyiv;
     RawBuffer digest, dataDigest;
 
-    if (m_domainKEK.size() == 0) {
-        ThrowMsg(Exception::DomainKeyError, "Empty domain key.");
-    }
     if (row.dataSize <= 0) {
         ThrowMsg(Exception::DecryptDBRowError, "Invalid dataSize.");
     }
@@ -171,21 +168,28 @@ int DBCryptoModule::decryptRow(const std::string &password, DBRow &row)
             decBase64(crow.data);
         }
         if (crow.encryptionScheme & ENCR_PASSWORD) {
-            generateKeysFromPassword(password, userkey, dropiv);
-            decryptAES(crow.data, 0, userkey, crow.iv);
+            decryptAES(crow.data, emptykey, crow.iv, password);
         }
         if (crow.encryptionScheme & ENCR_APPKEY) {
-            decryptAES(crow.data, 0, appkey, emptyiv);
+            decryptAES(crow.data, appkey, emptyiv, "");
         }
         removeDigest(crow.data, digest);
         if (static_cast<std::size_t>(crow.dataSize) != crow.data.size()) {
             ThrowMsg(Exception::DecryptDBRowError,
                      "Decrypted db row data size mismatch.");
         }
-        dataDigest = digestData(crow.data, 0);
+        Digest dig;
+        dig.append(crow.data);
+        dataDigest = dig.finalize();
     } catch (Exception::Base &e) {
         LogError("Failed to decrypt db row: " << e.DumpToString());
         throw;
+    } catch (AesCrypt::Exception::Base &e) {
+        LogError("Failed to decrypt db row: " << e.DumpToString());
+        throw;
+    } catch (Digest::Exception::Base &e) {
+        LogError("Failed to decrypt db row: " << e.DumpToString());
+        throw;
     }
     if (not equalDigests(digest, dataDigest)) {
         ThrowMsg(Exception::DecryptDBRowError,
@@ -196,200 +200,49 @@ int DBCryptoModule::decryptRow(const std::string &password, DBRow &row)
     return CKM_API_SUCCESS;
 }
 
-RawBuffer DBCryptoModule::generateRandIV(void)
-{
-    int ret = -1;
-    RawBuffer civ(EVP_MAX_IV_LENGTH);
-
-    ret = RAND_bytes(civ.data(), civ.size());
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLError, "RAND_bytes failed");
-    }
-    return civ;
-}
-
-void DBCryptoModule::generateKeysFromPassword(const std::string &password,
-                                              RawBuffer &key, RawBuffer &iv)
-{
-    int ret = -1;
-    const EVP_CIPHER *cipher = EVP_aes_256_cbc();
-    unsigned int keyLen = EVP_CIPHER_key_length(cipher);
-    unsigned int ivLen = EVP_CIPHER_iv_length(cipher);
-#if 0
-    const EVP_MD *md = EVP_sha1();
-#endif
-
-    if (password.empty()) {
-        ThrowMsg(Exception::KeyGenerationError, "Password is empty.");
-    }
-    key.resize(keyLen);
-    iv.resize(ivLen);
-    iv = generateRandIV();
-    ret = PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), password.size(),
-            NULL, 0, 1024, keyLen, key.data());
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLError, "PKCS5_PBKDF2_HMAC_SHA1 has failed.");
-    }
-#if 0
-    ret = EVP_BytesToKey(cipher, md, NULL,
-                         const_cast<const unsigned char *>(&password[0]),
-                         strlen(reinterpret_cast<const char *>(&password[0])),
-                         1, &key[0], &iv[0]);
-    LogDebug("Generated key len: " << ret);
-    if (ret > 0)
-        ret = EXIT_SUCCESS;
-#endif
-}
-
-void DBCryptoModule::cryptAES(RawBuffer &data, std::size_t len,
-                              const RawBuffer &key, const RawBuffer &iv)
+CryptoAlgConf DBCryptoModule::cryptAES(RawBuffer &data,
+                                       const RawBuffer &key,
+                                       const RawBuffer &iv,
+                                       std::string password)
 {
-    int ret = -1;
-    EVP_CIPHER_CTX ctx;
-    const EVP_CIPHER *cipher = EVP_aes_256_cbc();
-    std::size_t keyLen = EVP_CIPHER_key_length(cipher);
-    std::size_t ivLen = EVP_CIPHER_iv_length(cipher);
-    int maxBufLen;
-    int outl, outlf;
-
-    if (keyLen == 0) {
-        ThrowMsg(Exception::OpenSSLEncryptError, "Got invalid key length for "
-                 "our cipher from openssl.");
-    }
-    if (key.size() != keyLen) {
-        ThrowMsg(Exception::AESEncryptionError, "Wrong key size.");
-    }
-    if (data.size() == 0) {
-        ThrowMsg(Exception::AESEncryptionError, "Empty data.");
-    }
-    /* iv may be empty */
-    if (iv.size() > 0)
-        if (iv.size() != ivLen) {
-            ThrowMsg(Exception::AESEncryptionError, "IV size mismatch.");
-        }
-    if (0 == len)
-        len = data.size();
-    maxBufLen = len + EVP_CIPHER_block_size(cipher);
-
-    LogDebug("key len: " << keyLen);
-    LogDebug("iv len: " << ivLen);
-    LogDebug("buf len: " << maxBufLen);
-    LogDebug("len: " << len);
-
-    RawBuffer buf(maxBufLen);
-
-    EVP_CIPHER_CTX_init(&ctx);
-    ret = EVP_EncryptInit_ex(&ctx, cipher, NULL, &key[0], &iv[0]);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLEncryptError, "Failed to initialize "
-                 "encryption in openssl.");
-    }
-    EVP_CIPHER_CTX_set_padding(&ctx, 1);
-    ret = EVP_EncryptUpdate(&ctx, &buf[0], &outl, &data[0], len);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLEncryptError, "Failed to encrypt data in "
-                 "openssl");
-    }
-    ret = EVP_EncryptFinal_ex(&ctx, &buf[outl], &outlf);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLEncryptError, "Failed to encrypt data in "
-                 "openssl (final)");
-    }
-    LogDebug("Total out len: " << outl + outlf);
-    EVP_CIPHER_CTX_cleanup(&ctx);
-    data.assign(buf.begin(), buf.begin() + outl + outlf);
-}
+    try {
+        AesEncrypt enc(password);
 
-void DBCryptoModule::decryptAES(RawBuffer &data, std::size_t len,
-                                const RawBuffer &key, const RawBuffer &iv)
-{
-    int ret = -1;
-    EVP_CIPHER_CTX ctx;
-    const EVP_CIPHER *cipher = EVP_aes_256_cbc();
-    std::size_t keyLen = EVP_CIPHER_key_length(cipher);
-    std::size_t ivLen = EVP_CIPHER_iv_length(cipher);
-    int maxBufLen;
-    int outl, outlf;
-
-    if (keyLen == 0) {
-        ThrowMsg(Exception::OpenSSLDecryptError, "Got invalid key length for "
-                 "our cipher from openssl.");
-    }
-    if (key.size() != keyLen) {
-        ThrowMsg(Exception::AESDecryptionError, "Wrong key size.");
-    }
-    if (iv.size() > 0)
-        if (iv.size() != ivLen) {
-            ThrowMsg(Exception::AESDecryptionError, "Wrong IV size.");
+        if (password.empty()) {
+            enc.conf.setKey(key);
+            enc.conf.setIV(iv);
         }
-    if (0 == len)
-        len = data.size();
-
-    maxBufLen = len + EVP_CIPHER_block_size(cipher) + 1;
-
-    LogDebug("buf len: " << maxBufLen);
-    LogDebug("data len: " << len);
-
-    RawBuffer buf(maxBufLen, 0);
-
-    EVP_CIPHER_CTX_init(&ctx);
-    ret = EVP_DecryptInit_ex(&ctx, cipher, NULL, &key[0], &iv[0]);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLDecryptError, "Failed to initialize "
-                 "decryption in openssl.");
-    }
-    EVP_CIPHER_CTX_set_padding(&ctx, 1);
-    ret = EVP_DecryptUpdate(&ctx, &buf[0], &outl, &data[0], len);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLDecryptError, "Failed to decrypt data in "
-                 "openssl");
-    }
-    ret = EVP_DecryptFinal_ex(&ctx, &buf[outl], &outlf);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLDecryptError, "Failed to decrypt data in "
-                 "openssl (final)");
-    }
-    LogDebug("Total out len: " << outl + outlf);
-    EVP_CIPHER_CTX_cleanup(&ctx);
-    if ((outl + outlf) == 0) {
-        ThrowMsg(Exception::OpenSSLDecryptError, "Failed to decrypt data in "
-                 "openssl - zero output length (wrong input data?)");
+        enc.append(data);
+        data = enc.finalize();
+        return enc.conf;
+    } catch (CryptoAlgConf::Exception::Base &e) {
+        LogError("Failed to configure AES encryption: " << e.DumpToString());
+        throw;
+    } catch (AesCrypt::Exception::Base &e) {
+        LogError("AES encryption failed: " << e.DumpToString());
+        throw;
     }
-    data.assign(buf.begin(), buf.begin() + outl + outlf);
 }
 
-RawBuffer DBCryptoModule::digestData(const RawBuffer &data, std::size_t len)
+void DBCryptoModule::decryptAES(RawBuffer &data, const RawBuffer &key,
+                                const RawBuffer &iv, std::string password)
 {
-    int ret = -1;
-    EVP_MD_CTX ctx;
-    const EVP_MD *md = EVP_sha1();
-    unsigned int dlen;
-
-    if (data.size() == 0) {
-        ThrowMsg(Exception::DigestError, "Empty data.");
-    }
-    if (0 == len)
-        len = data.size();
+    try {
+        AesDecrypt dec(password);
 
-    ret = EVP_DigestInit(&ctx, md);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLDigestError, "Failed to initialize digest "
-                 "in openssl.");
-    }
-    ret = EVP_DigestUpdate(&ctx, &data[0], len);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLDigestError, "Failed in digest calculation "
-                 "in openssl.");
-    }
-    RawBuffer digest(EVP_MAX_MD_SIZE);
-    ret = EVP_DigestFinal(&ctx, &digest[0], &dlen);
-    if (ret != 1) {
-        ThrowMsg(Exception::OpenSSLDigestError, "Failed in digest final "
-                 "calculation in openssl.");
+        if (password.empty()) {
+            dec.conf.setKey(key);
+        }
+        dec.conf.setIV(iv);
+        dec.append(data);
+        data = dec.finalize();
+    } catch (CryptoAlgConf::Exception::Base &e) {
+        LogError("Failed to configure AES decryption: " << e.DumpToString());
+        throw;
+    } catch (AesCrypt::Exception::Base &e) {
+        LogError("AES Decryption failed: " << e.DumpToString());
+        throw;
     }
-    if (dlen != EVP_MAX_MD_SIZE)
-        digest.resize(dlen);
-    return digest;
 }
 
 void DBCryptoModule::encBase64(RawBuffer &data)
@@ -442,8 +295,9 @@ void DBCryptoModule::decBase64(RawBuffer &data)
 
 bool DBCryptoModule::equalDigests(RawBuffer &dig1, RawBuffer &dig2)
 {
-    if ((dig1.size() != SHA_DIGEST_LENGTH) ||
-        (dig2.size() != SHA_DIGEST_LENGTH))
+    unsigned int dlen = Digest().length();
+
+    if ((dig1.size() != dlen) || (dig2.size() != dlen))
         return false;
     return (dig1 == dig2);
 }
index 9521f2c..c1f0a8e 100644 (file)
@@ -20,6 +20,7 @@
 #include <ckm/ckm-type.h>
 #include <db-crypto.h>
 #include <dpl/exception.h>
+#include <aesCrypt.h>
 
 namespace CKM {
 
@@ -29,17 +30,7 @@ public:
     {
         public:
             DECLARE_EXCEPTION_TYPE(CKM::Exception, Base)
-            DECLARE_EXCEPTION_TYPE(Base, DomainKeyError)
-            DECLARE_EXCEPTION_TYPE(Base, SmackLabelError)
-            DECLARE_EXCEPTION_TYPE(Base, AppKeyError)
-            DECLARE_EXCEPTION_TYPE(Base, AESDecryptionError)
-            DECLARE_EXCEPTION_TYPE(Base, AESEncryptionError)
-            DECLARE_EXCEPTION_TYPE(Base, OpenSSLDecryptError)
-            DECLARE_EXCEPTION_TYPE(Base, OpenSSLEncryptError)
-            DECLARE_EXCEPTION_TYPE(Base, DigestError)
-            DECLARE_EXCEPTION_TYPE(Base, OpenSSLDigestError)
-            DECLARE_EXCEPTION_TYPE(Base, OpenSSLError)
-            DECLARE_EXCEPTION_TYPE(Base, KeyGenerationError)
+            DECLARE_EXCEPTION_TYPE(Base, InternalError)
             DECLARE_EXCEPTION_TYPE(Base, Base64EncoderError)
             DECLARE_EXCEPTION_TYPE(Base, Base64DecoderError)
             DECLARE_EXCEPTION_TYPE(Base, EncryptDBRowError)
@@ -48,7 +39,6 @@ public:
     DBCryptoModule();
     DBCryptoModule(const DBCryptoModule &second) = delete;
     DBCryptoModule(DBCryptoModule &&second);
-    DBCryptoModule(RawBuffer &domainKEK);
     DBCryptoModule& operator=(DBCryptoModule &&second);
     DBCryptoModule& operator=(const DBCryptoModule &second) = delete;
 
@@ -66,22 +56,19 @@ private:
        static const int ENCR_APPKEY =   1 << 1;
        static const int ENCR_PASSWORD = 1 << 2;
        
-       RawBuffer m_domainKEK;
        std::map<std::string, RawBuffer> m_keyMap;
 
     /* TODO: Move it to private/protected after tests (or remove if not needed) */
-    void cryptAES(RawBuffer &data, std::size_t len, const RawBuffer &key,
-                  const RawBuffer &iv);
-    void decryptAES(RawBuffer &data, std::size_t len, const RawBuffer &key,
-                    const RawBuffer &iv);
+    CryptoAlgConf cryptAES(RawBuffer &data, const RawBuffer &key,
+                           const RawBuffer &iv, std::string password);
+    void decryptAES(RawBuffer &data, const RawBuffer &key, const RawBuffer &iv,
+                    std::string password);
     void decBase64(RawBuffer &data);
-    RawBuffer digestData(const RawBuffer &data, std::size_t len);
     void encBase64(RawBuffer &data);
     bool equalDigests(RawBuffer &dig1, RawBuffer &dig2);
     std::size_t insertDigest(RawBuffer &data, const int dataSize);
     void generateKeysFromPassword(const std::string &password,
                                   RawBuffer &key, RawBuffer &iv);
-    RawBuffer generateRandIV(void);
     void removeDigest(RawBuffer &data, RawBuffer &digest);
 };
 
index 1e9c14c..b271782 100644 (file)
@@ -71,7 +71,7 @@ RawBuffer CKMLogic::unlockUserKey(uid_t user, const std::string &password) {
 
             RawBuffer key = handle.keyProvider.getPureDomainKEK();
             handle.database = DBCrypto(fs.getDBPath(), key);
-            handle.crypto = DBCryptoModule(key);
+            handle.crypto = DBCryptoModule();
             // TODO wipe key
         }
     } catch (const KeyProvider::Exception::Base &e) {