24#if __has_include(<openssl/hmac.h>)
25#include <openssl/hmac.h>
26#include <openssl/evp.h>
27#include <openssl/core_names.h>
28#include <openssl/params.h>
29#define HAS_OPENSSL_HMAC 1
75 const std::filesystem::path& audit_file,
88 auto parent = audit_file.parent_path();
89 if (!parent.empty() && !std::filesystem::exists(parent)) {
90 std::filesystem::create_directories(parent);
94 if (std::filesystem::exists(audit_file)) {
95 std::filesystem::permissions(
97 std::filesystem::perms::owner_read |
98 std::filesystem::perms::owner_write,
99 std::filesystem::perm_options::replace
112 const std::string& details,
113 const std::map<std::string, std::string>& metadata = {}
123 auto now = std::chrono::system_clock::now();
126 std::ostringstream oss;
130 <<
"\"details\":\"" <<
escape_json(details) <<
"\"";
133 if (!metadata.empty()) {
134 oss <<
",\"metadata\":{";
136 for (
const auto& [key, value] : metadata) {
137 if (!first) oss <<
",";
147 std::string json_entry = oss.str();
150 std::string signature;
166 const std::string& json_entry,
167 const std::string& signature
174 return expected == signature;
182 const std::chrono::system_clock::time_point& tp
184 auto time_t_value = std::chrono::system_clock::to_time_t(tp);
187 localtime_s(&tm_value, &time_t_value);
189 localtime_r(&time_t_value, &tm_value);
192 std::ostringstream oss;
193 oss << std::put_time(&tm_value,
"%Y-%m-%dT%H:%M:%S");
201 std::ostringstream oss;
204 case '"': oss <<
"\\\"";
break;
205 case '\\': oss <<
"\\\\";
break;
206 case '\b': oss <<
"\\b";
break;
207 case '\f': oss <<
"\\f";
break;
208 case '\n': oss <<
"\\n";
break;
209 case '\r': oss <<
"\\r";
break;
210 case '\t': oss <<
"\\t";
break;
213 oss <<
"\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
229 return "logger_started";
231 return "logger_stopped";
233 return "writer_added";
235 return "writer_removed";
237 return "encryption_key_loaded";
239 return "encryption_key_rotated";
241 return "encryption_key_generated";
243 return "permission_denied";
245 return "path_traversal_attempt";
247 return "insecure_permissions_detected";
249 return "suspicious_activity";
251 return "configuration_changed";
253 return "authentication_success";
255 return "authentication_failure";
257 return "file_access_denied";
259 return "file_access_granted";
261 return "unknown_event";
272 const std::string& message,
275#ifdef HAS_OPENSSL_HMAC
276 unsigned char digest[EVP_MAX_MD_SIZE];
277 size_t digest_len = 0;
280 EVP_MAC* mac = EVP_MAC_fetch(
nullptr,
"HMAC",
nullptr);
285 EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
291 OSSL_PARAM params[] = {
292 OSSL_PARAM_construct_utf8_string(
293 OSSL_MAC_PARAM_DIGEST,
294 const_cast<char*
>(
"SHA256"),
300 if (EVP_MAC_init(ctx, key.
data().data(), key.
size(), params) != 1) {
301 EVP_MAC_CTX_free(ctx);
306 if (EVP_MAC_update(ctx,
307 reinterpret_cast<const unsigned char*
>(message.data()),
308 message.size()) != 1) {
309 EVP_MAC_CTX_free(ctx);
314 if (EVP_MAC_final(ctx, digest, &digest_len,
sizeof(digest)) != 1) {
315 EVP_MAC_CTX_free(ctx);
320 EVP_MAC_CTX_free(ctx);
324 std::ostringstream hex;
325 hex << std::hex << std::setfill(
'0');
326 for (
size_t i = 0; i < digest_len; ++i) {
327 hex << std::setw(2) << static_cast<int>(digest[i]);
334 for (
size_t i = 0; i < message.size(); ++i) {
335 hash = hash * 31 + message[i];
336 if (i < key.
size()) {
337 hash ^= key.
data()[i];
341 std::ostringstream oss;
342 oss << std::hex << std::setfill(
'0') << std::setw(16) << hash;
353 const std::string& json_entry,
354 const std::string& signature
367 if (!signature.empty()) {
368 file <<
"\nSIGNATURE:" << signature;
377 static std::mutex mutex;
382 static std::filesystem::path path;
387 static std::unique_ptr<secure_key> key;
Secure audit logging with tamper detection.
static std::string event_to_string(audit_event event)
Convert audit event to string.
static std::string calculate_hmac(const std::string &message, const secure_key &key)
Calculate HMAC signature.
static std::filesystem::path & get_audit_file()
static std::string format_iso8601(const std::chrono::system_clock::time_point &tp)
Format timestamp as ISO8601 string.
static void initialize(const std::filesystem::path &audit_file, const secure_key *hmac_key=nullptr)
Initialize audit logger.
static std::string escape_json(const std::string &str)
Escape JSON special characters.
static std::unique_ptr< secure_key > & get_hmac_key()
static void log_audit_event(audit_event event, const std::string &details, const std::map< std::string, std::string > &metadata={})
Log an audit event.
audit_event
Types of security-relevant events to audit.
@ insecure_permissions_detected
@ encryption_key_generated
static void write_to_audit_log(const std::string &json_entry, const std::string &signature)
Write entry to audit log file.
static std::mutex & get_mutex()
static bool verify_entry(const std::string &json_entry, const std::string &signature)
Verify integrity of an audit log entry.
RAII wrapper for encryption keys with secure memory management.
size_t size() const
Get key size in bytes.
const std::vector< uint8_t > & data() const
Get const reference to key data.
RAII wrapper for encryption keys with secure memory management.