Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
kcenon::logger::security::audit_logger Class Reference

Secure audit logging with tamper detection. More...

#include <audit_logger.h>

Collaboration diagram for kcenon::logger::security::audit_logger:
Collaboration graph

Public Types

enum class  audit_event {
  logger_started , logger_stopped , writer_added , writer_removed ,
  encryption_key_loaded , encryption_key_rotated , encryption_key_generated , permission_denied ,
  path_traversal_attempt , insecure_permissions_detected , suspicious_activity , configuration_changed ,
  authentication_success , authentication_failure , file_access_denied , file_access_granted
}
 Types of security-relevant events to audit. More...
 

Static Public Member Functions

static void initialize (const std::filesystem::path &audit_file, const secure_key *hmac_key=nullptr)
 Initialize audit logger.
 
static void log_audit_event (audit_event event, const std::string &details, const std::map< std::string, std::string > &metadata={})
 Log an audit event.
 
static bool verify_entry (const std::string &json_entry, const std::string &signature)
 Verify integrity of an audit log entry.
 

Static Private Member Functions

static std::string format_iso8601 (const std::chrono::system_clock::time_point &tp)
 Format timestamp as ISO8601 string.
 
static std::string escape_json (const std::string &str)
 Escape JSON special characters.
 
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 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 std::filesystem::path & get_audit_file ()
 
static std::unique_ptr< secure_key > & get_hmac_key ()
 

Detailed Description

Secure audit logging with tamper detection.

Features:

  • JSON-formatted audit entries
  • HMAC signatures for tamper detection
  • Thread-safe logging
  • Configurable audit file location

Definition at line 44 of file audit_logger.h.

Member Enumeration Documentation

◆ audit_event

Types of security-relevant events to audit.

Enumerator
logger_started 
logger_stopped 
writer_added 
writer_removed 
encryption_key_loaded 
encryption_key_rotated 
encryption_key_generated 
permission_denied 
path_traversal_attempt 
insecure_permissions_detected 
suspicious_activity 
configuration_changed 
authentication_success 
authentication_failure 
file_access_denied 
file_access_granted 

Definition at line 50 of file audit_logger.h.

50 {
67 };

Member Function Documentation

◆ calculate_hmac()

static std::string kcenon::logger::security::audit_logger::calculate_hmac ( const std::string & message,
const secure_key & key )
inlinestaticprivate

Calculate HMAC signature.

Parameters
messageMessage to sign
keyHMAC key
Returns
Hex-encoded signature

Definition at line 271 of file audit_logger.h.

274 {
275#ifdef HAS_OPENSSL_HMAC
276 unsigned char digest[EVP_MAX_MD_SIZE];
277 size_t digest_len = 0;
278
279 // OpenSSL 3.x EVP_MAC API
280 EVP_MAC* mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
281 if (!mac) {
282 return "";
283 }
284
285 EVP_MAC_CTX* ctx = EVP_MAC_CTX_new(mac);
286 if (!ctx) {
287 EVP_MAC_free(mac);
288 return "";
289 }
290
291 OSSL_PARAM params[] = {
292 OSSL_PARAM_construct_utf8_string(
293 OSSL_MAC_PARAM_DIGEST,
294 const_cast<char*>("SHA256"),
295 0
296 ),
297 OSSL_PARAM_END
298 };
299
300 if (EVP_MAC_init(ctx, key.data().data(), key.size(), params) != 1) {
301 EVP_MAC_CTX_free(ctx);
302 EVP_MAC_free(mac);
303 return "";
304 }
305
306 if (EVP_MAC_update(ctx,
307 reinterpret_cast<const unsigned char*>(message.data()),
308 message.size()) != 1) {
309 EVP_MAC_CTX_free(ctx);
310 EVP_MAC_free(mac);
311 return "";
312 }
313
314 if (EVP_MAC_final(ctx, digest, &digest_len, sizeof(digest)) != 1) {
315 EVP_MAC_CTX_free(ctx);
316 EVP_MAC_free(mac);
317 return "";
318 }
319
320 EVP_MAC_CTX_free(ctx);
321 EVP_MAC_free(mac);
322
323 // Convert to hex string
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]);
328 }
329 return hex.str();
330#else
331 // Fallback: simple hash (NOT cryptographically secure)
332 // In production without OpenSSL, use a proper HMAC library
333 size_t hash = 0;
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];
338 }
339 }
340
341 std::ostringstream oss;
342 oss << std::hex << std::setfill('0') << std::setw(16) << hash;
343 return oss.str();
344#endif
345 }

