fileencrypt

package module
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Dec 1, 2025 License: MPL-2.0 Imports: 4 Imported by: 0

README

go-fileencrypt

CI Go Report Card GoDoc

Secure, streaming file encryption and decryption library for Go using AES-256-GCM. Designed for cross-platform use with memory-safe key handling, chunked processing for large files, and support for external libraries to enhance functionality.

[!WARNING] This library is provided "as-is" under the Mozilla Public License 2.0 (see LICENSE for details). While it implements industry-standard cryptographic primitives (AES-256-GCM), it has not undergone independent security audits. For production use, especially in security-critical applications, you should:

  • Conduct your own security review or hire a professional security auditor
  • Follow the security best practices outlined in this documentation
  • Stay updated on security advisories and updates

The author makes no warranties regarding the library's security or fitness for any particular purpose.

Features

  • Strong Encryption: AES-256-GCM with authenticated encryption
  • Streaming Support: Encrypt/decrypt files of any size without loading into memory
  • Cross-Platform: Works on Linux, macOS, and Windows with platform-specific memory locking
  • Memory Safety: Secure key handling with explicit memory zeroing
  • Progress Tracking: Built-in progress callbacks for long operations
  • Context Support: Cancellation and timeout support for all operations
  • Modern Key Derivation: Argon2id (recommended) and PBKDF2-HMAC-SHA256 support
  • GPU-Resistant: Argon2id provides superior protection against GPU/ASIC attacks

Table of Contents

Installation

go get github.com/gitrgoliveira/go-fileencrypt

Requirements:

  • Go 1.25 or later

Supported Platforms

This library works across all major operating systems:

  • Linux: Full support with memory locking via mlock(2)
  • macOS: Full support with memory locking via mlock(2)
  • Windows: Full support (memory locking is no-op)
Platform-Specific Features

Memory Locking:

  • On Unix-based systems (Linux, macOS), the library uses mlock() to prevent sensitive data from being swapped to disk
  • On Windows, memory locking is currently a no-op (not implemented)
  • All platforms support secure memory zeroing via secure.Zero()

File Permissions:

  • Unix/macOS: Use 0600 permissions for encrypted files (owner read/write only)
  • Windows: NTFS ACLs apply; consider restricting access to the current user

Performance:

  • Performance is consistent across platforms
  • Benchmarks shown in this README were conducted on Apple M1 Pro (ARM64)

Quick Start

Basic File Encryption
package main

import (
       "context"
       "crypto/rand"
       "log"
       "github.com/gitrgoliveira/go-fileencrypt"
       "github.com/gitrgoliveira/go-fileencrypt/secure" // Always import for key zeroing
)

func main() {
       // Generate a random 32-byte key
       key := make([]byte, 32)
       if _, err := rand.Read(key); err != nil {
	       log.Fatal(err)
       }
       defer secure.Zero(key) // Always zero sensitive data
       
       ctx := context.Background()
       
       // Encrypt
       err := fileencrypt.EncryptFile(ctx, "document.pdf", "document.pdf.enc", key)
       if err != nil {
	       log.Fatal(err)
       }
       
       // Decrypt
       err = fileencrypt.DecryptFile(ctx, "document.pdf.enc", "document.pdf", key)
       if err != nil {
	       log.Fatal(err)
       }
}
Password-Based Encryption
package main

import (
	"context"
	"log"
	
	"github.com/gitrgoliveira/go-fileencrypt"
	"github.com/gitrgoliveira/go-fileencrypt/secure"
)

func main() {
	password := []byte("your-secure-password")
	
	// Generate salt (store this with your encrypted file!)
	salt, err := fileencrypt.GenerateSalt(fileencrypt.DefaultSaltSize)
	if err != nil {
		log.Fatal(err)
	}
	
	// Derive key from password using PBKDF2
	key, err := fileencrypt.DeriveKeyPBKDF2(
		password,
		salt,
		fileencrypt.DefaultPBKDF2Iterations, // 600,000 iterations
		fileencrypt.DefaultKeySize,           // 32 bytes
	)
	if err != nil {
		log.Fatal(err)
	}
	defer secure.Zero(key) // Always zero sensitive data
	
	ctx := context.Background()
	err = fileencrypt.EncryptFile(ctx, "secret.txt", "secret.enc", key)
	if err != nil {
		log.Fatal(err)
	}
}
Stream Encryption
// Encrypt from io.Reader to io.Writer
src := bytes.NewReader(plaintext)
var dst bytes.Buffer

