mlocker

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2025 License: MIT Imports: 13 Imported by: 0

README

mlocker

mlocker is a minimal, high-assurance memory security library for Go. It provides locked, encrypted, and zeroed memory buffers for safely handling secrets like passwords, access tokens, cryptographic keys, and session credentials — all without writing anything to disk or exposing data to garbage collection or memory dumps.

Note The library currently supports Linux only. Running go build or go test on other platforms will print "no packages" because all sources use a Linux build tag.

Designed for modern Zero Trust systems, mlocker ensures secrets live only in a locked memory and are wiped immediately after use.


Introduction

In secure systems, secrets are often protected at rest and in transit — but rarely in memory. Most Go applications keep passwords, tokens, and keys in []byte or string, where they are:

  • Swappable to disk by the OS
  • Vulnerable to memory scraping and heap inspection

mlocker fixes this by:

  • Allocating and locking memory pages with mlock
  • Encrypting secrets even while in RAM
  • Requiring explicit decryption and zeroization
  • Keeping sensitive data completely out of Go’s GC

Problem Statement

Typical secret handling patterns are unsafe:

  • os.Getenv("SECRET_KEY") stays in GC-managed memory
  • []byte values are duplicated or retained unintentionally
  • Memory dumps and swap files or OS unauthorized access can leak tokens and provate keys or any other secret data
  • No standard Go mechanism exists to keep secrets isolated, locked, and zeroed

Features

  • Memory Locking Uses mlock to keep secrets off disk and out of swap files
  • Heap-Free Allocation Secrets created with AllocateLocked are manually allocated with mmap so they avoid Go's heap
  • In-Memory Encryption Encrypts secrets in RAM with AES-GCM via EncryptToMemory
  • Per-Buffer Keys Each buffer derives its own AES-GCM key from the master key. A compromised master key still allows decrypting all buffers.
  • Integrity Verification Optional HMAC checks detect tampering on decrypt or destroy
  • Plaintext Zeroing Set ZeroPlaintext to wipe plaintext after encryption
  • GC-Safe Architecture Buffers created by mlocker avoid Go-managed memory; however plaintext provided by the caller may still reside on the heap.
  • Crypto State on Heap AES-GCM and HMAC objects are instantiated using the standard library, briefly placing derived keys on the Go heap. These objects are wiped immediately after use.
  • No Internal Synchronization SecureBuffer does not guard against concurrent use; callers must serialize access.
  • Secure Destruction Manual Destroy() or Zero() wipes secrets from memory after use
  • Minimal API Simple: EncryptLocked(), EncryptToMemory(), Use(), Destroy()

Example Usage

package main

import (
    "fmt"
    "time"

    "github.com/AlyRagab/Mlocker"
)

func main() {
    // Initialise the master key. Memory pages will be locked on all supported platforms.
    if err := mlocker.Init(); err != nil {
        panic(err)
    }
    defer mlocker.Shutdown() // wipe master key when finished

    // Wipe plaintext after encryption and keep HMAC integrity checks enabled.
    mlocker.ZeroPlaintext = true
    mlocker.IntegrityCheck = true

    // Prepare the plaintext in locked memory to avoid the Go heap.
    secret, err := mlocker.AllocateLocked(len("secret-pass"))
    if err != nil {
        panic(err)
    }
    copy(secret.Bytes(), "secret-pass")

    // Encrypt the secret value into locked memory using a per-buffer key.
    // AES-GCM is used internally by EncryptLocked/EncryptToMemory.
    buf, err := mlocker.EncryptLocked(secret)
    if err != nil {
        panic(err)
    }
    buf.DestroyAfter(5 * time.Second)
    defer buf.Destroy() // secure destruction also verifies integrity
    mlocker.FreeLocked(secret)

    // Encrypt a []byte that may have been allocated on the Go heap.
    heapData := []byte("another secret")
    buf2, err := mlocker.EncryptToMemory(heapData)
    if err != nil {
        panic(err)
    }
    buf2.DestroyAfter(5 * time.Second)
    defer buf2.Destroy()
    mlocker.Zero(heapData)

    // Decrypt when needed; plaintext is wiped immediately after use.
    if err := buf.Use(func(pt []byte) error {
        fmt.Println(string(pt))
        return nil
    }); err != nil {
        panic(err)
    }

}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ZeroPlaintext  bool
	IntegrityCheck = true
)

Functions

func FreeLocked

func FreeLocked(b *LockedBuffer) error

func Init

func Init() error

Init generates a process-local master key.

func Shutdown

func Shutdown() error

Shutdown wipes the master key and allows reinitialization.

func Zero

func Zero(b []byte)

Zero overwrites the provided byte slice with zeroes.

func ZeroLocked

func ZeroLocked(b *LockedBuffer)

Types

type LockedBuffer

type LockedBuffer struct {
	// contains filtered or unexported fields
}

LockedBuffer represents memory allocated outside of Go's heap and locked to prevent swapping.

func AllocateLocked

func AllocateLocked(size int) (*LockedBuffer, error)

func (*LockedBuffer) Bytes

func (b *LockedBuffer) Bytes() []byte

Bytes returns a slice referencing the locked memory.

type SecureBuffer

type SecureBuffer struct {
	// contains filtered or unexported fields
}

SecureBuffer holds encrypted data locked in memory.

func EncryptLocked

func EncryptLocked(data *LockedBuffer) (SecureBuffer, error)

EncryptLocked encrypts data stored in a LockedBuffer. This avoids placing the plaintext on the Go heap. If ZeroPlaintext is true, the input buffer will be zeroed after encryption.

func EncryptToMemory

func EncryptToMemory(data []byte) (SecureBuffer, error)

EncryptToMemory encrypts data using AES-256-GCM and locks the memory. EncryptToMemory encrypts the provided byte slice into a SecureBuffer. The input slice is always wiped before encryption begins, independent of ZeroPlaintext.

func (*SecureBuffer) Decrypt

func (s *SecureBuffer) Decrypt() (*LockedBuffer, error)

Decrypt decrypts the buffer and returns the plaintext. Caller must zero the plaintext after use.

func (*SecureBuffer) Destroy

func (s *SecureBuffer) Destroy() error

Destroy wipes the buffer and unlocks the memory.

func (*SecureBuffer) DestroyAfter

func (s *SecureBuffer) DestroyAfter(d time.Duration)

DestroyAfter schedules the buffer to be destroyed after the provided duration. If called multiple times, any previous timer is stopped.

func (*SecureBuffer) Use

func (s *SecureBuffer) Use(fn func([]byte) error) error

Use decrypts the buffer and passes the plaintext to the provided function. The plaintext is zeroed and freed immediately after the function returns.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL