Skip to main content

Access Logs Implementation

Access logs are cryptographically-signed logs designed to be tamper-proof. By using RSA signatures, blockchain-style hash chaining, and future-proofing with post-quantum cryptography, we can ensure that access logs remain both authentic and tamper-evident, even in the presence of quantum threats.


How Cryptographically-Signed Access Logs Work

Cryptographically signing access logs ensures their integrity (logs have not been altered) and authenticity (logs come from a trusted source). Additionally, blockchain-style hash chaining ensures that even if logs are tampered with, the entire log sequence is compromised and detectable.

Core Concepts:

  1. RSA Signatures:
    • Private key signs log entries.
    • Public key is used to verify signatures and ensure authenticity.
  2. Blockchain-Style Hash Chaining:
    • Each log entry contains a hash of the previous log, forming a chain.
    • Tampering with one entry breaks the chain, making it obvious that the logs have been altered.
  3. Quantum Resistance (Future-Proofing):
    • As RSA is not quantum-safe, a hybrid approach combining RSA with post-quantum algorithms (e.g., lattice-based signatures) is recommended for future deployments.
  4. HMAC (Alternative to RSA):
    • For lower-powered devices or when using secret keys is preferred, HMAC-SHA256 can be used to secure logs.

Implementation Guide

1. RSA Digital Signatures for Log Entries

To ensure that the logs are authentic and tamper-evident, we'll use RSA to sign each log entry. Here's how the implementation would work:

RSA Log Signing Process:

  1. Log Entry is created.
  2. A private RSA key signs the log.
  3. The public RSA key is used for later verification.

Go Implementation:

Here’s how you can implement log signing with RSA in Go.

package main

import (
"crypto/rsa"
"crypto/sha256"
"crypto/rand"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"os"
)

// SignLogEntry signs a log entry using the private RSA key
func SignLogEntry(log string, privateKey *rsa.PrivateKey) ([]byte, error) {
hashed := sha256.Sum256([]byte(log))
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, 0, hashed[:])
if err != nil {
return nil, err
}
return signature, nil
}

// LoadPrivateKey loads an RSA private key from a file
func LoadPrivateKey(filePath string) (*rsa.PrivateKey, error) {
keyFile, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer keyFile.Close()

pemData, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}

block, _ := pem.Decode(pemData)
if block == nil {
return nil, fmt.Errorf("failed to parse PEM block")
}

privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}

return privateKey, nil
}

func main() {
// Example log entry
logEntry := `{"timestamp": "2025-03-08T12:34:56Z", "user": "RFID_12345", "event": "Access Granted"}`

// Load private key
privateKey, err := LoadPrivateKey("private.pem")
if err != nil {
log.Fatal("Error loading private key:", err)
}

// Sign the log entry
signature, err := SignLogEntry(logEntry, privateKey)
if err != nil {
log.Fatal("Error signing log entry:", err)
}

// Output the signed log
fmt.Printf("Log entry: %s\nSignature: %x\n", logEntry, signature)
}

Rust Implementation:

In Rust, we can use the rsa crate to sign the logs.

use rsa::{RsaPrivateKey, RsaPublicKey, PaddingScheme};
use sha2::{Sha256, Digest};
use rand::rngs::OsRng;

fn sign_log_entry(log: &str, private_key: &RsaPrivateKey) -> Vec<u8> {
let mut hasher = Sha256::new();
hasher.update(log.as_bytes());
let hash = hasher.finalize();

private_key.sign(PaddingScheme::PKCS1v15Sign { hash: None }, &hash).expect("Failed to sign log")
}

fn main() {
let log_entry = r#"{"timestamp": "2025-03-08T12:34:56Z", "user": "RFID_12345", "event": "Access Granted"}"#;

// Load private key
let private_key_pem = std::fs::read_to_string("private.pem").expect("Failed to read private key");
let private_key = RsaPrivateKey::from_pem(&private_key_pem).expect("Failed to parse private key");

// Sign the log entry
let signature = sign_log_entry(log_entry, &private_key);

// Output the signed log
println!("Log entry: {}\nSignature: {:?}", log_entry, signature);
}

2. Blockchain-Style Hash Chaining for Log Integrity

Incorporating blockchain-style hash chaining helps detect any tampering with the logs. Each log entry contains a hash of the previous entry.

Go Blockchain Chain Example:

package main

import (
"crypto/sha256"
"fmt"
)

type LogEntry struct {
Timestamp string
User string
Event string
PrevHash string
Hash string
}

func GenerateHash(entry LogEntry) string {
data := entry.Timestamp + entry.User + entry.Event + entry.PrevHash
hash := sha256.Sum256([]byte(data))
return fmt.Sprintf("%x", hash)
}

func main() {
var prevHash string
entries := []LogEntry{
{"2025-03-08T12:34:56Z", "RFID_12345", "Access Granted", prevHash, ""},
{"2025-03-08T12:35:10Z", "RFID_12346", "Access Denied", prevHash, ""},
}

for i := range entries {
entries[i].PrevHash = prevHash
entries[i].Hash = GenerateHash(entries[i])
prevHash = entries[i].Hash
}

for _, entry := range entries {
fmt.Printf("Log Entry: %s\nHash: %s\nPrevious Hash: %s\n\n", entry.Timestamp, entry.Hash, entry.PrevHash)
}
}

3. Quantum Resistance (Future-Proofing)

For future-proofing, consider using post-quantum algorithms (e.g., lattice-based cryptography) to sign logs once quantum computing becomes practical. Until then, combining RSA and post-quantum hybrid approaches can offer a transition path.

Post-Quantum Cryptography Libraries:

  • NTRU, Kyber, and other lattice-based algorithms are promising options for future implementations.

Next Steps

  1. Test and Integrate:

    • Test the RSA-based log signing system in your environment.
    • Consider future-proofing by incorporating hybrid post-quantum algorithms.
  2. Documentation Update:

    • Keep the documentation updated with hybrid cryptographic approaches for future deployments.
  3. Implementation on IoT/Microcontrollers:

    • Integrate the log signing and verification logic into your IoT devices, ensuring private key protection and efficient logging.
  4. Monitor for Quantum Advancements:

    • Stay updated on post-quantum cryptography standards and adjust your approach as needed.

Let me know if you need further help with the implementation or want to dive into C/C++ code examples or post-quantum cryptography in the future!