SecureCell is a small educational demo that shows how to store sensitive data in RAM in a way that’s encrypted-at-rest and only readable during short critical sections. It uses:
-
Rust for memory safety and ergonomics
-
Linux page protections (
mmap,mlock,mprotect,MADV_DONTDUMP,PR_SET_DUMPABLE) -
x86-64 Protection Keys (PKU) via inline assembly (
wrpkru/rdpkru) to open/close access without TLB invalidations (when supported) -
A minimal stream-XOR for encryption (for the demo). In real projects, replace it with a vetted cipher (AES-GCM or ChaCha20-Poly1305).
-
Prevent casual memory scraping (e.g., other processes reading
/proc/$pid/mem, core dumps, simple RCE payloads) from easily obtaining secrets. -
Minimize the time windows in which plaintext exists in accessible memory.
-
Make “read/modify” by other processes significantly harder without elevated privileges.
Not a silver bullet: Kernel-level attackers, root with ptrace, physical DMA, or hypervisor access can still defeat user-space defenses.
-
mmap(PROT_NONE)a page-aligned region -
mlockto prevent swapping -
MADV_DONTDUMPandPR_SET_DUMPABLE=0to keep secrets out of core dumps
-
A per-process random key is generated from
OsRng -
Data written with
SecureCell::set()is immediately XOR-encrypted and stored -
On
get(), ciphertext is read, decrypted on the stack, returned to the caller, and then zeroized
-
The mapping is associated with a protection key (
pkey_mprotect) -
Outside critical sections, access is denied by setting the corresponding PKRU bits (inline asm
wrpkru) -
For a read/write, we briefly allow access (clear PKRU AD/WD bits), perform the operation, then deny again
-
If PKU isn’t available, we fallback to toggling
mprotect(weaker, but portable)
-
On
Drop, the region is temporarily made writable; the bytes are overwritten viawrite_volatile -
The key material is zeroized
-
The mapping is unmapped
-
OS: Linux recommended
-
Arch: x86-64 (PKU path). Other arches will build, but only the
mprotectfallback is used. -
Rust: 1.70+ (tested on modern stable)
-
Tooling:
gcc/clang/libc headers for pkey functions (typical on Linux)
Some older distros or kernels may not expose pkey_* syscalls or may not actually enable PKU. The code gracefully falls back to mprotect.
cd securecell
cargo run --release
Example output:
SecureCell demo: protected, encrypted-at-rest memory.
Secret stored (encrypted at rest). Memory is PROT_NONE with PKU denial between accesses.
Decrypted read: Attack at dawn. Bring coffee. 🍺
-
Out of scope to fully prevent: root attackers, kernel exploits, DMA/PCIe sniffers, memory forensics with full privileges, or hypervisor inspection.
-
On Windows/macOS: This exact PKU approach won’t work; you’d use platform-specific features (e.g., VM protection APIs, enclaves/SGX/SEV/TEE if available).
-
Crypto: The demo uses XOR for simplicity. Replace
xor_keystreamwith a vetted AEAD (e.g.,ring,aes-gcm,chacha20poly1305crates) and include nonces + authentication tags.
-
AEAD encryption with per-record nonces and authentication tags
-
Per-thread WRPKRU guard using RAII to minimize enabled window durations
-
Guard pages around the region to catch over/underflows
-
Seccomp to restrict syscalls after setup
-
Key wrapping with KMS/TPM and only deriving the in-RAM key just-in-time
-
Enclaves/TEEs if your deployment platform supports them
-
SecureCell::new(len) -> SecureCell -
SecureCell::set(&mut self, plaintext)— encrypts and stores -
SecureCell::get(&self, out_buf) -> len— decrypts into user buffer -
Automatic zeroization and unmap on
Drop
We use inline asm to call wrpkru/rdpkru which are not regular instructions exposed by portable intrinsics. This shows how Rust and assembly can cooperate: Rust manages safety and lifecycle; assembly toggles hardware protection without flushing the TLB (unlike mprotect), keeping the “open access” window as short and cheap as possible.