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/error_utils.hpp"
#include "utils/file.hpp"
#include "utils/hash.hpp"
#include "utils/path.hpp"
#include "utils/string.hpp"
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 {
constexpr std::string_view invalid_chars = "&;|><$()`{}!*?";
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 {
auto name = req.get_param_value("name");
auto prov = provider_type_from_string(req.get_param_value("type"));
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 last_key{key};
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);
res.status = http_error_codes::ok;

View File

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