References kcenon::logger::security::secure_key::data(), and kcenon::logger::security::secure_key::size().

Referenced by verify_entry().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ escape_json()

static std::string kcenon::logger::security::audit_logger::escape_json ( const std::string & str)
inlinestaticprivate

Escape JSON special characters.

Definition at line 200 of file audit_logger.h.

200 {
201 std::ostringstream oss;
202 for (char c : str) {
203 switch (c) {
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;
211 default:
212 if (c < 32) {
213 oss << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(c);
214 } else {
215 oss << c;
216 }
217 break;
218 }
219 }
220 return oss.str();
221 }

◆ event_to_string()

static std::string kcenon::logger::security::audit_logger::event_to_string ( audit_event event)
inlinestaticprivate

Convert audit event to string.

Definition at line 226 of file audit_logger.h.

226 {
227 switch (event) {
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";
260 default:
261 return "unknown_event";
262 }
263 }

References authentication_failure, authentication_success, configuration_changed, encryption_key_generated, encryption_key_loaded, encryption_key_rotated, file_access_denied, file_access_granted, insecure_permissions_detected, logger_started, logger_stopped, path_traversal_attempt, permission_denied, suspicious_activity, writer_added, and writer_removed.

◆ format_iso8601()

static std::string kcenon::logger::security::audit_logger::format_iso8601 ( const std::chrono::system_clock::time_point & tp)
inlinestaticprivate

Format timestamp as ISO8601 string.

Definition at line 181 of file audit_logger.h.

183 {
184 auto time_t_value = std::chrono::system_clock::to_time_t(tp);
185 std::tm tm_value;
186#ifdef _WIN32
187 localtime_s(&tm_value, &time_t_value);
188#else
189 localtime_r(&time_t_value, &tm_value);
190#endif
191
192 std::ostringstream oss;
193 oss << std::put_time(&tm_value, "%Y-%m-%dT%H:%M:%S");
194 return oss.str();
195 }

◆ get_audit_file()

static std::filesystem::path & kcenon::logger::security::audit_logger::get_audit_file ( )
inlinestaticprivate

Definition at line 381 of file audit_logger.h.

381 {
382 static std::filesystem::path path;
383 return path;
384 }

Referenced by initialize(), and write_to_audit_log().

Here is the caller graph for this function:

◆ get_hmac_key()

static std::unique_ptr< secure_key > & kcenon::logger::security::audit_logger::get_hmac_key ( )
inlinestaticprivate

Definition at line 386 of file audit_logger.h.

386 {
387 static std::unique_ptr<secure_key> key;
388 return key;
389 }

Referenced by initialize(), and verify_entry().

Here is the caller graph for this function:

◆ get_mutex()

static std::mutex & kcenon::logger::security::audit_logger::get_mutex ( )
inlinestaticprivate

Definition at line 376 of file audit_logger.h.

376 {
377 static std::mutex mutex;
378 return mutex;
379 }

Referenced by initialize().

Here is the caller graph for this function:

◆ initialize()

static void kcenon::logger::security::audit_logger::initialize ( const std::filesystem::path & audit_file,
const secure_key * hmac_key = nullptr )
inlinestatic

Initialize audit logger.

Parameters
audit_filePath to audit log file
hmac_keyHMAC key for tamper detection (optional)

Definition at line 74 of file audit_logger.h.

77 {
78 std::lock_guard lock(get_mutex());
79
80 get_audit_file() = audit_file;
81
82 if (hmac_key) {
83 // Create a copy of the key data (secure_key is move-only)
84 get_hmac_key().reset(new secure_key(hmac_key->data()));
85 }
86
87 // Create audit file directory if needed
88 auto parent = audit_file.parent_path();
89 if (!parent.empty() && !std::filesystem::exists(parent)) {
90 std::filesystem::create_directories(parent);
91 }
92
93 // Set secure permissions on audit file
94 if (std::filesystem::exists(audit_file)) {
95 std::filesystem::permissions(
96 audit_file,
97 std::filesystem::perms::owner_read |
98 std::filesystem::perms::owner_write,
99 std::filesystem::perm_options::replace
100 );
101 }
102 }
static std::filesystem::path & get_audit_file()
static std::unique_ptr< secure_key > & get_hmac_key()

