encrypt/decrypt secret data

This commit is contained in:
Scott E. Graves 2025-03-20 12:54:43 -05:00
parent 0101e92d97
commit 4b45e71193
2 changed files with 44 additions and 8 deletions

View File

@ -29,10 +29,33 @@
#include "utils/common.hpp" #include "utils/common.hpp"
#include "utils/error_utils.hpp" #include "utils/error_utils.hpp"
#include "utils/file.hpp" #include "utils/file.hpp"
#include "utils/hash.hpp"
#include "utils/path.hpp" #include "utils/path.hpp"
#include "utils/string.hpp" #include "utils/string.hpp"
namespace { namespace {
[[nodiscard]] auto decrypt(std::string_view data, std::string_view password)
-> std::string {
auto decoded = macaron::Base64::Decode(data);
repertory::data_buffer buffer(decoded.size());
auto key = repertory::utils::encryption::create_hash_blake2b_256(password);
std::uint64_t size{};
crypto_aead_xchacha20poly1305_ietf_decrypt(
reinterpret_cast<unsigned char *>(buffer.data()), &size, nullptr,
reinterpret_cast<const unsigned char *>(
&decoded.at(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES)),
decoded.size() - crypto_aead_xchacha20poly1305_IETF_NPUBBYTES,
reinterpret_cast<const unsigned char *>(REPERTORY.data()), 9U,
reinterpret_cast<const unsigned char *>(decoded.data()),
reinterpret_cast<const unsigned char *>(key.data()));
return std::string(
buffer.begin(),
std::next(buffer.begin(), static_cast<std::int64_t>(size)));
}
[[nodiscard]] constexpr auto is_restricted(std::string_view data) -> bool { [[nodiscard]] constexpr auto is_restricted(std::string_view data) -> bool {
constexpr std::string_view invalid_chars = "&;|><$()`{}!*?"; constexpr std::string_view invalid_chars = "&;|><$()`{}!*?";
return data.find_first_of(invalid_chars) != std::string_view::npos; return data.find_first_of(invalid_chars) != std::string_view::npos;
@ -386,6 +409,7 @@ void handlers::handle_post_mount(auto &&req, auto &&res) const {
void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) const { void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) const {
auto name = req.get_param_value("name"); auto name = req.get_param_value("name");
auto prov = provider_type_from_string(req.get_param_value("type")); auto prov = provider_type_from_string(req.get_param_value("type"));
if (not data_directory_exists(prov, name)) { if (not data_directory_exists(prov, name)) {
@ -394,8 +418,19 @@ void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) const {
} }
auto key = req.get_param_value("key"); auto key = req.get_param_value("key");
auto last_key{key};
auto value = req.get_param_value("value"); auto value = req.get_param_value("value");
auto parts = utils::string::split(key, '.', false);
if (parts.size() > 1U) {
last_key = parts.at(parts.size() - 1U);
}
if (last_key == JSON_API_PASSWORD || last_key == JSON_ENCRYPTION_TOKEN ||
last_key == JSON_SECRET_KEY) {
value = decrypt(value, config_->get_api_password());
}
set_key_value(prov, name, key, value); set_key_value(prov, name, key, value);
res.status = http_error_codes::ok; res.status = http_error_codes::ok;

View File

@ -227,6 +227,8 @@ bool validateSettings(
} }
Map<String, dynamic> convertAllToString(Map<String, dynamic> settings) { Map<String, dynamic> convertAllToString(Map<String, dynamic> settings) {
final password = 'test';
settings.forEach((key, value) { settings.forEach((key, value) {
if (value is Map<String, dynamic>) { if (value is Map<String, dynamic>) {
convertAllToString(value); convertAllToString(value);
@ -236,7 +238,7 @@ Map<String, dynamic> convertAllToString(Map<String, dynamic> settings) {
if (key == 'ApiPassword' || if (key == 'ApiPassword' ||
key == 'EncryptionToken' || key == 'EncryptionToken' ||
key == 'SecretKey') { key == 'SecretKey') {
value = encryptValue(value); value = encryptValue(value, password);
} else if (value is String) { } else if (value is String) {
return; return;
} }
@ -247,7 +249,7 @@ Map<String, dynamic> convertAllToString(Map<String, dynamic> settings) {
return settings; return settings;
} }
String encryptValue(String value) { String encryptValue(String value, String password) {
final sodium = constants.sodium; final sodium = constants.sodium;
if (sodium == null) { if (sodium == null) {
return value; return value;
@ -255,19 +257,18 @@ String encryptValue(String value) {
final keyHash = sodium.crypto.genericHash( final keyHash = sodium.crypto.genericHash(
outLen: sodium.crypto.aeadChaCha20Poly1305.keyBytes, outLen: sodium.crypto.aeadChaCha20Poly1305.keyBytes,
message: Uint8List.fromList('test'.toCharArray()), message: Uint8List.fromList(password.toCharArray()),
); );
final crypto = sodium.crypto.aeadXChaCha20Poly1305IETF; final crypto = sodium.crypto.aeadXChaCha20Poly1305IETF;
final nonce = sodium.secureRandom(crypto.nonceBytes).extractBytes();
final data = crypto.encrypt( final data = crypto.encrypt(
additionalData: Uint8List.fromList( additionalData: Uint8List.fromList('repertory'.toCharArray()),
'repertory'.toCharArray(),
),
key: SecureKey.fromList(sodium, keyHash), key: SecureKey.fromList(sodium, keyHash),
message: Uint8List.fromList(value.toCharArray()), message: Uint8List.fromList(value.toCharArray()),
nonce: sodium.secureRandom(crypto.nonceBytes).extractBytes(), nonce: nonce,
); );
return base64Encode(data); return base64Encode(Uint8List.fromList([...nonce, ...data]));
} }