err := fileencrypt.EncryptStream(ctx, src, &dst, key)
if err != nil {
	log.Fatal(err)
}

// Decrypt back
encReader := bytes.NewReader(dst.Bytes())
var plainDst bytes.Buffer

err = fileencrypt.DecryptStream(ctx, encReader, &plainDst, key)
if err != nil {
	log.Fatal(err)
}

Usage Examples

Large Files with Progress Tracking
chunkOpt, err := fileencrypt.WithChunkSize(1*1024*1024) // 1MB chunks
if err != nil {
	// handle invalid chunk size (very large or environment-limited)
	// fallback to default chunk size or return error
	// For examples we abort on error
	log.Fatalf("invalid chunk size: %v", err)
}

err = fileencrypt.EncryptFile(ctx, "large_video.mp4", "large_video.enc", key,
	fileencrypt.WithProgress(func(progress float64) {
		// progress is a fraction between 0.0 and 1.0
		fmt.Printf("\rEncrypting: %.1f%%", progress*100)
	}),
	chunkOpt,
)
Context Cancellation
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

err := fileencrypt.EncryptFile(ctx, "source.bin", "encrypted.bin", key)
if err == context.DeadlineExceeded {
	log.Println("Encryption timed out")
}

For more examples, see the examples/ directory and run them locally:

  • examples/basic/ — Basic encryption/decryption
  • examples/with-password/ — Password-based encryption (PBKDF2)
  • examples/with-argon2/ — Password-based encryption with Argon2id
  • examples/large-files/ — Large files with progress tracking (shows WithChunkSize and fractional progress usage)

API Reference

Core Functions
EncryptFile
func EncryptFile(ctx context.Context, srcPath, dstPath string, key []byte, opts ...Option) error

Encrypts a file from srcPath to dstPath using the provided 32-byte key.

Options:

  • WithChunkSize(size int) - Set chunk size (default: DefaultChunkSize = 1MB, allowed range: 1 byte to MaxChunkSize = 10MB).
  • WithProgress(callback func(float64)) - Progress callback (receives a fraction between 0.0 and 1.0).
DecryptFile
func DecryptFile(ctx context.Context, srcPath, dstPath string, key []byte, opts ...Option) error

Decrypts a file from srcPath to dstPath using the provided key.

EncryptStream
func EncryptStream(ctx context.Context, src io.Reader, dst io.Writer, key []byte, opts ...Option) error

Encrypts data from an io.Reader to an io.Writer.

DecryptStream
func DecryptStream(ctx context.Context, src io.Reader, dst io.Writer, key []byte, opts ...Option) error

Decrypts data from an io.Reader to an io.Writer.

Key Derivation
DeriveKeyPBKDF2
func DeriveKeyPBKDF2(password, salt []byte, iterations, keyLen int) ([]byte, error)

Derives an encryption key from a password using PBKDF2-HMAC-SHA256.

Recommended values:

  • iterations: 600,000 (OWASP 2023) or minimum 210,000
  • keyLen: 32 bytes for AES-256
GenerateSalt
func GenerateSalt(size int) ([]byte, error)

Generates a cryptographically secure random salt. Recommended size: 32 bytes.

Secure Memory
secure.Zero
func Zero(b []byte)

Securely zeros a byte slice to prevent key material from remaining in memory.

secure.LockMemory / UnlockMemory
func LockMemory(b []byte) error
func UnlockMemory(b []byte) error

Lock/unlock memory pages (uses mlock on Unix/macOS, no-op on Windows).

