Skip to content

PilouGit/secure_memory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SecureMemory 🔒

A Rust library for multi-layered secure memory management with hardware-backed encryption, memory protection, and anti-tampering features. Includes Java (JNA) bindings for cross-language integration.

⚠️ Status: Alpha - Not yet production-ready. See limitations before use.

Rust License Status Security


⚠️ ALPHA STATUS: This library is in active development and has not undergone independent security audits. While it implements multiple security layers, it is not yet recommended for production use in critical systems. See Security Analysis for detailed threat model and limitations.

📋 Complete Security Analysis - Comprehensive security analysis covering OWASP Top 10, CWE Top 25, and detailed threat modeling. Includes honest assessment of protections and limitations.


🎯 Features

🛡️ Multi-Layered Security Architecture

SecureMemory implements defense in depth with 6 independent security layers:

1. Hardware-Backed Encryption

  • 🔐 AES-256-GCM - Military-grade authenticated encryption at rest
  • 🔑 TPM Integration - Keys sealed with Trusted Platform Module (optional)
  • 🎲 Cryptographic RNG - Hardware random number generation via TPM
  • 🔒 Process Isolation - Keys bound to specific binaries and PIDs

2. Memory Access Protection (NEW ⭐)

  • 🚫 PROT_NONE by default - Memory inaccessible except during crypto operations
  • 🔓 Dynamic Permissions - mprotect() grants temporary READ/WRITE only when needed
  • ⚡ Microsecond Windows - Access permissions active for microseconds only
  • 💥 Immediate Segfault - Exploit attempts crash instantly

3. Buffer Overflow Detection

  • 🛡️ Random Canaries - 64-bit random values guard memory boundaries
  • 🔍 Continuous Validation - Checked before/after every operation
  • 🚨 Instant Abort - Process termination on corruption detection

4. Anti-Swapping Protection

  • 💾 mlock() - Memory locked in RAM, cannot swap to disk
  • 🔒 mmap() - Kernel-level memory management
  • 🗑️ Secure Cleanup - munlock() + munmap() + zeroization on drop

5. Write-Once Enforcement

  • ✍️ Immutable Secrets - Cryptographically enforced single-write policy
  • 🔐 AAD Protected - Write-once flag included in authenticated encryption
  • 🚫 Bypass-Proof - Cannot be circumvented via memory manipulation

6. Automatic Secure Cleanup

  • 🧹 Guaranteed Zeroing - Memory wiped even on panic/crash
  • ⏱️ RAII Pattern - Cleanup tied to Rust/Java lifecycle
  • 🔍 Verification - Canary checks during cleanup

🌍 Language Support

  • Rust - Native high-performance API with zero-cost abstractions
  • Java - Full-featured JNA bindings with automatic library loading
  • C/C++ - FFI-compatible interface for broad integration

⚡ Advanced Features

  • Hardware Security - TPM 2.0 integration for key sealing (Linux)
  • Thread-Safe - Send + Sync with lock-free operations where possible
  • Performance - AES-NI hardware acceleration, minimal overhead
  • Cross-Platform - Linux (full), macOS (partial), Windows (partial)

📦 Installation

Rust

Add to your Cargo.toml:

[dependencies]
secure_memory = "0.1.0"

Java (Maven)

Requirements: Java 17+ (LTS recommended)

<dependency>
    <groupId>io.github.pilougit.security</groupId>
    <artifactId>secure-memory-java</artifactId>
    <version>1.0.0</version>
</dependency>

The native library is automatically embedded in the JAR - no manual setup required!


⚙️ Configuration

TPM TCTI Selection

By default, SecureMemory uses a TPM simulator (Mssim) for development and testing. You can configure which TPM interface to use via the TPM_TCTI environment variable:

Supported Values:

Value Description Use Case
mssim or simulator TPM Software Simulator Development, testing, CI/CD (default)
device Hardware TPM (/dev/tpm0 or /dev/tpmrm0) Production on physical machines
tabrmd TPM Access Broker & Resource Manager Enterprise deployments

Examples:

# Use TPM simulator (default - no TPM hardware required)
export TPM_TCTI=mssim
cargo run

# Use hardware TPM on Linux (auto-detects /dev/tpm0 or /dev/tpmrm0)
export TPM_TCTI=device
cargo run

# Use TPM Access Broker & Resource Manager
export TPM_TCTI=tabrmd
cargo run

# Java applications
export TPM_TCTI=device
java -jar your-app.jar

Requirements by TCTI:

Simulator (mssim):

  • Install TPM simulator: sudo apt-get install tpm2-tools
  • Start simulator: tpm_server &
  • No hardware TPM needed

