forked from UkoeHB/monero
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request UkoeHB#14 from ghostway0/ghostway/encrypted_file
[seraphis_wallet]: encrypted file
- Loading branch information
Showing
3 changed files
with
176 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
#pragma once | ||
|
||
#include "crypto/chacha.h" | ||
#include "crypto/crypto.h" | ||
#include "file_io_utils.h" | ||
#include "serialization/binary_archive.h" | ||
#include "serialization/containers.h" | ||
#include "serialization/crypto.h" | ||
#include "serialization/serialization.h" | ||
#include "serialization/string.h" | ||
#include "storages/portable_storage_template_helper.h" | ||
#include "string_coding.h" | ||
|
||
#include <type_traits> | ||
|
||
struct EncryptedFile | ||
{ | ||
std::string encrypted_data; | ||
crypto::chacha_iv iv; | ||
|
||
BEGIN_SERIALIZE_OBJECT() | ||
VERSION_FIELD(0) | ||
FIELD(encrypted_data) | ||
FIELD(iv) | ||
END_SERIALIZE() | ||
}; | ||
|
||
template <class T> bool read_encrypted_file(std::string path, const crypto::chacha_key &key, T &struct_out) | ||
{ | ||
std::string buf; | ||
if (!epee::file_io_utils::load_file_to_string(path, buf)) | ||
return false; | ||
|
||
EncryptedFile file; | ||
|
||
binary_archive<false> file_ar{epee::strspan<std::uint8_t>(buf)}; | ||
if (!::serialization::serialize(file_ar, file)) | ||
return false; | ||
|
||
std::string decrypted_data; | ||
decrypted_data.resize(file.encrypted_data.size()); | ||
crypto::chacha20(file.encrypted_data.data(), file.encrypted_data.size(), key, file.iv, &decrypted_data[0]); | ||
|
||
binary_archive<false> ar{epee::strspan<std::uint8_t>(decrypted_data)}; | ||
|
||
if (!::serialization::serialize(ar, struct_out)) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
// NOTE: if this were c++20, Concepts and `require` could be used to make this one function | ||
template <class T> bool read_encrypted_file_json(std::string path, const crypto::chacha_key &key, T &struct_out) | ||
{ | ||
std::string buf; | ||
if (!epee::file_io_utils::load_file_to_string(path, buf)) | ||
return false; | ||
|
||
EncryptedFile file; | ||
|
||
binary_archive<false> file_ar{epee::strspan<std::uint8_t>(buf)}; | ||
if (!::serialization::serialize(file_ar, file)) | ||
return false; | ||
|
||
std::string decrypted_data; | ||
decrypted_data.resize(file.encrypted_data.size()); | ||
crypto::chacha20(file.encrypted_data.data(), file.encrypted_data.size(), key, file.iv, &decrypted_data[0]); | ||
|
||
return epee::serialization::load_t_from_json(struct_out, decrypted_data); | ||
} | ||
|
||
template <class T> bool write_encrypted_file(std::string path, const crypto::chacha_key &key, T &struct_in) | ||
{ | ||
std::stringstream data_oss; | ||
binary_archive<true> data_ar(data_oss); | ||
if (!::serialization::serialize(data_ar, struct_in)) | ||
return false; | ||
|
||
std::string buf = data_oss.str(); | ||
|
||
EncryptedFile file = {}; | ||
file.iv = crypto::rand<crypto::chacha_iv>(); | ||
|
||
std::string encrypted_data; | ||
encrypted_data.resize(buf.size()); | ||
|
||
crypto::chacha20(std::move(buf.data()), buf.size(), key, file.iv, &encrypted_data[0]); | ||
|
||
file.encrypted_data = encrypted_data; | ||
|
||
std::stringstream file_oss; | ||
binary_archive<true> file_ar(file_oss); | ||
if (!::serialization::serialize(file_ar, file)) | ||
return false; | ||
|
||
return epee::file_io_utils::save_string_to_file(path, file_oss.str()); | ||
} | ||
|
||
template <class T> bool write_encrypted_file_json(std::string path, const crypto::chacha_key &key, T &struct_in) | ||
{ | ||
std::string struct_json = epee::serialization::store_t_to_json(struct_in); | ||
|
||
EncryptedFile file = {}; | ||
file.iv = crypto::rand<crypto::chacha_iv>(); | ||
|
||
std::string encrypted_data; | ||
encrypted_data.resize(struct_json.size()); | ||
|
||
crypto::chacha20(std::move(struct_json.data()), struct_json.size(), key, file.iv, &encrypted_data[0]); | ||
|
||
file.encrypted_data = encrypted_data; | ||
|
||
std::stringstream file_oss; | ||
binary_archive<true> file_ar(file_oss); | ||
if (!::serialization::serialize(file_ar, file)) | ||
return false; | ||
|
||
return epee::file_io_utils::save_string_to_file(path, file_oss.str()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#include <boost/filesystem.hpp> | ||
#include <boost/filesystem/operations.hpp> | ||
#include <gtest/gtest.h> | ||
|
||
#include "crypto/chacha.h" | ||
#include "seraphis_wallet/encrypted_file.h" | ||
#include "serialization/serialization.h" | ||
#include "serialization/keyvalue_serialization.h" | ||
|
||
struct test_s | ||
{ | ||
std::string data; | ||
|
||
BEGIN_SERIALIZE() | ||
FIELD(data) | ||
END_SERIALIZE() | ||
|
||
BEGIN_KV_SERIALIZE_MAP() | ||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(data) | ||
END_KV_SERIALIZE_MAP() | ||
}; | ||
|
||
TEST(EncryptedFile, ReadWriteBlob) | ||
{ | ||
boost::filesystem::path temp_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); | ||
const std::string tmp_path = temp_file.native(); | ||
|
||
test_s test{.data = "monero is awesome"}; | ||
|
||
crypto::chacha_key key; | ||
crypto::generate_chacha_key("monero is double awesome", key, 1); | ||
|
||
ASSERT_TRUE(write_encrypted_file(tmp_path, key, test)); | ||
|
||
ASSERT_TRUE(read_encrypted_file(tmp_path, key, test)); | ||
|
||
ASSERT_TRUE(test.data == "monero is awesome"); | ||
} | ||
|
||
TEST(EncryptedFile, ReadWriteJson) | ||
{ | ||
boost::filesystem::path temp_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); | ||
const std::string tmp_path = temp_file.native(); | ||
|
||
test_s test{.data = "monero is awesome!"}; | ||
|
||
crypto::chacha_key key; | ||
crypto::generate_chacha_key("monero is double awesome", key, 1); | ||
|
||
ASSERT_TRUE(write_encrypted_file_json(tmp_path, key, test)); | ||
|
||
ASSERT_TRUE(read_encrypted_file_json(tmp_path, key, test)); | ||
|
||
ASSERT_TRUE(test.data == "monero is awesome!"); | ||
} |