Help us shape the future of Go! Take the 2026 Go Developer Survey

fde

package module
v0.0.0-...-932d4e3 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: BSD-3-Clause Imports: 6 Imported by: 1

README

go-fde/fde

fde

ci Go Reference

Unified dispatcher for Full-Disk Encryption block devices.

Overview

The fde package provides a single Device interface and a set of dispatcher functions that abstract over three backends:

Backend Type constant Package
LUKS 1/2 fde.LUKS github.com/go-fde/luks
APFS FileVault 2 fde.APFS github.com/go-fde/apfs
Plaintext passthrough fde.CLEAR github.com/go-fde/clear

Pass fde.Auto to any Open or OpenFrom call to auto-detect the format from the on-disk header.

Format detection

Detect(path) and DetectFrom(rw) identify the format by reading the first 36 bytes of the device:

  • Bytes 0–5 equal "LUKS\xba\xbe" → LUKS
  • Bytes 32–35 equal "NXSB" → APFS
  • Otherwise → CLEAR

Usage

Open an existing device (explicit type)
import "github.com/go-fde/fde"

// LUKS
dev, err := fde.Open(fde.LUKS, "/dev/sdb", []byte("passphrase"))

// APFS
dev, err := fde.Open(fde.APFS, "/dev/disk2s2", []byte("passphrase"))

// Plaintext
dev, err := fde.Open(fde.CLEAR, "/path/to/disk.raw", nil)
Open with auto-detection
dev, err := fde.Open(fde.Auto, "/path/to/disk", []byte("passphrase"))
if err != nil {
    log.Fatal(err)
}
defer dev.Close()

buf := make([]byte, 4096)
_, err = dev.ReadAt(buf, 0)
Detect format without opening
kind, err := fde.Detect("/path/to/disk")
switch kind {
case fde.LUKS:
    fmt.Println("LUKS container")
case fde.APFS:
    fmt.Println("APFS FileVault 2 container")
case fde.CLEAR:
    fmt.Println("plaintext device")
}
Layer on top of another block device (e.g. QCOW2)

OpenFrom and CreateFrom accept any value satisfying fde.RW:

interface {
    io.ReaderAt
    WriteAt([]byte, int64) (int, error)
    io.Closer
}
import (
    "github.com/go-fde/fde"
    qcow2 "github.com/go-diskimages/qcow2"
)

qdev, err := qcow2.OpenDevice("disk.qcow2")
if err != nil { log.Fatal(err) }

// Auto-detect: the QCOW2 virtual disk may hold LUKS, APFS, or raw data.
dev, err := fde.OpenFrom(fde.Auto, qdev, []byte("passphrase"))
if err != nil {
    qdev.Close()
    log.Fatal(err)
}
defer dev.Close()
Create (initialise) a new container

Create and CreateFrom write a fresh container header to an existing file and return an opened Device ready for payload I/O. The passphrase is ignored for CLEAR (no header is written).

// Create a new LUKS1 container on a pre-allocated file.
f, _ := os.Create("disk.luks")
f.Close()

dev, err := fde.Create(fde.LUKS, "disk.luks", []byte("passphrase"))
if err != nil { log.Fatal(err) }
defer dev.Close()

// Write payload starting at offset 0 (LUKS) or block 2 (APFS).
dev.WriteAt(myData, 0)

API reference

Opening and format detection
Function Description
Detect(path) (Type, error) Detect format from file header
DetectFrom(rw) (Type, error) Detect format from an io.ReaderAt
Open(kind, path, passphrase) (Device, error) Open device by path; Auto auto-detects
OpenFrom(kind, rw, passphrase) (Device, error) Open device from an RW; Auto auto-detects
OpenLUKS(path, passphrase) (Device, error) LUKS shorthand
OpenLUKSFrom(rw, passphrase) (Device, error) LUKS-on-RW shorthand
OpenAPFS(path, passphrase) (Device, error) APFS shorthand
OpenAPFSFrom(rw, passphrase) (Device, error) APFS-on-RW shorthand
OpenClear(path) (Device, error) Plaintext shorthand
OpenClearFrom(rw) (Device, error) Plaintext-on-RW shorthand
Container creation
Function Description
Create(kind, path, passphrase) (Device, error) Write container header to existing file
CreateFrom(kind, rw, passphrase) (Device, error) Write container header to existing RW
Device interface
Method LUKS offset semantics APFS offset semantics CLEAR offset semantics
ReadAt(p, off) Relative to payload start Absolute from container start Absolute from file start
WriteAt(p, off) Relative to payload start Absolute from container start Absolute from file start
Size() int64 Plaintext payload size (0 if unknown) Always 0 File size at open time
Close() Closes underlying device Closes underlying device Closes underlying device

Offset semantics

LUKS and CLEAR offsets differ from APFS offsets:

  • LUKS ReadAt/WriteAt offsets are relative to payload sector 0 — the LUKS header overhead is hidden.
  • APFS ReadAt/WriteAt offsets are absolute from the container start (byte 0 of the device). Block 0 is the NX superblock, block 1 is the key bag, payload starts at block 2.
  • CLEAR ReadAt/WriteAt offsets are absolute from the file start.

Documentation

Overview