Device (device):

  • Physical TPM 2.0 chip required
  • Linux kernel with TPM support
  • Device file: /dev/tpm0 or /dev/tpmrm0

Tabrmd:

  • Install daemon: sudo apt-get install tpm2-abrmd
  • Start daemon: sudo systemctl start tpm2-abrmd

Note: If TPM_TCTI is not set, SecureMemory defaults to mssim (simulator mode) for maximum compatibility during development.

Quick Test:

Run the demo script to test all available TCTI configurations:

./examples/tpm-tcti-demo.sh

This script will automatically detect available TPM interfaces and demonstrate each one.


🚀 Quick Start

Rust - Basic Usage

use secure_memory::secure_memory::SecureMemory;

fn main() {
    // Create a secure memory buffer (256 bytes)
    let mut memory = SecureMemory::new(256).expect("Failed to allocate");

    // Write sensitive data
    memory.write(|buf| {
        let password = b"MySecretPassword123!";
        buf[..password.len()].copy_from_slice(password);
    }).expect("Write failed");

    // Read data back (automatically decrypted)
    memory.read(|buf| {
        let password = std::str::from_utf8(&buf[..20]).unwrap();
        println!("Password: {}", password);
    });

    // Memory is automatically zeroed when dropped
}

Rust - Write-Once Memory

use secure_memory::secure_memory::SecureMemory;

// Create write-once memory (can only be written once)
let mut memory = SecureMemory::new_with_options(256, true)
    .expect("Failed to allocate");

// First write: OK
memory.write(|buf| {
    buf[0] = 42;
}).expect("First write should succeed");

// Second write: ERROR!
let result = memory.write(|buf| {
    buf[0] = 99;
});

assert!(result.is_err()); // Rejected!

Java - Basic Usage

import com.securememory.SecureMemory;
import java.nio.charset.StandardCharsets;

public class Example {
    public static void main(String[] args) {
        // Try-with-resources ensures automatic cleanup
        try (SecureMemory memory = new SecureMemory(256)) {

            // Write sensitive data
            String password = "MySecretPassword123!";
            memory.write(password.getBytes(StandardCharsets.UTF_8));

            // Read data back
            byte[] data = memory.read(password.length());
            String retrieved = new String(data, StandardCharsets.UTF_8);

            System.out.println("Retrieved: " + retrieved);

            // Zero the byte array after use
            for (int i = 0; i < data.length; i++) {
                data[i] = 0;
            }
        } // Memory automatically freed and zeroed here
    }
}

Java - Write-Once Memory

try (SecureMemory memory = new SecureMemory(256, true)) { // write-once = true

    // First write: OK
    memory.write("EncryptionKey".getBytes());

    // Second write: Exception!
    try {
        memory.write("Hacked!".getBytes());
    } catch (IllegalStateException e) {
        System.out.println("Second write blocked: " + e.getMessage());
        // Output: "SECURITY VIOLATION: Attempted to write to write-once memory..."
    }
}

🔬 How It Works

Memory Layout & Protection

┌──────────────────────────────────────────────────────────────────────────────┐
│                        mmap() Region (Page-Aligned)                          │
│                        🔒 PROT_NONE by default                               │
├─────────────┬──────────────┬──────────────────────────────────────┬─────────────┤
│ Canary (8B) │ Write-Once   │ Encrypted Data                       │ Canary (8B) │
│ TPM Random  │ Flag (1B)    │ [Nonce + Ciphertext + GCM Tag]      │ TPM Random  │
└─────────────┴──────────────┴──────────────────────────────────────┴─────────────┘
      ↓              ↓                        ↓                            ↓
   Protected by AAD (Additional Authenticated Data) in AES-GCM

Memory State Transitions:
┌──────────────────┐
│   PROT_NONE      │ ← Default: NO access (segfault on any access)
└────────┬─────────┘
         │
    ┌────▼─────────────────────┐
    │   Operation Required     │
    └────┬─────────────────────┘
         │
    ┌────▼─────────────────────┐
    │ mprotect(PROT_READ)      │ ← Read encrypted data
    └────┬─────────────────────┘
         │
    ┌────▼─────────────────────┐
    │   PROT_NONE              │ ← Back to protected (decrypt in CPU)
    └────┬─────────────────────┘
         │
    ┌────▼─────────────────────┐
    │ mprotect(PROT_WRITE)     │ ← Write encrypted data
    └────┬─────────────────────┘
         │
    ┌────▼─────────────────────┐
    │   PROT_NONE              │ ← Back to protected
    └──────────────────────────┘

⏱️  Access window: ~1-5 microseconds per operation

