Added new classes for handling AES encryption and digest calculation.
Change-Id: Ic538130ff86eb53ee5c0446212e1cf628cca708e
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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+
+/*
+ * 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>
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);
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;
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.");
}
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);
} 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;
{
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.");
}
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,
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)
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);
}
#include <ckm/ckm-type.h>
#include <db-crypto.h>
#include <dpl/exception.h>
+#include <aesCrypt.h>
namespace CKM {
{
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)
DBCryptoModule();
DBCryptoModule(const DBCryptoModule &second) = delete;
DBCryptoModule(DBCryptoModule &&second);
- DBCryptoModule(RawBuffer &domainKEK);
DBCryptoModule& operator=(DBCryptoModule &&second);
DBCryptoModule& operator=(const DBCryptoModule &second) = delete;
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);
};
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) {