goshred

package module
v1.0.4 Latest Latest
Warning

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

Go to latest
Published: Jan 27, 2026 License: MIT Imports: 16 Imported by: 0

README

goshred

Go Reference Go Report Card

goshred is a robust, cross-platform Go library for securely deleting files and directories. It goes beyond simple deletion by overwriting data with cryptographically secure random patterns, bypassing operating system caches, obfuscating file metadata, and inspecting the underlying storage medium to warn about limitations (such as SSDs or Copy-on-Write filesystems).

Features

  • Cryptographically Secure Wiping: Uses AES-CTR based PRNG to generate random noise for overwriting data.
  • Direct I/O: Bypasses OS page caches (O_DIRECT on Linux/FreeBSD, O_SYNC on Windows) to ensure data is flushed to the physical disk.
  • Smart Storage Inspection: Automatically detects the filesystem and device type (Rotational HDD vs. SSD/NVMe) to determine if secure deletion is physically possible.
  • Copy-on-Write (CoW) Awareness: Detects filesystems like ZFS, Btrfs, and APFS where standard overwriting is ineffective, requiring a forced override.
  • Metadata Shredding: Renames files multiple times with random characters and shortening lengths before unlinking to hide original filenames.
  • Timestamp Reset: Resets file timestamps to the Unix epoch.
  • Recursive Deletion: Supports shredding entire directories recursively.
  • Verification: Optional read-back verification to ensure data was actually overwritten.
  • SSD TRIM Support: Attempts to punch holes (TRIM) in the file on Linux/SSDs after wiping to aid in data unreachability.

Requirements

  • Go 1.20 or higher

Installation

go get github.com/OpexDevelop/goshred

Usage

Basic Usage

The simplest way to shred a file with default settings (1 pass of random data, metadata obfuscation):

package main

import (
    "log"
    "github.com/OpexDevelop/goshred"
)

func main() {
    err := goshred.File("secret_document.pdf")
    if err != nil {
        log.Fatalf("Failed to shred file: %v", err)
    }
    log.Println("File securely deleted")
}
Advanced Configuration

You can customize the shredding process using functional options:

package main

import (
    "context"
    "log"
    "time"
    "github.com/OpexDevelop/goshred"
)

func main() {
    // Configure shredding options
    err := goshred.File("sensitive_data.db",
        goshred.WithPasses(3),          // Overwrite 3 times
        goshred.WithZeroFill(true),     // Final pass writes all zeros
        goshred.WithVerify(true),       // Read back to verify overwrite
        goshred.WithForce(true),        // Force operation even on CoW/SSD
        goshred.WithBufferSize(4*1024), // 4KB buffer
    )

    if err != nil {
        log.Fatal(err)
    }
}
Using Context

You can cancel a long-running shred operation (e.g., large files or many passes) using FileWithContext:

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

err := goshred.FileWithContext(ctx, "large_file.iso", goshred.WithPasses(3))

Testing

go test -v ./...

Storage Inspection & Safety Levels

goshred attempts to protect you from a false sense of security. Modern storage technologies often make "overwriting" a specific physical block impossible.

Before wiping, goshred inspects the file path:

  1. High Security (Supported): Standard filesystems on rotational drives (ext4, xfs, ntfs on HDD).
  2. Medium Security (SSD/Flash): Flash storage uses wear-leveling. Overwriting logical block X does not guarantee physical block Y is overwritten. goshred will warn or require Force depending on configuration.
  3. Low Security (CoW/Network): Filesystems like ZFS, Btrfs, APFS, ReiserFS, or Network shares. On these systems, overwriting a file simply allocates new blocks and unlinks the old ones, leaving the original data intact on disk.

Behavior: If goshred detects a Low Security environment (e.g., a file on ZFS), it will return ErrNotSupported to prevent a false sense of security. You must use WithForce(true) to proceed anyway.