🔐 Security Layers (Defense in Depth)

Layer 1: Memory Access Control (Hardware-Enforced)

🚫 Default: mmap(PROT_NONE) + mlock()
   • Memory inaccessible to ANY process (including self!)
   • Prevents exploits from reading sensitive data
   • OS kernel enforces via page tables

🔓 Temporary Access: mprotect(PROT_READ) or mprotect(PROT_WRITE)
   • Only during cryptographic operations
   • 1-5 microsecond windows
   • Immediately revoked after use

Layer 2: Encryption (AES-256-GCM)

🔐 Per-Instance Keys
   • Each SecureMemory has unique 256-bit key
   • Keys never reused across instances
   • Keys sealed with TPM (optional)

🎲 Random Nonces
   • Fresh 96-bit nonce per encryption
   • Generated via TPM hardware RNG
   • Prevents replay attacks

✅ Authentication Tag
   • 128-bit GCM tag verifies integrity
   • Includes AAD (canaries + metadata)
   • Decryption fails if tampered

Layer 3: Canary Protection

🛡️ Random Guards
   • 64-bit random canaries from TPM
   • Placed at memory boundaries
   • Included in GCM AAD (double protection)

🔍 Continuous Validation
   • Checked BEFORE every operation
   • Checked AFTER every operation
   • Checked during Drop

💥 Immediate Response
   • Zeroize memory on corruption
   • Abort process (no recovery)
   • Prevents exploit continuation

Layer 4: Write-Once Enforcement

✍️ Cryptographic Guarantee
   • Flag stored in GCM AAD
   • Cannot modify without breaking tag
   • Enforced in Rust + FFI + Java

🚫 Attack Resistance
   • Memory manipulation → GCM verification fails
   • Direct memory write → Canary detection
   • Second write attempt → Rejected before encryption

Layer 5: Anti-Swapping

💾 Memory Locking
   • mlock() prevents kernel swap
   • Secrets never written to disk
   • Survives low-memory conditions

🗑️ Secure Cleanup
   • munlock() before munmap()
   • Zeroization before unlock
   • Prevents remanence

Layer 6: Process Isolation (TPM Mode)

🔑 Binary Binding
   • Hash of executable included in key derivation
   • Modified binary → different keys
   • Prevents trojan replacement

🆔 PID Binding
   • Process ID included in key derivation
   • Each process has unique keys
   • Prevents inter-process attacks

🔒 Attack Surface Reduction

Attack Vector Without SecureMemory With SecureMemory
Memory dump ✅ Plaintext visible ❌ AES-256 encrypted
Process inspection gcore, /proc/mem ❌ PROT_NONE blocks access
Buffer overflow ✅ Arbitrary read/write ❌ Canaries + instant abort
Use-after-free ✅ Old data readable ❌ Zeroized on drop
Disk swap ✅ Secrets on disk ❌ mlock() prevents swap
Cold boot ✅ RAM remanence ❌ Encrypted + ephemeral keys
GDB/ptrace ✅ Debugger reads all ❌ PROT_NONE + encrypted
Second write ✅ Overwrite allowed ❌ Write-once blocks

📚 API Documentation

Rust API

SecureMemory

impl SecureMemory {
    // Create standard memory (allows multiple writes)
    pub fn new(size: usize) -> Option<Self>

    // Create with write-once protection
    pub fn new_with_options(size: usize, write_once: bool) -> Option<Self>

    // Read data (callback receives decrypted buffer)
    pub fn read<F>(&mut self, f: F)
        where F: FnMut(&mut [u8])

    // Write data (returns Err if write-once violation)
    pub fn write<F>(&mut self, f: F) -> Result<(), ()>
        where F: FnMut(&mut [u8])

    // Get buffer size
    pub fn get_size(&self) -> usize
}

Thread Safety

unsafe impl Send for SecureMemory {}
unsafe impl Sync for SecureMemory {}

Java API

SecureMemory

public class SecureMemory implements AutoCloseable {
    // Create standard memory
    public SecureMemory(long size)

    // Create with write-once protection
    public SecureMemory(long size, boolean writeOnce)

    // Write data
    public void write(byte[] data)

    // Read all data
    public byte[] read()

    // Read specific length
    public byte[] read(int length)

    // Query methods
    public boolean isWriteOnce()
    public boolean hasBeenWritten()
    public long getSize()
    public boolean isClosed()

    // Cleanup (automatically called by try-with-resources)
    public void close()
}

Error Codes (FFI)

Code Meaning
0 Success
-1 Invalid parameters
-2 Canary corruption detected
-3 Write-once violation

🧪 Testing

