diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index ff7e8f66c2f273e25eabb9d537db05b46717f408..2fe59c9e8783c4b14ed939a2c958738dd8de516c 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 933e2e2fb8412ff2a0e0bf244c90bf7873924594..8fb23c828a698cd28071c35f9fa6eab28b1ef7ba 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 1db221266e4aca68d3d86764dbbbf59008adccd3..48da81694cec98dd8871d1ec61677a5a1fb62e76 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 0000000000000000000000000000000000000000..d2278a6dad01e3016f8fce82f36bc4e24e15e230 --- /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 0000000000000000000000000000000000000000..2351c822b6f0782027b12f3f2ff53f38ea9cb50a --- /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 50801aa31232afb84197200829b54d6b2cb1743d..0d420f0ad7a2829a7c4f2d46c4170e7bbdc8ad56 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 1f8b08289811e938c7b9012049a6c0d92d77a38b..e1675e44cf4c63132e560832847016c762eeae46 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 e54416e0103262ca2ff0ada2ef60764a1fcb4f5e..271acf4bdb6f12db5af2fb80a86e9cb6ddd258ae 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 4ae120f9496d3dfb8168cbd1d70f317bddda7656..cc88a31589d2a717aa4b579e81db7b62159cf50a 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 9ef0e5674c931a9cf0a30d93fa7fd85f838fcf22..6cb4048d401b997f6f4f8ba79b38d5c9eab8581c 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;