Security Considerations

Cryptography
  • Algorithm: AES-256-GCM (Galois/Counter Mode)
  • Key Size: 256 bits (32 bytes)
  • Nonce: 96 bits (12 bytes), randomly generated per file
  • Authentication: 128-bit GCM tag per chunk
  • Key Derivation: PBKDF2-HMAC-SHA256 (600,000 iterations default)
Best Practices

Key Management:

  • Generate keys using crypto/rand (cryptographically secure)
  • Never hardcode keys in source code
  • Use defer secure.Zero(key) to clear key material from memory
  • Store keys securely (HSM, KMS, or encrypted key storage)
  • Use unique keys for different contexts

Password-Based Encryption:

  • Use strong passwords (minimum 12 characters, mixed complexity)
  • Always generate a unique, random salt per encryption
  • Store the salt alongside the encrypted file
  • Use at least 600,000 PBKDF2 iterations (OWASP 2023)

File Handling:

  • Validate decrypted data integrity before use
  • Use secure file permissions (0600 for sensitive files)
  • Delete plaintext securely after encryption (consider shred or srm)
  • Handle authentication failures as potential tampering

Production Deployment:

  • Run security audits before production use
  • Implement proper error handling without leaking sensitive data
  • Use context cancellation for long-running operations
  • Monitor for security advisories and updates

Performance

Benchmarks

Tested on Apple M1 Pro:

Operation File Size Throughput Time
Encryption 1 MB ~949 MB/s ~1.1 ms
Encryption 10 MB ~1361 MB/s ~7.7 ms
Encryption 100 MB ~1039 MB/s ~101 ms
Encryption 1 GB ~235 MB/s ~4.6 s
Decryption 1 MB ~1260 MB/s ~0.8 ms
Decryption 10 MB ~1362 MB/s ~7.7 ms
Decryption 100 MB ~1338 MB/s ~78 ms
Decryption 1 GB ~800 MB/s ~1.3 s
PBKDF2 (600k iter) - - ~76 ms

Chunk Size Impact (10MB file):

  • 64KB chunks: ~1376 MB/s
  • 256KB chunks: ~1478 MB/s
  • 1MB chunks: ~1483 MB/s (default, recommended)
  • 4MB chunks: ~1409 MB/s

Run benchmarks yourself:

go test -bench=. ./benchmark -benchtime=10s
File Format Overhead
  • Header: 20 bytes (12-byte nonce + 8-byte file size)
  • Per-chunk: 20 bytes (4-byte size + 16-byte GCM tag)
  • Example: 1GB file with 1MB chunks = ~20KB overhead (~0.002%)

Documentation

FAQ

How do I store the encryption key?

Keys should never be stored in plaintext. Options include:

  • Hardware Security Modules (HSM): For production environments
  • Key Management Services (KMS): Cloud providers (AWS KMS, Azure Key Vault, etc.)
  • Environment Variables: For development (not recommended for production)
  • Password-based: Derive from user password with PBKDF2
Can I use this for encrypting data in transit?

This library is designed for data at rest (file encryption). For data in transit, use TLS/HTTPS.

How do I handle the salt for password-based encryption?

The salt must be stored alongside the encrypted file. Common approaches:

  • Prepend salt to encrypted file: [32 bytes salt][encrypted data]
  • Store in separate metadata file: file.enc and file.enc.salt
  • Include in file header (requires custom format)
Is this library thread-safe?

Yes. Each encryption/decryption operation is independent and can run concurrently. However, do not share keys across goroutines without proper synchronization (use separate key copies).

What happens if decryption fails?

Decryption failures typically indicate:

  • Wrong key (authentication failed)
  • File corruption or tampering
  • Truncated file

Always treat authentication failures as potential security issues.

Can I encrypt the same file multiple times with the same key?

Yes. Each encryption uses a unique random nonce, so the output will be different each time. However, for better security, consider using different keys for different files.

What about post-quantum cryptography?

Post-quantum cryptography support may be considered in future versions

Environment Variables

FILEENCRYPT_CHUNKSIZE_LIMIT

You can override the default chunk size limit (10MB) by setting the FILEENCRYPT_CHUNKSIZE_LIMIT environment variable. This variable accepts human-readable file sizes, such as 10MB, 1GB, etc.

Example:

export FILEENCRYPT_CHUNKSIZE_LIMIT=50MB

Contributing

Contributions are welcome! Please:

  1. Open an issue to discuss proposed changes
  2. Follow existing code style and conventions
  3. Add tests for new functionality
  4. Update documentation as needed
  5. Run make validate-all before submitting

See CONTRIBUTING.md for details.

License

Mozilla Public License 2.0 - see LICENSE for details.

Acknowledgments

  • Inspired by age and sops
  • Built with Go standard library cryptography
  • OWASP password storage guidelines
  • NIST SP 800-38D (GCM specification)

Documentation

Overview

Package fileencrypt provides secure, streaming file encryption and decryption for Go using AES-256-GCM authenticated encryption.

This library is designed for encrypting files and streams of any size with strong cryptographic primitives, memory-safe key handling, and cross-platform compatibility. It uses chunked processing to handle large files without loading them entirely into memory.

Features

  • Strong authenticated encryption with AES-256-GCM
  • Streaming support for files of any size
  • Cross-platform memory safety (mlock on Unix/macOS)
  • Context support for cancellation and timeouts
  • Progress tracking callbacks
  • Modern key derivation: Argon2id (recommended) and PBKDF2-HMAC-SHA256

Basic Usage

Encrypt and decrypt a file with a random key:

import (
    "context"
    "crypto/rand"
    "github.com/gitrgoliveira/go-fileencrypt"
    "github.com/gitrgoliveira/go-fileencrypt/secure"
)

// Generate a 32-byte encryption key
key := make([]byte, 32)
rand.Read(key)
defer secure.Zero(key) // Always zero sensitive data

ctx := context.Background()

// Encrypt a file
err := fileencrypt.EncryptFile(ctx, "document.pdf", "document.pdf.enc", key)

// Decrypt the file
err = fileencrypt.DecryptFile(ctx, "document.pdf.enc", "document.pdf", key)

Password-Based Encryption

Derive a key from a password using Argon2id (recommended for new applications):

password := []byte("your-secure-password")
salt, _ := fileencrypt.GenerateSalt(fileencrypt.DefaultSaltSize)

key, _ := fileencrypt.DeriveKeyArgon2(
    password, salt,
    fileencrypt.DefaultArgon2Time,      // 3 iterations
    fileencrypt.DefaultArgon2Memory,    // 64 MB
    fileencrypt.DefaultArgon2Threads,   // 4 threads
    fileencrypt.DefaultKeySize,         // 32 bytes
)
defer secure.Zero(key)

// Store the salt alongside your encrypted file - you'll need it for decryption!

Or use PBKDF2 for compatibility with older systems:

key, _ := fileencrypt.DeriveKeyPBKDF2(
    password, salt,
    fileencrypt.DefaultPBKDF2Iterations, // 600,000 iterations
    fileencrypt.DefaultKeySize,          // 32 bytes
)

Stream Encryption

Encrypt data from any io.Reader to any io.Writer:

var input io.Reader  // any reader
var output io.Writer // any writer

err := fileencrypt.EncryptStream(ctx, input, output, key)

Security Considerations

Key Management:

  • Always use crypto/rand for key generation
  • Never hardcode keys in source code
  • Always call secure.Zero(key) to clear keys from memory
  • Store keys securely (HSM, KMS, encrypted storage)

Passwords:

  • Use strong passwords (12+ characters, mixed complexity)
  • Generate unique, random salts (store with encrypted file)
  • Prefer Argon2id over PBKDF2 for better GPU/ASIC attack resistance

File Handling:

  • Use secure file permissions (0600 for sensitive files)
  • Validate decrypted data before use
  • Handle authentication failures as potential tampering

For complete documentation, examples, and security best practices, see: https://github.com/gitrgoliveira/go-fileencrypt