Rust Tests

# Run all tests
cargo test

# Run specific test suite
cargo test write_once
cargo test aad_tamper

# Run with output
cargo test -- --nocapture

# Build release
cargo build --release

Java Tests

cd java

# Run unit tests
mvn test

# Run memory verification
./verify-memory-security.sh

# Run write-once example
mvn compile
java -cp target/classes:... com.securememory.WriteOnceExample

Memory Leak Verification

Java provides tools to verify that secrets don't leak into memory:

# Automated verification
cd java
./verify-memory-security.sh

# Manual heap dump analysis
java -cp target/classes:... com.securememory.MemoryLeakDemo
# In another terminal:
jmap -dump:format=b,file=heap.hprof <PID>
strings heap.hprof | grep "YourSecret"  # Should NOT find it!

See java/MEMORY_VERIFICATION.md for detailed instructions.


🏗️ Project Structure

secure_memory/
├── src/
│   ├── lib.rs                    # Library root
│   ├── secure_memory.rs          # Core SecureMemory (mmap + encryption)
│   ├── secure_memory_ffi.rs      # C FFI bindings for Java/C++
│   ├── secure_key.rs             # Cryptographic key generation
│   ├── tpm_service.rs            # TPM 2.0 service (singleton)
│   ├── process_key_deriver.rs    # Process-bound key derivation
│   └── secure_error.rs           # Error types
│
├── tests/
│   ├── write_once_test.rs        # Write-once functionality tests
│   ├── aad_tamper_test.rs        # AAD authentication tests
│   ├── secure_memory_test.rs     # Core functionality tests
│   └── integration_test.rs       # Integration tests
│
├── java/                         # Java bindings
│   ├── src/main/java/com/securememory/
│   │   ├── SecureMemory.java     # High-level wrapper
│   │   ├── SecureMemoryNative.java  # JNA interface
│   │   ├── NativeLibraryLoader.java # Auto-loading
│   │   ├── Example.java          # Basic example
│   │   ├── WriteOnceExample.java # Write-once example
│   │   ├── MemorySecurityTester.java  # Memory verification
│   │   └── MemoryLeakDemo.java   # Leak detection demo
│   │
│   ├── src/test/java/
│   │   └── SecureMemoryTest.java # Unit tests
│   │
│   ├── pom.xml                   # Maven configuration
│   ├── verify-memory-security.sh # Automated verification
│   └── MEMORY_VERIFICATION.md    # Detailed verification guide
│
├── springboot-example/           # Spring Boot integration example
│   └── src/main/java/...         # Spring Boot app
│
├── Cargo.toml                    # Rust dependencies
├── README.md                     # This file
└── JAVA_BINDINGS.md             # Java integration guide

🔐 Security Considerations

✅ What SecureMemory Protects Against

Threat Protection Mechanism Effectiveness
Memory dumps (gcore, crash dumps) AES-256-GCM encryption + PROT_NONE 🟢 Strong - Data encrypted at rest
Process inspection (/proc/mem, ptrace) mmap(PROT_NONE) + mlock() 🟢 Strong - OS blocks access
Buffer overflows Random canaries + AAD + instant abort 🟢 Strong - Detection + termination
Use-after-free Automatic zeroization on Drop 🟢 Strong - No data remanence
Swap to disk mlock() prevents paging 🟢 Strong - Never touches disk
Cold boot attacks Ephemeral keys + encryption 🟡 Medium - Limited time window
Tampering GCM AAD authentication 🟢 Strong - Cryptographic guarantee
Write-once bypass AAD-protected flag + runtime checks 🟢 Strong - Multi-layer enforcement
Debugger access (GDB) PROT_NONE + encrypted 🟢 Strong - Segfault + ciphertext only
Binary replacement TPM binary hash binding 🟢 Strong - Keys tied to executable
Inter-process leaks TPM PID binding + mlock 🟢 Strong - Per-process isolation
ROP/Code reuse W^X enforcement + canaries 🟡 Medium - Reduces attack surface

❌ What SecureMemory Does NOT Protect Against

Threat Why Not Protected Mitigation
Spectre/Meltdown CPU-level speculation Use hardened kernels, update microcode
DMA attacks Hardware bypass OS security Use IOMMU, physical security
Root/admin access Kernel can override all protections Use HSM, Intel SGX for root isolation
Side-channel timing Not constant-time by design Use dedicated crypto libraries for keys
String interning (Java) JVM pools immutable strings Always use byte[] or char[]
Rowhammer DRAM disturbance attacks Use ECC RAM, recent hardware
Power analysis Hardware side-channel Use secure enclaves (SGX/TrustZone)

