From c78f3eb033a733a9e57634e3417bf27d3e42beb8 Mon Sep 17 00:00:00 2001 From: Daniel Lyubomirov <daniel.lyubomirov@vereign.com> Date: Fri, 26 Jun 2020 10:14:38 +0300 Subject: [PATCH] [17] crypto storage common base implementation --- cpp/src/CMakeLists.txt | 2 +- cpp/src/vereign/core/string.cc | 4 +- cpp/src/vereign/core/string.hh | 4 +- .../kvstore/detail/base_crypto_storage.cc | 95 +++++++++++++++++++ .../kvstore/detail/base_crypto_storage.hh | 37 ++++++++ .../kvstore/detail/linux_crypto_storage.cc | 76 +-------------- .../kvstore/detail/linux_crypto_storage.hh | 16 +--- .../kvstore/detail/win_crypto_storage.cc | 81 ++-------------- .../kvstore/detail/win_crypto_storage.hh | 15 +-- cpp/src/vereign/ncrypt/rsa.hh | 6 +- 10 files changed, 157 insertions(+), 179 deletions(-) create mode 100644 cpp/src/vereign/kvstore/detail/base_crypto_storage.cc create mode 100644 cpp/src/vereign/kvstore/detail/base_crypto_storage.hh diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index ff7e8f6..2fe59c9 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -75,8 +75,8 @@ set(VEREIGNLIB_SRC vereign/crypto/bio.cc vereign/crypto/digest.cc - vereign/kvstore/lock.cc + vereign/kvstore/detail/base_crypto_storage.cc vereign/kvstore/sqlite_storage.cc vereign/kvstore/crypto_storage.cc diff --git a/cpp/src/vereign/core/string.cc b/cpp/src/vereign/core/string.cc index 933e2e2..8fb23c8 100644 --- a/cpp/src/vereign/core/string.cc +++ b/cpp/src/vereign/core/string.cc @@ -11,7 +11,7 @@ namespace vereign::string { #ifdef _WIN32 -auto widen(const std::string& utf8_str) -> std::wstring { +auto widen(std::string_view utf8_str) -> std::wstring { if (utf8_str.empty()) { return L""; } @@ -39,7 +39,7 @@ auto widen(const std::string& utf8_str) -> std::wstring { return result; } -auto narrow(const std::wstring& utf16_str) -> std::string { +auto narrow(std::wstring_view utf16_str) -> std::string { if (utf16_str.empty()) { return ""; } diff --git a/cpp/src/vereign/core/string.hh b/cpp/src/vereign/core/string.hh index 1db2212..48da816 100644 --- a/cpp/src/vereign/core/string.hh +++ b/cpp/src/vereign/core/string.hh @@ -8,8 +8,8 @@ namespace vereign::string { #ifdef _WIN32 -auto widen(const std::string& utf8_str) -> std::wstring; -auto narrow(const std::wstring& utf16_str) -> std::string; +auto widen(std::string_view utf8_str) -> std::wstring; +auto narrow(std::wstring_view utf16_str) -> std::string; #endif diff --git a/cpp/src/vereign/kvstore/detail/base_crypto_storage.cc b/cpp/src/vereign/kvstore/detail/base_crypto_storage.cc new file mode 100644 index 0000000..d2278a6 --- /dev/null +++ b/cpp/src/vereign/kvstore/detail/base_crypto_storage.cc @@ -0,0 +1,95 @@ +#include <vereign/kvstore/detail/base_crypto_storage.hh> + +#include <vereign/kvstore/detail/value_encoder.hh> +#include <vereign/kvstore/errors.hh> +#include <vereign/kvstore/lock.hh> + +#include <vereign/crypto/digest.hh> +#include <vereign/crypto/errors.hh> +#include <vereign/crypto/rand.hh> +#include <vereign/crypto/rsa.hh> +#include <vereign/crypto/aes.hh> +#include <vereign/crypto/bio.hh> + +#include <boost/core/ignore_unused.hpp> +#include <chrono> + +namespace { + + // FIXME: should these be injected and provided by the integrator + constexpr int tagSizeBytes = 64; + constexpr int lockRetryCount = 10; + constexpr auto lockRetrySleep = std::chrono::milliseconds{1000}; +} + +namespace vereign::kvstore::detail { + +BaseCryptoStorageImpl::BaseCryptoStorageImpl(kvstore::Storage& storage) + : storage_{storage} +{ +} + +void BaseCryptoStorageImpl::encryptBytes(const std::string& key, bytes::View value) { + if (key_.Size() == 0) { + throw Error("crypto storage is not initialized"); + } + + bytes::Buffer iv; + bytes::Buffer tag; + bytes::Buffer encrypted; + + crypto::aes::GCM256Encrypt(value, key_.View(), iv, encrypted, tag); + + bytes::Buffer encoded_value; + EncodeEncryptedValue(encoded_value, iv.View(), tag.View(), encrypted.View()); + + storage_.PutBytes(key, encoded_value.View()); +} + +void BaseCryptoStorageImpl::PutBytes(const std::string& key, bytes::View value) { + kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; + + validateTag(); + + encryptBytes(key, value); +} + +void BaseCryptoStorageImpl::GetBytes(const std::string& key, bytes::Buffer& value) const { + kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; + + if (key_.Size() == 0) { + throw Error("crypto storage is not initialized"); + } + + bytes::Buffer encoded; + storage_.GetBytes(key, encoded); + + bytes::View iv; + bytes::View tag; + bytes::View encrypted; + DecodeEncryptedValue(encoded.View(), iv, tag, encrypted); + + crypto::aes::GCM256Decrypt(encrypted, key_.View(), iv, tag, value); +} + +void BaseCryptoStorageImpl::initKey(bytes::Buffer&& key) { + key_ = std::move(key); +} + +void BaseCryptoStorageImpl::validateTag() const { + bytes::Buffer tag; + try { + GetBytes("__tag", tag); + } catch (const crypto::Error& err) { + throw IdentityChanged{}; + } +} + +void BaseCryptoStorageImpl::updateTag() { + bytes::Buffer tag{tagSizeBytes}; + crypto::Rand(tag); + + encryptBytes("__tag", tag.View()); +} + +} // namespace vereign::kvstore::detail diff --git a/cpp/src/vereign/kvstore/detail/base_crypto_storage.hh b/cpp/src/vereign/kvstore/detail/base_crypto_storage.hh new file mode 100644 index 0000000..2351c82 --- /dev/null +++ b/cpp/src/vereign/kvstore/detail/base_crypto_storage.hh @@ -0,0 +1,37 @@ +#ifndef __VEREIGN_KVSTORE_DETAIL_BASE_CRYPTO_STORAGE_HH +#define __VEREIGN_KVSTORE_DETAIL_BASE_CRYPTO_STORAGE_HH + +#include <vereign/kvstore/storage.hh> + +namespace vereign::kvstore::detail { + +class BaseCryptoStorageImpl { +public: + BaseCryptoStorageImpl(kvstore::Storage& storage); + + // disable copying + BaseCryptoStorageImpl(const BaseCryptoStorageImpl&) = delete; + auto operator=(const BaseCryptoStorageImpl&) -> BaseCryptoStorageImpl& = delete; + + void PutBytes(const std::string& key, bytes::View value); + void GetBytes(const std::string& key, bytes::Buffer& value) const; + +protected: + void initKey(bytes::Buffer&& key); + void validateTag() const; + void updateTag(); + +private: + void encryptBytes(const std::string& key, bytes::View value); + +protected: + kvstore::Storage& storage_; + +private: + bytes::Buffer key_; +}; + +} // namespace vereign::kvstore::detail + + +#endif // __VEREIGN_KVSTORE_DETAIL_BASE_CRYPTO_STORAGE_HH diff --git a/cpp/src/vereign/kvstore/detail/linux_crypto_storage.cc b/cpp/src/vereign/kvstore/detail/linux_crypto_storage.cc index 50801aa..0d420f0 100644 --- a/cpp/src/vereign/kvstore/detail/linux_crypto_storage.cc +++ b/cpp/src/vereign/kvstore/detail/linux_crypto_storage.cc @@ -18,7 +18,6 @@ namespace { // FIXME: should these be injected and provided by the integrator constexpr int iterations = 1 << 18; constexpr int saltSizeBytes = 64; - constexpr int tagSizeBytes = 64; constexpr int aesKeySizeBytes = 32; constexpr int lockRetryCount = 10; @@ -28,7 +27,7 @@ namespace { namespace vereign::kvstore::detail { CryptoStorageImpl::CryptoStorageImpl(kvstore::Storage& storage, bool disable_key_protection) - : storage_{storage} + : BaseCryptoStorageImpl{storage} { boost::ignore_unused(disable_key_protection); } @@ -60,17 +59,9 @@ void CryptoStorageImpl::Open(const std::string& pin) { key.IncSize(aesKeySizeBytes); - key_ = std::move(key); - + initKey(std::move(key)); // FIXME: write tests for tampering and regular identity change - try { - bytes::Buffer tag; - GetBytes("__tag", tag); - tag_ = std::move(tag); - - } catch (const crypto::Error& err) { - throw IdentityChanged{}; - } + validateTag(); } void CryptoStorageImpl::Reset(const std::string& pin) { @@ -93,75 +84,18 @@ void CryptoStorageImpl::Reset(const std::string& pin) { } key.IncSize(aesKeySizeBytes); - key_ = std::move(key); - - bytes::Buffer tag{tagSizeBytes}; - crypto::Rand(tag); + initKey(std::move(key)); { kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; storage_.DeleteAll(); - encryptBytes("__tag", tag.View()); - tag_ = std::move(tag); + updateTag(); storage_.PutInt64("__master_key_iterations", iterations); storage_.PutBytes("__master_key_salt", salt.View()); } } -void CryptoStorageImpl::encryptBytes(const std::string& key, bytes::View value) { - if (key_.Size() == 0) { - throw Error("crypto storage is not initialized"); - } - - bytes::Buffer iv; - bytes::Buffer tag; - bytes::Buffer encrypted; - - crypto::aes::GCM256Encrypt(value, key_.View(), iv, encrypted, tag); - - bytes::Buffer encoded_value; - EncodeEncryptedValue(encoded_value, iv.View(), tag.View(), encrypted.View()); - - storage_.PutBytes(key, encoded_value.View()); -} - -void CryptoStorageImpl::PutBytes(const std::string& key, bytes::View value) { - kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; - - bytes::Buffer tag; - try { - GetBytes("__tag", tag); - } catch (const crypto::Error& err) { - throw IdentityChanged{}; - } - - if (tag.View() != tag_.View()) { - throw IdentityChanged{}; - } - - encryptBytes(key, value); -} - -void CryptoStorageImpl::GetBytes(const std::string& key, bytes::Buffer& value) { - kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; - - if (key_.Size() == 0) { - throw Error("crypto storage is not initialized"); - } - - bytes::Buffer encoded; - storage_.GetBytes(key, encoded); - - bytes::View iv; - bytes::View tag; - bytes::View encrypted; - DecodeEncryptedValue(encoded.View(), iv, tag, encrypted); - - crypto::aes::GCM256Decrypt(encrypted, key_.View(), iv, tag, value); -} - - } // namespace vereign::kvstore::detail diff --git a/cpp/src/vereign/kvstore/detail/linux_crypto_storage.hh b/cpp/src/vereign/kvstore/detail/linux_crypto_storage.hh index 1f8b082..e1675e4 100644 --- a/cpp/src/vereign/kvstore/detail/linux_crypto_storage.hh +++ b/cpp/src/vereign/kvstore/detail/linux_crypto_storage.hh @@ -2,10 +2,11 @@ #define __VEREIGN_KVSTORE_DETAIL_LINUX_CRYPTO_STORAGE_HH #include <vereign/kvstore/storage.hh> +#include <vereign/kvstore/detail/base_crypto_storage.hh> namespace vereign::kvstore::detail { -class CryptoStorageImpl { +class CryptoStorageImpl : public BaseCryptoStorageImpl { public: CryptoStorageImpl(kvstore::Storage& storage, bool disable_key_protection); @@ -15,19 +16,6 @@ public: void Reset(const std::string& pin); void Open(const std::string& pin); - - void PutBytes(const std::string& key, bytes::View value); - void GetBytes(const std::string& key, bytes::Buffer& value); - -private: - void encryptBytes(const std::string& key, bytes::View value); - -private: - kvstore::Storage& storage_; - - bytes::Buffer key_; - - bytes::Buffer tag_; }; } // namespace vereign::kvstore::detail diff --git a/cpp/src/vereign/kvstore/detail/win_crypto_storage.cc b/cpp/src/vereign/kvstore/detail/win_crypto_storage.cc index e54416e..271acf4 100644 --- a/cpp/src/vereign/kvstore/detail/win_crypto_storage.cc +++ b/cpp/src/vereign/kvstore/detail/win_crypto_storage.cc @@ -19,7 +19,6 @@ namespace { // FIXME: should these be injected and provided by the integrator constexpr int keySizeBits = 2048; - constexpr int tagSizeBytes = 64; constexpr int aesKeySizeBytes = 32; constexpr int lockRetryCount = 10; @@ -37,7 +36,7 @@ namespace { namespace vereign::kvstore::detail { CryptoStorageImpl::CryptoStorageImpl(kvstore::Storage& storage, bool disable_key_protection) - : storage_{storage}, + : BaseCryptoStorageImpl{storage}, disable_key_protection_{disable_key_protection} {} @@ -56,17 +55,10 @@ void CryptoStorageImpl::Open(const std::string& pin) { bytes::Buffer key; ncrypt::rsa::PrivateKeyDecrypt(rsa_key.Get(), encrypted_key.View(), key); - key_ = std::move(key); + initKey(std::move(key)); // FIXME: write tests for tampering and regular identity change - try { - bytes::Buffer tag; - GetBytes("__tag", tag); - tag_ = std::move(tag); - - } catch (const crypto::Error&) { - throw IdentityChanged{}; - } + validateTag(); } void CryptoStorageImpl::Reset(const std::string& pin) { @@ -82,9 +74,9 @@ void CryptoStorageImpl::Reset(const std::string& pin) { std::optional<ncrypt::rsa::KeyUIPolicy> ui_policy; if (!disable_key_protection_) { ui_policy = ncrypt::rsa::KeyUIPolicy{ - std::string(vereignKeyCreationTitle), - std::string(vereignKeyDescription), - std::string(vereignKeyFriendlyName) + vereignKeyCreationTitle, + vereignKeyDescription, + vereignKeyFriendlyName }; } @@ -103,66 +95,9 @@ void CryptoStorageImpl::Reset(const std::string& pin) { bytes::Buffer encrypted_key; ncrypt::rsa::PublicKeyEncrypt(rsa_key.Get(), key.View(), encrypted_key); storage_.PutBytes("__master_key", encrypted_key.View()); - key_ = std::move(key); - - bytes::Buffer tag{tagSizeBytes}; - crypto::Rand(tag); - - encryptBytes("__tag", tag.View()); - tag_ = std::move(tag); -} - -void CryptoStorageImpl::encryptBytes(const std::string& key, bytes::View value) { - if (key_.Size() == 0) { - throw Error("crypto storage is not initialized"); - } - - bytes::Buffer iv; - bytes::Buffer tag; - bytes::Buffer encrypted; - - crypto::aes::GCM256Encrypt(value, key_.View(), iv, encrypted, tag); - - bytes::Buffer encoded_value; - EncodeEncryptedValue(encoded_value, iv.View(), tag.View(), encrypted.View()); - - storage_.PutBytes(key, encoded_value.View()); -} - -void CryptoStorageImpl::PutBytes(const std::string& key, bytes::View value) { - kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; - bytes::Buffer tag; - try { - GetBytes("__tag", tag); - } catch (const crypto::Error&) { - throw IdentityChanged{}; - } - - if (tag.View() != tag_.View()) { - throw IdentityChanged{}; - } - - encryptBytes(key, value); + initKey(std::move(key)); + updateTag(); } -void CryptoStorageImpl::GetBytes(const std::string& key, bytes::Buffer& value) { - kvstore::Lock l{storage_, lockRetryCount, lockRetrySleep}; - - if (key_.Size() == 0) { - throw Error("crypto storage is not initialized"); - } - - bytes::Buffer encoded; - storage_.GetBytes(key, encoded); - - bytes::View iv; - bytes::View tag; - bytes::View encrypted; - DecodeEncryptedValue(encoded.View(), iv, tag, encrypted); - - crypto::aes::GCM256Decrypt(encrypted, key_.View(), iv, tag, value); -} - - } diff --git a/cpp/src/vereign/kvstore/detail/win_crypto_storage.hh b/cpp/src/vereign/kvstore/detail/win_crypto_storage.hh index 4ae120f..cc88a31 100644 --- a/cpp/src/vereign/kvstore/detail/win_crypto_storage.hh +++ b/cpp/src/vereign/kvstore/detail/win_crypto_storage.hh @@ -2,10 +2,11 @@ #define __VEREIGN_KVSTORE_DETAIL_WIN_CRYPTO_STORAGE_HH #include <vereign/kvstore/storage.hh> +#include <vereign/kvstore/detail/base_crypto_storage.hh> namespace vereign::kvstore::detail { -class CryptoStorageImpl { +class CryptoStorageImpl : public BaseCryptoStorageImpl { public: CryptoStorageImpl(kvstore::Storage& storage, bool disable_key_protection); @@ -16,20 +17,8 @@ public: void Reset(const std::string& pin); void Open(const std::string& pin); - void PutBytes(const std::string& key, bytes::View value); - void GetBytes(const std::string& key, bytes::Buffer& value); - -private: - void encryptBytes(const std::string& key, bytes::View value); - private: - kvstore::Storage& storage_; - bool disable_key_protection_ = false; - - bytes::Buffer key_; - - bytes::Buffer tag_; }; } // namespace vereign::kvstore::detail diff --git a/cpp/src/vereign/ncrypt/rsa.hh b/cpp/src/vereign/ncrypt/rsa.hh index 9ef0e56..6cb4048 100644 --- a/cpp/src/vereign/ncrypt/rsa.hh +++ b/cpp/src/vereign/ncrypt/rsa.hh @@ -12,9 +12,9 @@ namespace vereign::ncrypt::rsa { struct KeyUIPolicy { - std::string CreationTitle; - std::string Description; - std::string FriendlyName; + std::string_view CreationTitle; + std::string_view Description; + std::string_view FriendlyName; }; auto OpenStorageProvider() -> UniquePtr; -- GitLab