Index

Constants

View Source
const (
	DefaultPBKDF2Iterations = core.DefaultPBKDF2Iterations
	DefaultSaltSize         = core.DefaultSaltSize
	DefaultKeySize          = core.DefaultKeySize
	DefaultArgon2Time       = core.DefaultArgon2Time
	DefaultArgon2Memory     = core.DefaultArgon2Memory
	DefaultArgon2Threads    = core.DefaultArgon2Threads
)

Re-export key derivation constants from internal/core

Variables

View Source
var CalculateChecksum = core.CalculateChecksum

Re-export checksum helpers from internal/core so callers can compute/verify checksums.

View Source
var CalculateChecksumHex = core.CalculateChecksumHex
View Source
var VerifyChecksum = core.VerifyChecksum
View Source
var VerifyChecksumHex = core.VerifyChecksumHex
View Source
var WithAlgorithm = core.WithAlgorithm

WithAlgorithm sets the encryption algorithm (re-exported from internal/core).

View Source
var WithChunkSize = core.WithChunkSize

WithChunkSize sets the chunk size for streaming operations (re-exported from internal/core).

View Source
var WithProgress = core.WithProgress

WithProgress sets a progress callback (re-exported from internal/core).

View Source
var ZeroKey = secure.Zero

ZeroKey securely zeroes a key slice. Always use defer ZeroKey(key) after key generation.

Functions

func DecryptFile

func DecryptFile(ctx context.Context, srcPath, dstPath string, key []byte, opts ...Option) error

DecryptFile decrypts a file.

func DecryptStream

func DecryptStream(ctx context.Context, src io.Reader, dst io.Writer, key []byte, opts ...Option) error

DecryptStream decrypts a stream.

func DeriveKeyArgon2

func DeriveKeyArgon2(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) ([]byte, error)

DeriveKeyArgon2 derives a key from a password using Argon2id. Argon2id is the recommended algorithm for password-based key derivation (2023). It provides better resistance to GPU/ASIC attacks compared to PBKDF2.

OWASP 2023 recommended parameters for interactive logins:

  • time: 3, memory: 65536 (64 MB), threads: 4, keyLen: 32

Re-exported from internal/core for public API.

func DeriveKeyPBKDF2

func DeriveKeyPBKDF2(password, salt []byte, iterations, keyLen int) ([]byte, error)

DeriveKeyPBKDF2 derives a key from a password using PBKDF2-HMAC-SHA256. For new applications, consider using DeriveKeyArgon2 instead (more resistant to GPU attacks). Re-exported from internal/core for public API.

func EncryptFile

func EncryptFile(ctx context.Context, srcPath, dstPath string, key []byte, opts ...Option) error

EncryptFile encrypts a file.

func EncryptStream

func EncryptStream(ctx context.Context, src io.Reader, dst io.Writer, key []byte, opts ...Option) error

EncryptStream encrypts a stream.

func GenerateSalt

func GenerateSalt(size int) ([]byte, error)

GenerateSalt generates a random salt of the specified size. Re-exported from internal/core for public API.

Types

type Option

type Option = core.Option

Option defines functional options for encryption/decryption (re-exported from internal/core).

Directories

Path Synopsis
examples
basic command
Basic example of file encryption and decryption
Basic example of file encryption and decryption
large-files command
Example of encrypting large files with progress tracking
Example of encrypting large files with progress tracking
with-argon2 command
Example of password-based encryption using Argon2id (recommended for new applications)
Example of password-based encryption using Argon2id (recommended for new applications)
with-checksum command
with-password command
Example of password-based encryption using PBKDF2
Example of password-based encryption using PBKDF2
internal
core
decryptor.go: Chunked streaming decryption logic for go-fileencrypt
decryptor.go: Chunked streaming decryption logic for go-fileencrypt
Package secure provides primitives for handling sensitive data securely in memory.
Package secure provides primitives for handling sensitive data securely in memory.

Jump to

Keyboard shortcuts

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