⚠️ Threat Model & Assumptions

SecureMemory is designed for:

  • Defense against userspace attackers (malware, exploits, rogue processes)
  • Protection during runtime (active process with secrets in memory)
  • Hardening applications (reduce attack surface, defense in depth)
  • Compliance requirements (PCI-DSS, HIPAA memory protection)

SecureMemory assumes:

  • ⚠️ Trusted kernel - Root/kernel has full memory access
  • ⚠️ Physical security - No physical access to RAM (cold boot, DMA)
  • ⚠️ Correct usage - Developers follow best practices (see below)

📋 Best Practices

✅ DO:

  1. Use SecureMemory for sensitive data

    // ✅ Good: Passwords, keys, tokens
    let mut password_mem = SecureMemory::new(64)?;
    let mut api_key_mem = SecureMemory::new(128)?;
  2. Enable write-once for immutable secrets

    // ✅ Good: Encryption keys, certificates
    let key_mem = SecureMemory::new_with_options(32, true)?;
  3. Zero temporary buffers

    // ✅ Good: Clear after use
    memory.read(|data| {
        process_secret(data);
        data.zeroize(); // Explicit clear
    });
  4. Use RAII/try-with-resources

    // ✅ Good: Automatic cleanup
    try (SecureMemory mem = new SecureMemory(256)) {
        // Use memory...
    } // Automatically freed + zeroed
  5. Use byte[] in Java, never String

    // ✅ Good
    byte[] secret = memory.read();
    
    // ❌ Bad (String is immutable and pooled!)
    String secret = new String(memory.read());
  6. Check for mlock() failures in production

    # Increase locked memory limit
    ulimit -l unlimited  # or specific KiB amount

❌ DON'T:

  1. Store secrets in Java String

    // ❌ BAD: String cannot be erased!
    String password = new String(secretBytes);
  2. Log or print secrets

    // ❌ BAD: Creates copies in log buffers
    println!("Secret: {:?}", secret_data);
  3. Forget to close/drop

    // ❌ BAD: Memory leak + security risk
    SecureMemory mem = new SecureMemory(256);
    // ... forgot to close!
  4. Share across threads without sync

    // ❌ BAD: Data race
    let mem = SecureMemory::new(64)?;
    thread::spawn(move || mem.read(...)); // Undefined behavior
  5. Trust garbage collection

    // ❌ BAD: GC doesn't zero memory!
    byte[] secret = getSecret();
    secret = null; // Secret still in heap!
  6. Disable TPM without good reason

    // ⚠️ Consider: TPM provides stronger guarantees
    // Only disable if TPM unavailable or performance critical

🚀 Performance

Benchmarks (AMD Ryzen 9 5950X)

Operation Time Throughput
Allocation (256B) ~1.2 µs -
Write (1 KB) ~3.5 µs ~285 MB/s
Read (1 KB) ~3.2 µs ~312 MB/s
Write-once check ~0.02 µs -
Drop + zero (1 KB) ~0.8 µs ~1.25 GB/s

Note: Actual performance varies by system. AES-GCM uses hardware acceleration (AES-NI) when available.


🌍 Platform Support

Platform Status Notes
Linux x86_64 ✅ Full mlock(), TPM support
macOS (Intel/ARM) ✅ Full mlock() support
Windows x64 ⚠️ Partial No mlock(), no TPM
Linux ARM64 ✅ Full Tested on Raspberry Pi 4
WASM ❌ Not supported No FFI, no mlock()

🤝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure cargo test and cargo clippy pass
  5. Submit a pull request

Code Quality Standards

# Format code
cargo fmt

# Run lints
cargo clippy -- -D warnings

# Run all tests
cargo test --all

# Build documentation
cargo doc --open

📄 License

This project is dual-licensed under:

You may choose either license.


📖 Additional Documentation


🙏 Acknowledgments

  • aes-gcm crate for authenticated encryption
  • zeroize crate for secure memory wiping
  • JNA for seamless Java integration
  • tss-esapi for TPM support

⚠️ Disclaimer

This library provides strong security guarantees but is provided "as-is" without warranty. Always:

  • Perform security audits for production use
  • Follow secure coding best practices
  • Keep dependencies up to date
  • Test thoroughly in your specific environment

Not a replacement for proper key management, access control, or security architecture.


Built with ❤️ for security-conscious developers

About

secure_memory is a Rust library (with optional Java / FFI bindings) providing secure memory management for sensitive data — passwords, cryptographic keys, secrets, etc. It’s designed to minimize the risk of secrets leaking through memory dumps, swapping, debugging, or buffer overflows.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors