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 ships "as-is" under the Mozilla Public License 2.0 (refer to 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.
- 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
- Installation
- Supported platforms
- Quick start
- Usage examples
- API reference
- Security considerations
- Performance
- Documentation
- Key storage
- Thread safety
- Contributing
- License
go get github.com/gitrgoliveira/go-fileencryptRequirements:
- Go 1.27 or later
This library works across all major operating systems:
- Linux: Full support with memory locking using
mlock(2) - macOS: Full support with memory locking using
mlock(2) - Windows: Full support (memory locking is no-op)
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 a no-op (not implemented)
- All platforms support secure memory zeroing through
secure.Zero()
File Permissions:
- Unix/macOS: Use
0600permissions for encrypted files (owner read/write only) - Windows: NTFS ACLs apply; consider restricting access to the current user
Performance:
- Performance is consistent across platforms
- The benchmarks in this README use an Apple M1 Pro (ARM64)
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)
}
}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)
}
}// 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)
}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,
)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, refer to the examples/ directory and run them locally:
examples/basic/— Basic encryption/decryptionexamples/with-password/— Password-based encryption (PBKDF2)examples/with-argon2/— Password-based encryption with Argon2idexamples/large-files/— Large files with progress tracking (showsWithChunkSizeand fractional progress usage)
The library exposes the following functions for encryption, decryption, key derivation, and secure memory management.
func EncryptFile(ctx context.Context, srcPath, dstPath string, key []byte, opts ...Option) errorEncrypts 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 toMaxChunkSize= 10MB).WithProgress(callback func(float64))- Progress callback (receives a fraction between0.0and1.0).
func DecryptFile(ctx context.Context, srcPath, dstPath string, key []byte, opts ...Option) errorDecrypts a file from srcPath to dstPath using the provided key.
func EncryptStream(ctx context.Context, src io.Reader, dst io.Writer, key []byte, opts ...Option) errorEncrypts data from an io.Reader to an io.Writer.
func DecryptStream(ctx context.Context, src io.Reader, dst io.Writer, key []byte, opts ...Option) errorDecrypts data from an io.Reader to an io.Writer.
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,000keyLen: 32 bytes for AES-256
func GenerateSalt(size int) ([]byte, error)Generates a cryptographically secure random salt. Recommended size: 32 bytes.
func Zero(b []byte)Securely zeros a byte slice to prevent key material from remaining in memory.
func LockMemory(b []byte) error
func UnlockMemory(b []byte) errorLock/unlock memory pages (uses mlock on Unix/macOS, no-op on Windows).
Follow these guidelines to use the library securely.
- 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)
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
shredorsrm) - 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
The following tables summarize throughput and overhead measurements.
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- 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%)
- GoDoc - API documentation
- File Format Specification - Detailed file format description
Never store keys in plaintext. The following options provide secure key storage:
- Hardware Security Modules (HSM): For production environments
- Key Management Services (KMS): Cloud providers (AWS KMS, Azure Key Vault, and other cloud key management services)
- Environment Variables: For development (not recommended for production)
- Password-based: Derive from a user password with PBKDF2
Store the salt alongside the encrypted file. Common approaches include the following:
- Prepend salt to encrypted file:
[32 bytes salt][encrypted data] - Store in a separate metadata file:
file.encandfile.enc.salt - Include in file header (requires custom format)
Decryption failures typically indicate one of the following issues:
- Wrong key (authentication failed)
- File corruption or tampering
- Truncated file
Always treat authentication failures as potential security issues.
Each encryption uses a unique random nonce, so encrypting the same file multiple times with the same key produces different output each time. However, for better security, consider using different keys for different files.
The file format reserves algorithm IDs for post-quantum cryptography (ML-KEM hybrid). Refer to FORMAT.md for details.
Each encryption/decryption operation is independent and can run concurrently. Do not share keys across goroutines without proper synchronization. Use separate key copies instead.
This library encrypts data at rest (file encryption). For data in transit, use TLS/HTTPS.
You can configure runtime behavior with the following environment variables.
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=50MBContributions are welcome! Please:
- Open an issue to discuss proposed changes
- Follow existing code style and conventions
- Add tests for new functionality
- Update documentation as needed
- Run
make validate-allbefore submitting
Refer to CONTRIBUTING.md for details.
Mozilla Public License 2.0 - refer to LICENSE for details.