Package fde provides a uniform Device interface for Full-Disk Encryption block devices, abstracting over LUKS, APFS FileVault 2, and plaintext (CLEAR) backends.

Both encrypted backends expose a Device whose ReadAt and WriteAt methods transparently decrypt and encrypt I/O using their respective volume keys. The CLEAR backend is a passthrough that applies no encryption.

Supported backends

  • LUKS 1/2 via github.com/go-fde/luks
  • APFS FileVault 2 via github.com/go-fde/apfs
  • Plaintext passthrough via github.com/go-fde/clear

Usage

// Open a raw LUKS device:
dev, err := fde.OpenLUKS("/path/to/disk.luks", []byte("passphrase"))

// Stack APFS FDE on top of a QCOW2 virtual disk:
qdev, _ := qcow2.OpenDevice("/path/to/disk.qcow2")
dev, err := fde.OpenAPFSFrom(qdev, []byte("passphrase"))

// Auto-detect format and open:
dev, err := fde.Open(fde.Auto, "/path/to/disk", []byte("passphrase"))

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Device

type Device interface {
	io.ReaderAt
	WriteAt(p []byte, off int64) (int, error)
	// Size returns the byte length of the plaintext payload.
	// Returns 0 when the size is not exposed by the backend (APFS).
	Size() int64
	// Close releases all resources held by the device.
	Close() error
}

Device is the uniform interface exposed by all FDE backends. ReadAt and WriteAt transparently decrypt and encrypt data using the volume key.

LUKS offsets are relative to the start of the plaintext payload. APFS offsets are absolute (relative to the start of the container device).

func Create

func Create(kind Type, path string, passphrase []byte) (Device, error)

Create initialises a new FDE container of the given type at path, encrypting it with passphrase. The file must already exist. Returns an opened Device ready for payload I/O. For CLEAR, no initialisation is performed; the file is opened as a passthrough device.

func CreateFrom

func CreateFrom(kind Type, rw RW, passphrase []byte) (Device, error)

CreateFrom initialises a new FDE container of the given type on rw, encrypting it with passphrase. Returns an opened Device ready for payload I/O. For CLEAR, no initialisation is performed; rw is wrapped as a passthrough device.

func Open

func Open(kind Type, path string, passphrase []byte) (Device, error)

Open opens an FDE device of the given type at path, unlocking it with passphrase. It dispatches based on kind; when kind is Auto the format is detected from the file header. For CLEAR devices passphrase is ignored.

func OpenAPFS

func OpenAPFS(path string, passphrase []byte) (Device, error)

OpenAPFS opens the FileVault 2-encrypted APFS container at path, unlocking it with passphrase. path may be a raw disk image or block device file.

func OpenAPFSFrom

func OpenAPFSFrom(rw RW, passphrase []byte) (Device, error)

OpenAPFSFrom opens a FileVault 2 APFS container on top of an existing block device rw, unlocking it with passphrase. Close on the returned Device also closes rw.

func OpenClear

func OpenClear(path string) (Device, error)

OpenClear opens the plaintext block device at path as a passthrough Device. No decryption is applied; I/O is forwarded directly to the file.

func OpenClearFrom

func OpenClearFrom(rw RW) (Device, error)

OpenClearFrom wraps rw as a passthrough Device with no encryption.

func OpenFrom

func OpenFrom(kind Type, rw RW, passphrase []byte) (Device, error)

OpenFrom opens an FDE device of the given type on top of rw, unlocking it with passphrase. When kind is Auto the format is detected from rw's header. For CLEAR devices passphrase is ignored.

func OpenLUKS

func OpenLUKS(path string, passphrase []byte) (Device, error)

OpenLUKS opens the LUKS1/LUKS2 encrypted container at path, unlocking it with passphrase. path may be a raw disk image or block device file.

func OpenLUKSFrom

func OpenLUKSFrom(rw RW, passphrase []byte) (Device, error)

OpenLUKSFrom opens a LUKS container on top of an existing block device rw, unlocking it with passphrase. This allows LUKS to be stacked on a QCOW2 device or any other RW backend. Close on the returned Device also closes rw.

type RW

type RW interface {
	io.ReaderAt
	WriteAt(p []byte, off int64) (int, error)
	io.Closer
}

RW is the minimal read-write-close interface accepted by OpenLUKSFrom and OpenAPFSFrom. It allows FDE to be layered on top of any block device, such as a QCOW2 virtual disk.

type Type

type Type int

Type identifies the FDE backend used by Create and CreateFrom.

const (
	// LUKS selects the LUKS 1/2 backend.
	LUKS Type = iota
	// APFS selects the APFS FileVault 2 backend.
	APFS
	// CLEAR selects the plaintext passthrough backend (no encryption).
	CLEAR
	// Auto causes Open and OpenFrom to detect the format automatically.
	Auto
)

func Detect

func Detect(path string) (Type, error)

Detect reads the header of the file at path and returns the detected Type. Returns CLEAR when no known FDE header is found.

func DetectFrom

func DetectFrom(rw io.ReaderAt) (Type, error)

DetectFrom reads from rw and returns the detected Type. Returns CLEAR when no known FDE header is found.

Jump to

Keyboard shortcuts

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