References get_audit_file(), get_hmac_key(), and get_mutex().

Here is the call graph for this function:

◆ log_audit_event()

static void kcenon::logger::security::audit_logger::log_audit_event ( audit_event event,
const std::string & details,
const std::map< std::string, std::string > & metadata = {} )
inlinestatic

Log an audit event.

Parameters
eventEvent type
detailsEvent details
metadataAdditional metadata (key-value pairs)

Definition at line 110 of file audit_logger.h.

113 {}
114 ) {
115 std::lock_guard lock(get_mutex());
116
117 // Skip if not initialized
118 if (get_audit_file().empty()) {
119 return;
120 }
121
122 // 1. Get current timestamp
123 auto now = std::chrono::system_clock::now();
124
125 // 2. Build JSON entry
126 std::ostringstream oss;
127 oss << "{"
128 << "\"timestamp\":\"" << format_iso8601(now) << "\","
129 << "\"event\":\"" << event_to_string(event) << "\","
130 << "\"details\":\"" << escape_json(details) << "\"";
131
132 // 3. Add metadata if present
133 if (!metadata.empty()) {
134 oss << ",\"metadata\":{";
135 bool first = true;
136 for (const auto& [key, value] : metadata) {
137 if (!first) oss << ",";
138 oss << "\"" << escape_json(key) << "\":"
139 << "\"" << escape_json(value) << "\"";
140 first = false;
141 }
142 oss << "}";
143 }
144
145 oss << "}";
146
147 std::string json_entry = oss.str();
148
149 // 4. Calculate HMAC signature (if key is available)
150 std::string signature;
151 if (get_hmac_key()) {
152 signature = calculate_hmac(json_entry, *get_hmac_key());
153 }
154
155 // 5. Write to audit file
156 write_to_audit_log(json_entry, signature);
157 }
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::string format_iso8601(const std::chrono::system_clock::time_point &tp)
Format timestamp as ISO8601 string.
static std::string escape_json(const std::string &str)
Escape JSON special characters.
static void write_to_audit_log(const std::string &json_entry, const std::string &signature)
Write entry to audit log file.

Referenced by kcenon::logger::encrypted_writer::encrypted_writer().

Here is the caller graph for this function:

◆ verify_entry()

static bool kcenon::logger::security::audit_logger::verify_entry ( const std::string & json_entry,
const std::string & signature )
inlinestatic

Verify integrity of an audit log entry.

Parameters
json_entryJSON audit entry
signatureHMAC signature
Returns
true if signature is valid, false otherwise

Definition at line 165 of file audit_logger.h.

168 {
169 if (!get_hmac_key() || signature.empty()) {
170 return false;
171 }
172
173 std::string expected = calculate_hmac(json_entry, *get_hmac_key());
174 return expected == signature;
175 }

References calculate_hmac(), and get_hmac_key().

Here is the call graph for this function:

◆ write_to_audit_log()

static void kcenon::logger::security::audit_logger::write_to_audit_log ( const std::string & json_entry,
const std::string & signature )
inlinestaticprivate

Write entry to audit log file.

Parameters
json_entryJSON audit entry
signatureHMAC signature (optional)

Definition at line 352 of file audit_logger.h.

355 {
356 std::ofstream file(get_audit_file(), std::ios::app);
357 if (!file) {
358 // Cannot log audit event - this is a critical failure
359 // In production, consider alternative logging (syslog, etc.)
360 return;
361 }
362
363 // Write JSON entry
364 file << json_entry;
365
366 // Write signature if present
367 if (!signature.empty()) {
368 file << "\nSIGNATURE:" << signature;
369 }
370
371 file << "\n";
372 file.flush();
373 }

References get_audit_file().

Here is the call graph for this function:

The documentation for this class was generated from the following file: