Skip to content
Snippets Groups Projects
Verified Commit c78f3eb0 authored by Daniel Lyubomirov's avatar Daniel Lyubomirov
Browse files

[17] crypto storage common base implementation

parent bc629b90
No related branches found
No related tags found
1 merge request!97Crypto Storage and LoginWithNewDevice and LoginWithPreviouslyAddedDevice APIs
......@@ -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
......
......@@ -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 "";
}
......
......@@ -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
......
#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
#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
......@@ -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
......@@ -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
......
......@@ -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);
}
}
......@@ -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
......
......@@ -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;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment