gofilecrypto

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 27, 2026 License: MIT Imports: 15 Imported by: 0

README

go-file-crypto

Zero-dependency file encryption for Go, compatible with @time-file/browser-file-crypto.

Language:

Features

  • Browser-compatible wire format (0x01, 0x02, 0x11, 0x12)
  • AES-256-GCM
  • PBKDF2-SHA256 (100,000 iterations)
  • Password mode + keyfile mode
  • Streaming encryption/decryption for large files
  • Auto-detect decryption for standard + streaming payloads
  • Keyfile generation/parsing/hash utilities
  • Custom profile support (salt/iv/tag/chunk/markers)
  • No external crypto dependency (Go stdlib only, Go 1.24+)

Why

time-file ecosystem already has browser-native encryption.
This module gives the same data format in Go so encrypted files can move between:

  • browser -> go (decrypt)
  • go -> browser (decrypt)

without conversion or migration code.

Requirements

  • Go 1.24+
    • Uses standard library crypto/pbkdf2.

Install

go get github.com/Time-File/go-file-crypto

Quick Start

package main

import (
	"fmt"

	filecrypto "github.com/Time-File/go-file-crypto"
)

func main() {
	plain := []byte("hello-go-file-crypto")

	enc, err := filecrypto.Encrypt(plain, filecrypto.EncryptOptions{
		Password: "secret-password",
	})
	if err != nil {
		panic(err)
	}

	dec, err := filecrypto.Decrypt(enc, filecrypto.DecryptOptions{
		Password: "secret-password",
	})
	if err != nil {
		panic(err)
	}

	fmt.Println(string(dec))
}

API

Standard Encryption
encrypted, err := filecrypto.Encrypt(data, filecrypto.EncryptOptions{
	Password: "secret", // OR KeyData: "<base64>"
})
Standard Decryption (Auto-detect marker)
plain, err := filecrypto.Decrypt(encrypted, filecrypto.DecryptOptions{
	Password: "secret", // OR KeyData: "<base64>"
})
Auto Encryption
encrypted, err := filecrypto.EncryptAuto(data, filecrypto.AutoEncryptOptions{
	Password:      "secret",
	AutoStreaming: true, // stream when size > threshold
	// StreamingThreshold default: 100MB
})
Streaming (Reader/Writer)
err := filecrypto.EncryptReader(src, dst, filecrypto.StreamEncryptOptions{
	Password:  "secret", // OR KeyData
	ChunkSize: 64 * 1024,
})

err = filecrypto.DecryptReader(srcEnc, dstPlain, filecrypto.StreamDecryptOptions{
	Password: "secret", // OR KeyData
})
File Helpers
// Writes streaming format (0x11 or 0x12)
err := filecrypto.EncryptFileStream("plain.bin", "encrypted.bin", filecrypto.StreamEncryptOptions{
	Password: "secret",
})

// Auto-detects standard/streaming marker and decrypts
err = filecrypto.DecryptFile("encrypted.bin", "decrypted.bin", filecrypto.DecryptOptions{
	Password: "secret",
})
Keyfile Utilities
kf, err := filecrypto.GenerateKeyFile()
hash, err := filecrypto.ComputeKeyFileHash(kf.Key)
Detection Utilities
t := filecrypto.DetectEncryptionType(data, filecrypto.Profile{})
ok := filecrypto.IsEncryptedData(data, filecrypto.Profile{})

Error Handling

Primary error codes:

  • PASSWORD_REQUIRED
  • KEYFILE_REQUIRED
  • INVALID_PASSWORD
  • INVALID_KEYFILE
  • INVALID_ENCRYPTED_DATA
  • UNSUPPORTED_FORMAT
  • ENCRYPTION_FAILED
  • DECRYPTION_FAILED

Example:

plain, err := filecrypto.Decrypt(encrypted, filecrypto.DecryptOptions{Password: "wrong"})
if err != nil && filecrypto.IsCryptoErrorCode(err, filecrypto.ErrInvalidPassword) {
	// wrong password
}
_ = plain

Browser Compatibility

This module is intentionally compatible with @time-file/browser-file-crypto format.

  • Standard password:
    • [0x01] + [salt:16] + [iv:12] + [ciphertext||tag]
  • Standard keyfile:
    • [0x02] + [iv:12] + [ciphertext||tag]
  • Stream password:
    • [0x11] + [version] + [chunkSize LE] + [salt] + [baseIV] + [chunks...]
  • Stream keyfile:
    • [0x12] + [version] + [chunkSize LE] + [baseIV] + [chunks...]

Detailed spec:

timefile-cli Integration

timefile-cli can now encrypt files locally before upload using this module.

timefile upload secret.zip --crypto-password "my-pass"
timefile upload secret.zip --crypto-keyfile ./mykey.tfkey

Testing

This repository includes:

  • deterministic unit tests
  • stream corruption/error-path tests
  • browser WebCrypto vector interoperability tests

Run:

go test ./...
go vet ./...

License

MIT. See LICENSE.

Documentation

Index

Constants

View Source
const (
	// Browser-compatible cryptographic defaults.
	SaltLength       = 16
	IVLength         = 12
	KeyLengthBytes   = 32
	AuthTagLength    = 16
	PBKDF2Iterations = 100_000

	EncryptionMarkerPassword       byte = 0x01
	EncryptionMarkerKeyfile        byte = 0x02
	EncryptionMarkerPasswordStream byte = 0x11
	EncryptionMarkerKeyfileStream  byte = 0x12

	StreamFormatVersion byte = 0x01
	DefaultChunkSize         = 64 * 1024

	DefaultStreamingThreshold = 100 * 1024 * 1024 // 100MB
)

Variables

This section is empty.

Functions

func ComputeKeyFileHash

func ComputeKeyFileHash(keyData string) (string, error)

func Decrypt

func Decrypt(encrypted []byte, opts DecryptOptions) ([]byte, error)

func DecryptFile

func DecryptFile(srcPath, dstPath string, opts DecryptOptions) error

DecryptFile auto-detects non-streaming and streaming formats.

func DecryptReader

func DecryptReader(r io.Reader, w io.Writer, opts StreamDecryptOptions) error

func DecryptStreamBytes

func DecryptStreamBytes(data []byte, opts StreamDecryptOptions) ([]byte, error)

func Encrypt

func Encrypt(data []byte, opts EncryptOptions) ([]byte, error)

func EncryptAuto

func EncryptAuto(data []byte, opts AutoEncryptOptions) ([]byte, error)

func EncryptFileStream

func EncryptFileStream(srcPath, dstPath string, opts StreamEncryptOptions) error

EncryptFileStream writes streaming format (0x11 or 0x12) to dstPath.

func EncryptReader

func EncryptReader(r io.Reader, w io.Writer, opts StreamEncryptOptions) error

func EncryptStreamBytes

func EncryptStreamBytes(data []byte, opts StreamEncryptOptions) ([]byte, error)

func GenerateKeyData

func GenerateKeyData() (string, error)

func GenerateKeyDataWithOptions

func GenerateKeyDataWithOptions(opts KeyFileOptions) (string, error)

func IsCryptoErrorCode

func IsCryptoErrorCode(err error, code ErrorCode) bool

func IsEncryptedData

func IsEncryptedData(data []byte, profile Profile) bool

func IsStreamingEncryption

func IsStreamingEncryption(t EncryptionType) bool

Types

type AutoEncryptOptions

type AutoEncryptOptions struct {
	Password           string
	KeyData            string
	AutoStreaming      bool
	StreamingThreshold int
	ChunkSize          int
	Profile            Profile
	Rand               io.Reader
	OnProgress         func(Progress)
}

type CryptoError

type CryptoError struct {
	Code ErrorCode
	Err  error
}

func (*CryptoError) Error

func (e *CryptoError) Error() string

func (*CryptoError) Unwrap

func (e *CryptoError) Unwrap() error

type DecryptOptions

type DecryptOptions struct {
	Password   string
	KeyData    string
	Profile    Profile
	OnProgress func(Progress)
}

type EncryptOptions

type EncryptOptions struct {
	Password   string
	KeyData    string
	Profile    Profile
	Rand       io.Reader
	OnProgress func(Progress)
}

type EncryptionType

type EncryptionType string
const (
	EncryptionTypePassword       EncryptionType = "password"
	EncryptionTypeKeyfile        EncryptionType = "keyfile"
	EncryptionTypePasswordStream EncryptionType = "password-stream"
	EncryptionTypeKeyfileStream  EncryptionType = "keyfile-stream"
	EncryptionTypeUnknown        EncryptionType = "unknown"
)

func DetectEncryptionType

func DetectEncryptionType(data []byte, profile Profile) EncryptionType

type ErrorCode

type ErrorCode string
const (
	ErrInvalidInput         ErrorCode = "INVALID_INPUT"
	ErrPasswordRequired     ErrorCode = "PASSWORD_REQUIRED"
	ErrKeyfileRequired      ErrorCode = "KEYFILE_REQUIRED"
	ErrInvalidPassword      ErrorCode = "INVALID_PASSWORD"
	ErrInvalidKeyfile       ErrorCode = "INVALID_KEYFILE"
	ErrInvalidEncryptedData ErrorCode = "INVALID_ENCRYPTED_DATA"
	ErrEncryptionFailed     ErrorCode = "ENCRYPTION_FAILED"
	ErrDecryptionFailed     ErrorCode = "DECRYPTION_FAILED"
	ErrUnsupportedFormat    ErrorCode = "UNSUPPORTED_FORMAT"
)

type KeyFile

type KeyFile struct {
	Version   int    `json:"version"`
	Algorithm string `json:"algorithm"`
	Key       string `json:"key"`
	CreatedAt string `json:"createdAt"`
}

func GenerateKeyFile

func GenerateKeyFile() (KeyFile, error)

func GenerateKeyFileWithOptions

func GenerateKeyFileWithOptions(opts KeyFileOptions) (KeyFile, error)

func ParseKeyFile

func ParseKeyFile(content []byte, profile Profile) (KeyFile, error)

type KeyFileOptions

type KeyFileOptions struct {
	Profile Profile
	Rand    io.Reader
	Now     func() time.Time
}

type Profile

type Profile struct {
	SaltLength       int
	IVLength         int
	KeyLengthBytes   int
	AuthTagLength    int
	PBKDF2Iterations int

	MarkerPassword       byte
	MarkerKeyfile        byte
	MarkerPasswordStream byte
	MarkerKeyfileStream  byte

	StreamVersion    byte
	DefaultChunkSize int
}

func BrowserCompatProfile

func BrowserCompatProfile() Profile

type Progress

type Progress struct {
	Phase          ProgressPhase
	Progress       int
	ProcessedBytes int64
	TotalBytes     int64
	ProcessedChunk int
}

type ProgressPhase

type ProgressPhase string
const (
	ProgressPhaseDerivingKey ProgressPhase = "deriving_key"
	ProgressPhaseEncrypting  ProgressPhase = "encrypting"
	ProgressPhaseDecrypting  ProgressPhase = "decrypting"
	ProgressPhaseComplete    ProgressPhase = "complete"
)

type StreamDecryptOptions

type StreamDecryptOptions struct {
	Password   string
	KeyData    string
	TotalBytes int64
	Profile    Profile
	OnProgress func(Progress)
}

type StreamEncryptOptions

type StreamEncryptOptions struct {
	Password   string
	KeyData    string
	ChunkSize  int
	TotalBytes int64
	Profile    Profile
	Rand       io.Reader
	OnProgress func(Progress)
}

Jump to

Keyboard shortcuts

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