How It Works

  1. Inspection: Checks filesystem magic numbers and device properties (rotational vs non-rotational).
  2. Permissions: Ensures the file is writable (chmod) if Force is enabled.
  3. Wiping:
    • Opens file with O_DIRECT/O_SYNC.
    • Generates a random AES key and IV.
    • Writes random streams to the file for $N passes.
    • Optionally writes zeros on the final pass.
  4. Verification: Reads the file back to ensure the data on disk matches the pattern (if enabled).
  5. Cleanup:
    • TRIM: On Linux/SSD, calls FALLOC_FL_PUNCH_HOLE.
    • Timestamps: Sets Access/Modify times to 1970-01-01.
    • Obfuscation: Renames secret.txt -> a8f3.txt -> x9.txt -> z (example) to scrub directory entries.
    • Removal: Unlinks the file.

Limitations & Disclaimer

WARNING: Data recovery is a complex field.

  • SSDs/NVMe/Flash: Due to wear leveling and over-provisioning, software-based wiping cannot guarantee 100% data destruction on flash media. The firmware may remap blocks transparently.
  • Journaling/CoW: Metadata journals or snapshots might retain copies of the file metadata or content.
  • Bad Sectors: Hard drives reallocate bad sectors; data in damaged sectors may remain readable by specialized hardware.

For strictly confidential data on modern hardware, physical destruction of the drive is the only method guaranteed to be 100% effective. goshred provides the best effort possible via software.

License

This project is licensed under the MIT License.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrFileNotExist    = errors.New("file does not exist")
	ErrDirNotSupported = errors.New("directories are not supported")
	ErrPermission      = errors.New("permission denied")
	ErrWipeFailed      = errors.New("failed to wipe data")
	ErrRemoveFailed    = errors.New("failed to remove file")
	ErrNotWritable     = errors.New("file is not writable")
	ErrNotSupported    = errors.New("operation not supported on this file system/device (use Force option to override)")
	ErrVerifyFailed    = errors.New("verification failed: data on disk does not match expected pattern")
)

Functions

func File

func File(path string, opts ...Option) error

func FileWithContext

func FileWithContext(ctx context.Context, path string, opts ...Option) (retErr error)

func TrimFile added in v1.0.4

func TrimFile(f *os.File) error

Types

type Config

type Config struct {
	Passes     int
	ZeroFill   bool
	Force      bool
	BufferSize int
	Verify     bool
}

func NewConfig

func NewConfig(opts ...Option) *Config

type FileInfo

type FileInfo struct {
	Level      SecurityLevel
	IsSSD      bool
	IsCoW      bool
	FileSystem string
	Warning    string
}

func Inspect

func Inspect(path string) (*FileInfo, error)

type OnePattern added in v1.0.4

type OnePattern struct{}

func (OnePattern) Fill added in v1.0.4

func (o OnePattern) Fill(p []byte) (int, error)

func (OnePattern) Reset added in v1.0.4

func (o OnePattern) Reset()

type Option

type Option func(*Config)

func WithBufferSize

func WithBufferSize(size int) Option

func WithForce

func WithForce(enable bool) Option

func WithPasses

func WithPasses(n int) Option

func WithVerify added in v1.0.4

func WithVerify(enable bool) Option

func WithZeroFill

func WithZeroFill(enable bool) Option

type Pattern added in v1.0.4

type Pattern interface {
	Fill(p []byte) (n int, err error)
	Reset()
}

type RandomPattern added in v1.0.4

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

func NewRandomPattern added in v1.0.4

func NewRandomPattern() (*RandomPattern, error)

func (*RandomPattern) Fill added in v1.0.4

func (r *RandomPattern) Fill(p []byte) (int, error)

func (*RandomPattern) Reset added in v1.0.4

func (r *RandomPattern) Reset()

type SecurityLevel

type SecurityLevel int
const (
	LevelHigh SecurityLevel = iota
	LevelMedium
	LevelLow
)

type ZeroPattern added in v1.0.4

type ZeroPattern struct{}

func (ZeroPattern) Fill added in v1.0.4

func (z ZeroPattern) Fill(p []byte) (int, error)

func (ZeroPattern) Reset added in v1.0.4

func (z ZeroPattern) Reset()

Jump to

Keyboard shortcuts

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