Documentation
¶
Overview ¶
WARNING: V1 compat reads the entire file into memory. Large legacy files (>= 1 GiB) are rejected with ErrCorrupted to prevent OOM crashes.
WARNING: KDF CANNOT BE CANCELLED.
All *Context functions spawn a goroutine that runs the full Argon2id key derivation to completion, even when ctx is cancelled. The goroutine is "leaked" until KDF finishes — it cannot be interrupted.
This means:
- A cancelled context does NOT speed up a running KDF.
- Memory and CPU for Argon2id are fully consumed regardless of ctx.
- Only the subsequent encrypt/decrypt phases (AES-GCM) can be cancelled.
If you need to bound KDF runtime, adjust Config.Time, Config.Memory, or set a deadline on ctx *before* calling KDF.
Package cipherlock implements AES-256-GCM encryption with Argon2id key derivation.
FORMAT ¶
All versions share a 4-byte magic prefix "CV2\0" followed by a version byte. Unless otherwise noted, multi-byte integers are little-endian.
V2/V3 (single-recipient, non-streaming)
4 bytes Magic: "CV2\0" 1 byte Version: 0x02 or 0x03 1 byte Flags (v0x03 only): bit 0 = checksum present 2 bytes Salt length N bytes Argon2id salt 4 bytes Argon2 time 4 bytes Argon2 memory 1 byte Argon2 threads 4 bytes Key length 12 bytes AES-GCM nonce [32 bytes SHA-256 checksum (v0x03, when flags bit 0 set)] Variable Ciphertext + 16-byte GCM tag
V4 (multi-recipient, non-streaming)
4 bytes Magic: "CV2\0" 1 byte Version: 0x04 1 byte Flags: bit 0 = checksum present 4 bytes Number of recipients For each recipient: 2 bytes Salt length N bytes Argon2id salt 4 bytes Time 4 bytes Memory 1 byte Threads 4 bytes Key length 12 bytes Nonce for key encryption 2 bytes Sealed key length M bytes Encrypted file key + GCM tag 12 bytes File nonce [32 bytes SHA-256 checksum (when flags bit 0 set)] Variable Ciphertext + GCM tag
The plaintext is buffered in memory — use V7 for large files.
V5 (streaming, cleartext metadata)
4 bytes Magic: "CV2\0" 1 byte Version: 0x05 1 byte Flags: bit 0 = checksum present 2 bytes Salt length N bytes Argon2id salt 4 bytes Time 4 bytes Memory 1 byte Threads 4 bytes Key length 4 bytes Chunk size 1 byte Has metadata (0/1) [If metadata:] 2 bytes Filename length M bytes Filename (UTF-8) 8 bytes File size 8 bytes Modification time (Unix nanosecond) [32 bytes SHA-256 checksum (trailer, when flags bit 0 set)] Zero or more data chunks: 12 bytes Nonce 4 bytes Ciphertext + GCM tag length (0 = end of stream) N bytes Ciphertext + 16-byte GCM tag 4 zero bytes (end marker)
V6 (streaming, encrypted metadata)
4 bytes Magic: "CV2\0" 1 byte Version: 0x06 1 byte Flags: bit 0 = checksum present, bit 1 = has metadata 2 bytes Salt length N bytes Argon2id salt 4 bytes Time 4 bytes Memory 1 byte Threads 4 bytes Key length 4 bytes Chunk size [Optional encrypted metadata chunk, when flags bit 1 set:] 12 bytes Nonce 4 bytes Ciphertext length M bytes Ciphertext + GCM tag (decrypts to: nameLen(2)+name+size(8)+mtime(8)) Zero or more data chunks — same as V5. 4 zero bytes (end marker) [32 bytes SHA-256 checksum trailer, when flags bit 0 set]
Metadata is encrypted under the same key as the data so filename and size are not visible without the password. EncryptStreamV2 selects this format automatically when FileMeta is provided.
V7 (streaming, multi-recipient)
4 bytes Magic: "CV2\0" 1 byte Version: 0x07 1 byte Flags: bit 0 = checksum present, bit 1 = has metadata 4 bytes Number of recipients For each recipient: 2 bytes Salt length N bytes Argon2id salt 4 bytes Time 4 bytes Memory 1 byte Threads 4 bytes Key length 12 bytes Nonce for key encryption 2 bytes Sealed key length M bytes Encrypted file key + GCM tag [Optional encrypted metadata chunk — same layout as V6] Zero or more data chunks — same as V5. 4 zero bytes (end marker) [32 bytes SHA-256 checksum trailer, when flags bit 0 set]
A fresh random file key encrypts the data and metadata chunk. The file key is sealed once per recipient with their derived key. This is the streaming replacement for V4 — use EncryptStreamMulti / DecryptStreamMulti.
V8 (asymmetric, X25519)
4 bytes Magic: "CV2\0" 1 byte Version: 0x08 1 byte Flags: bit 0 = checksum present, bit 1 = has metadata 4 bytes Number of X25519 recipients For each recipient: 1 byte Identity type (0x01 = X25519) 32 bytes Ephemeral X25519 public key 12 bytes Nonce for key sealing 48 bytes Sealed file key (AES-256-GCM, ciphertext + 16-byte tag) [Optional encrypted metadata chunk — same layout as V6] Zero or more data chunks — same as V5. 4 zero bytes (end marker) [32 bytes SHA-256 checksum trailer, when flags bit 0 set]
Uses ECDH + HKDF-SHA256 for key agreement. Use --recipient-pubkey (CLI) or EncryptAsymmetric / DecryptAsymmetric (library).
ASCII-armor ¶
When --armor is used, the binary format is base64-encoded with PEM-style delimiters:
-----BEGIN CIPHERLOCK----- <base64, wrapped at 64 columns> -----END CIPHERLOCK-----
Decrypt detects armor automatically.
Example ¶
dir, err := os.MkdirTemp("", "cipherlock")
if err != nil {
return
}
defer os.RemoveAll(dir)
src := filepath.Join(dir, "secret.txt")
os.WriteFile(src, []byte("my secret data"), 0644)
dst := src + ".encrypted"
password := []byte("my-strong-password")
if err := EncryptFile(src, dst, password, nil); err != nil {
return
}
restored := filepath.Join(dir, "restored.txt")
if err := DecryptFile(dst, restored, password); err != nil {
return
}
Index ¶
- Constants
- Variables
- func Armor(w io.Writer, data []byte) error
- func Decrypt(dst io.Writer, src io.Reader, password []byte) error
- func DecryptAsymmetric(dst io.Writer, src io.Reader, identity *X25519Identity) error
- func DecryptContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte) error
- func DecryptDir(source, dest string, password []byte) error
- func DecryptDirContext(ctx context.Context, source, dest string, password []byte) error
- func DecryptFile(source, dest string, password []byte) error
- func DecryptFileV1(source, dest string, password []byte) error
- func DecryptStream(dst io.Writer, src io.Reader, password []byte) error
- func DecryptStreamContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte) error
- func DecryptStreamMultiContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte) error
- func DecryptStreamV2Context(ctx context.Context, dst io.Writer, src io.Reader, password []byte) error
- func Encrypt(dst io.Writer, src io.Reader, password []byte, config *Config) errordeprecated
- func EncryptAsymmetric(dst io.Writer, src io.Reader, recipients []*X25519Recipient, config *Config) error
- func EncryptContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte, ...) error
- func EncryptDir(source, dest string, password []byte, config *Config) error
- func EncryptDirContext(ctx context.Context, source, dest string, password []byte, config *Config) error
- func EncryptFile(source, dest string, password []byte, config *Config) error
- func EncryptMulti(dst io.Writer, src io.Reader, passwords [][]byte, config *Config) errordeprecated
- func EncryptMultiContext(ctx context.Context, dst io.Writer, src io.Reader, passwords [][]byte, ...) errordeprecated
- func EncryptStream(dst io.Writer, src io.Reader, password []byte, config *Config) error
- func EncryptStreamContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte, ...) error
- func EncryptStreamMulti(dst io.Writer, src io.Reader, passwords [][]byte, config *Config) error
- func EncryptStreamMultiContext(ctx context.Context, dst io.Writer, src io.Reader, passwords [][]byte, ...) error
- func EncryptStreamV2(dst io.Writer, src io.Reader, password []byte, config *Config) error
- func EncryptStreamV2Context(ctx context.Context, dst io.Writer, src io.Reader, password []byte, ...) error
- func IsArmored(data []byte) bool
- func IsArmoredReader(r io.Reader) (bool, io.Reader, error)
- func IsEncrypted(path string) (bool, error)
- func NewArmorWriter(w io.Writer) io.WriteCloser
- func NewUnarmorReader(r io.Reader) (io.Reader, error)
- func ReKey(dst io.Writer, src io.Reader, oldPassword, newPassword []byte, config *Config) error
- func ReKeyContext(ctx context.Context, dst io.Writer, src io.Reader, ...) error
- func ReKeyFile(source, dest string, oldPassword, newPassword []byte, config *Config) error
- func SerializeX25519Identity(identity *X25519Identity, passphrase []byte) ([]byte, error)
- func Shred(path string) error
- func ShredWith(path string, fn ShredProgressFn) error
- func Unarmor(r io.Reader) ([]byte, error)
- func UnarmorBytes(data []byte) ([]byte, error)
- type Config
- type FileMeta
- func DecryptAsymmetricWithMeta(dst io.Writer, src io.Reader, identity *X25519Identity) (*FileMeta, error)
- func DecryptFileWithMeta(source, dest string, password []byte) (*FileMeta, error)
- func DecryptStreamMeta(dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)deprecated
- func DecryptStreamMulti(dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)
- func DecryptStreamMultiFromReader(dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)
- func DecryptStreamV2(dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)
- func DecryptWithMeta(dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)
- func DecryptWithMetaContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)
- func ReadStreamMeta(src io.Reader) (*FileMeta, error)
- func ReadStreamMetaWithPassword(src io.Reader, password []byte) (*FileMeta, error)
- type Profile
- type ShredProgressFn
- type X25519Identity
- type X25519Recipient
Examples ¶
Constants ¶
const DefaultChunkSize = 64 * 1024
DefaultChunkSize is the default chunk size (64 KB) used for stream encryption.
Variables ¶
var DefaultConfig = &Config{ SaltLen: 16, Time: 3, Memory: 64 * 1024, Threads: 4, KeyLen: 32, ChunkSize: DefaultChunkSize, }
DefaultConfig is the default configuration used when a nil config is passed. It uses Argon2id with time=3, memory=64MB, threads=4, 16-byte salt, 32-byte key, and 64KB chunk size with no checksum.
var ErrAtLeastOnePassword = errors.New("cipherlock: at least one password required")
ErrAtLeastOnePassword is returned when no passwords are provided for multi-key encryption.
var ErrAuthFailed = errors.New("cipherlock: authentication failed")
ErrAuthFailed is returned when decryption authentication fails. This typically indicates an incorrect password or corrupted data.
var ErrChecksumMismatch = errors.New("cipherlock: checksum mismatch")
ErrChecksumMismatch is returned when the decrypted data's checksum does not match the stored checksum.
var ErrConfigInvalid = errors.New("cipherlock: invalid configuration")
ErrConfigInvalid is returned when Config.Validate() detects invalid parameters.
var ErrCorrupted = errors.New("cipherlock: corrupted data")
ErrCorrupted is returned when the encrypted data is malformed or incomplete.
var ErrEncryptedMeta = errors.New("cipherlock: file metadata is encrypted; password required")
ErrEncryptedMeta is returned by ReadStreamMeta when the file uses an encrypted-metadata format version (v0x06 or v0x07) and the caller must supply a password to ReadStreamMetaWithPassword.
var ErrIdentityNeedsPassphrase = errors.New("cipherlock: identity is encrypted, provide a passphrase")
ErrIdentityNeedsPassphrase is returned when attempting to deserialize an encrypted identity without providing a passphrase.
var ErrInvalidFormat = errors.New("cipherlock: invalid file format")
ErrInvalidFormat is returned when the input does not contain a valid cipherlock header.
var (
ErrNotArmored = errors.New("cipherlock: not an armored file")
)
var ErrUnsupportedIdentity = errors.New("cipherlock: unsupported identity type")
ErrUnsupportedIdentity is returned when an asymmetric identity type is not recognized.
var ErrVersionMismatch = errors.New("cipherlock: unsupported version")
ErrVersionMismatch is returned when the cipherlock format version is not supported.
var MagicArmorHeader = []byte(armorHeader)
MagicArmorHeader is the ASCII armor header line as a byte slice. It can be used to detect whether a byte stream uses the cipherlock armored format before calling Unarmor or IsArmored.
Functions ¶
func Armor ¶ added in v1.1.0
Armor writes data to w in ASCII-armor format (base64 encoded with header/footer lines). It returns any write error from the underlying io.Writer.
Example ¶
var encrypted bytes.Buffer
Encrypt(&encrypted, bytes.NewReader([]byte("armored data")), []byte("password"), nil)
var armored bytes.Buffer
if err := Armor(&armored, encrypted.Bytes()); err != nil {
return
}
func Decrypt ¶
Decrypt decrypts data read from src using password and writes plaintext to dst. It supports all format versions (v2, v3, v0x04 multi-key, v0x05 stream, v0x06 stream with encrypted metadata, v0x07 streaming multi-recipient). Returns ErrInvalidFormat, ErrVersionMismatch, ErrAuthFailed, or ErrChecksumMismatch on failure. To recover FileMeta attached to a v0x06/v0x07 container use DecryptWithMeta.
Example ¶
var encrypted bytes.Buffer
Encrypt(&encrypted, bytes.NewReader([]byte("hello")), []byte("password"), nil)
var plaintext bytes.Buffer
err := Decrypt(&plaintext, &encrypted, []byte("password"))
if err != nil {
return
}
func DecryptAsymmetric ¶ added in v1.1.1
DecryptAsymmetric decrypts a v0x08 asymmetric cipherlock file from src and writes the plaintext to dst. The identity is used to unseal the file key.
It returns ErrInvalidFormat, ErrVersionMismatch, ErrAuthFailed, or ErrChecksumMismatch on failure.
func DecryptContext ¶ added in v1.1.1
DecryptContext is a context-aware wrapper around Decrypt. It cancels decryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func DecryptDir ¶
DecryptDir decrypts a cipherlock file containing a tar.gz archive and extracts it. The output directory defaults to source without the .cipherlock or .encrypted suffix.
It returns errors from os.Open, Decrypt, or gzip/tar extraction, including ErrInvalidFormat, ErrVersionMismatch, or ErrAuthFailed from the decrypt step.
func DecryptDirContext ¶ added in v1.1.1
DecryptDirContext is a context-aware wrapper around DecryptDir. It cancels directory decryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func DecryptFile ¶
DecryptFile decrypts a source file and writes the plaintext to a destination file. If dest is empty, the .encrypted or .cipherlock suffix is stripped, or .decrypted is appended.
It returns errors from os.Open/os.Create, or ErrInvalidFormat, ErrVersionMismatch, ErrAuthFailed, or ErrChecksumMismatch.
func DecryptFileV1 ¶
DecryptFileV1 decrypts a v1-format encrypted file using PBKDF2 key derivation. This is provided for backward compatibility with legacy cipherlock files.
WARNING: The entire file is loaded into memory. Large legacy files may cause out-of-memory crashes. Files >= 1 GiB are rejected upfront.
It returns ErrCorrupted if the ciphertext is too large (>= 1 GiB) and ErrInvalidFormat if the ciphertext is too short.
func DecryptStream ¶ added in v1.1.1
DecryptStream decrypts a stream-format cipherlock file from src and writes plaintext to dst. It is a convenience wrapper around DecryptStreamMeta that discards the FileMeta.
It returns ErrInvalidFormat if src does not start with the cipherlock magic, ErrVersionMismatch for an unrecognized version, ErrAuthFailed on wrong password or tampered ciphertext, or ErrChecksumMismatch if the embedded checksum does not match.
func DecryptStreamContext ¶ added in v1.1.1
DecryptStreamContext is a context-aware wrapper around DecryptStream. It cancels stream decryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func DecryptStreamMultiContext ¶ added in v1.1.1
func DecryptStreamMultiContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte) error
DecryptStreamMultiContext is a context-aware wrapper around the v0x07 streaming multi-recipient decrypt path. Metadata is always returned via ReadStreamMetaWithPassword when needed.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func DecryptStreamV2Context ¶ added in v1.1.1
func DecryptStreamV2Context(ctx context.Context, dst io.Writer, src io.Reader, password []byte) error
DecryptStreamV2Context is a context-aware wrapper around DecryptStreamV2. It cancels v0x06 streaming decryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func Encrypt
deprecated
Encrypt encrypts data read from src using password and writes ciphertext to dst. It is a convenience wrapper around EncryptStream and always produces the streaming format (v0x05). The config parameter controls Argon2 parameters and whether to include a checksum. Returns ErrAuthFailed if authentication fails.
Deprecated: Encrypt is identical to EncryptStream. Prefer EncryptStream for clarity.
Example ¶
var buf bytes.Buffer
err := Encrypt(&buf, bytes.NewReader([]byte("hello")), []byte("password"), nil)
if err != nil {
return
}
func EncryptAsymmetric ¶ added in v1.1.1
func EncryptAsymmetric(dst io.Writer, src io.Reader, recipients []*X25519Recipient, config *Config) error
EncryptAsymmetric encrypts src to dst using the v0x08 asymmetric streaming format. The data is encrypted with a random file key using AES-256-GCM, and the file key is sealed once per recipient. Each recipient can independently decrypt the file.
It returns an error if no recipients are provided.
func EncryptContext ¶ added in v1.1.1
func EncryptContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte, config *Config) error
EncryptContext is a context-aware wrapper around Encrypt. It cancels encryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled. Only the AES-GCM encrypt phase can be cancelled early.
Example ¶
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var buf bytes.Buffer
err := EncryptContext(ctx, &buf, bytes.NewReader([]byte("context data")), []byte("password"), nil)
if err != nil {
return
}
func EncryptDir ¶
EncryptDir encrypts a directory by tar+gzipping it and encrypting the archive. The result is written to dest (or source+.cipherlock if dest is empty).
It returns errors from os.Create, tar/gzip writing, or Encrypt.
func EncryptDirContext ¶ added in v1.1.1
func EncryptDirContext(ctx context.Context, source, dest string, password []byte, config *Config) error
EncryptDirContext is a context-aware wrapper around EncryptDir. It cancels directory encryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func EncryptFile ¶
EncryptFile encrypts a source file and writes the ciphertext to a destination file. If dest is empty, the source path with a .encrypted suffix is used.
The output format is v0x05 (streaming) by default. When config.FileMeta is set the output is v0x06 so the metadata chunk is encrypted (v0x05 would leak the original filename and mtime in the cleartext header). EncryptFile explicitly selects EncryptStreamV2 in that case.
It returns errors from os.Open/os.Create, or any error returned by Encrypt or EncryptStreamV2 (see those functions for details).
func EncryptMulti
deprecated
added in
v1.1.1
EncryptMulti encrypts data using multiple passwords, each of which can decrypt independently. It generates a random file key, seals it under each password, and stores all recipient entries in the header. Returns ErrAtLeastOnePassword if no passwords are provided.
Deprecated: EncryptMulti produces a non-streaming v0x04 file, which buffers the full plaintext in memory. New code should use EncryptStreamMulti (v0x07) for streaming, or EncryptStreamV2 (v0x06) for single-recipient. The v0x04 format is still readable and remains for backward compatibility.
Example ¶
var buf bytes.Buffer
passwords := [][]byte{[]byte("alice"), []byte("bob"), []byte("charlie")}
src := bytes.NewReader([]byte("shared secret"))
err := EncryptMulti(&buf, src, passwords, nil)
if err != nil {
return
}
func EncryptMultiContext
deprecated
added in
v1.1.1
func EncryptMultiContext(ctx context.Context, dst io.Writer, src io.Reader, passwords [][]byte, config *Config) error
EncryptMultiContext is a context-aware wrapper around EncryptMulti. It cancels multi-key encryption if the context is done before completion.
Deprecated: EncryptMulti (and this wrapper) is retained only for v0x04 backward compatibility. New code should use EncryptStreamMulti (v0x07).
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func EncryptStream ¶ added in v1.1.1
EncryptStream encrypts src using password with a streaming (chunked) format. It supports large data sizes by processing data in chunks. The config controls Argon2 parameters, chunk size, checksumming, and optional FileMeta.
When config.FileMeta is set, EncryptStream automatically produces the v0x06 format (encrypted metadata chunk) instead of v0x05 (cleartext metadata). This avoids leaking the original filename, size, or modification time in the header.
It returns a ChunkSize bound error when config.ChunkSize exceeds maxChunkSize.
Example ¶
var buf bytes.Buffer
err := EncryptStream(&buf, bytes.NewReader([]byte("stream data")), []byte("password"), nil)
if err != nil {
return
}
func EncryptStreamContext ¶ added in v1.1.1
func EncryptStreamContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte, config *Config) error
EncryptStreamContext is a context-aware wrapper around EncryptStream. It cancels stream encryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func EncryptStreamMulti ¶ added in v1.1.1
EncryptStreamMulti encrypts src to dst using the v0x07 streaming multi-recipient format. A fresh random file key encrypts the data (and optional metadata chunk), and the file key is sealed once per password. Each password can independently decrypt the file. The config controls Argon2id parameters, chunk size, optional SHA-256 checksum, and optional FileMeta. Returns ErrAtLeastOnePassword if no passwords are provided.
Unlike the legacy v0x04 EncryptMulti this routine streams the plaintext and never loads the entire input into memory, so it is safe for arbitrarily large files.
func EncryptStreamMultiContext ¶ added in v1.1.1
func EncryptStreamMultiContext(ctx context.Context, dst io.Writer, src io.Reader, passwords [][]byte, config *Config) error
EncryptStreamMultiContext is a context-aware wrapper around EncryptStreamMulti. It cancels v0x07 streaming multi-recipient encryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func EncryptStreamV2 ¶ added in v1.1.1
EncryptStreamV2 encrypts src using password with the v0x06 streaming format. Unlike v0x05, the optional FileMeta is stored as an encrypted chunk so it is not visible without the password. Use this when you need streaming encryption and want to keep the original filename and size confidential.
It returns a ChunkSize bound error when config.ChunkSize exceeds maxChunkSize.
func EncryptStreamV2Context ¶ added in v1.1.1
func EncryptStreamV2Context(ctx context.Context, dst io.Writer, src io.Reader, password []byte, config *Config) error
EncryptStreamV2Context is a context-aware wrapper around EncryptStreamV2. It cancels v0x06 streaming encryption if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func IsArmored ¶ added in v1.1.0
IsArmored reports whether data begins with a cipherlock armor header.
func IsArmoredReader ¶ added in v1.1.0
IsArmoredReader peeks at the reader to determine if the stream starts with an armor header. It returns the result along with a new reader that includes the peeked bytes.
func IsEncrypted ¶
IsEncrypted reports whether the file at path is a cipherlock file. It detects both the binary format (CV2\0 magic bytes) and the ASCII-armored format (-----BEGIN CIPHERLOCK----- header). It returns false without error if the file cannot be read or is too short.
Example ¶
dir, err := os.MkdirTemp("", "cipherlock")
if err != nil {
return
}
defer os.RemoveAll(dir)
plainFile := filepath.Join(dir, "plain.txt")
os.WriteFile(plainFile, []byte("public data"), 0644)
encFile := plainFile + ".encrypted"
EncryptFile(plainFile, encFile, []byte("password"), nil)
ok, _ := IsEncrypted(encFile)
_ = ok
ok, _ = IsEncrypted(plainFile)
_ = ok
func NewArmorWriter ¶ added in v1.1.1
func NewArmorWriter(w io.Writer) io.WriteCloser
NewArmorWriter returns a writer that base64-encodes anything written to it and emits the result on w as ASCII-armored cipherlock data (header, wrapped at armorLineLen-character lines, footer). Close must be called to flush the base64 encoder, emit the final partial line, and write the footer; callers should defer Close.
The armor header is written on the first Write call (not on Close), so a partial output that never receives Close will have a header but no footer. Callers MUST call Close after checking the encrypt error to ensure the armor footer is present.
The returned writer is not safe for concurrent use.
func NewUnarmorReader ¶ added in v1.1.1
NewUnarmorReader returns an io.Reader that decodes ASCII-armored cipherlock data on the fly. It scans r for the armorHeader, then base64-decodes each subsequent line, and stops at armorFooter.
Use NewUnarmorReader to pipe an armored source directly into a streaming Decrypt path without buffering the full plaintext in memory. If the input does not begin with armorHeader, NewUnarmorReader returns the original reader unchanged so callers can transparently handle both armored and raw inputs.
The returned reader is not safe for concurrent reads.
func ReKey ¶ added in v1.1.1
ReKey decrypts data from src with oldPassword and re-encrypts it with newPassword. The output format mirrors the input format:
- v0x05 in -> v0x05 out
- v0x06 in -> v0x06 out (preserves the attached FileMeta)
- v0x07 in -> v0x07 out (collapses the recipient list to newPassword)
For all streaming inputs the operation is performed without buffering the entire plaintext. For legacy v0x02/v0x03/v0x04 inputs the plaintext is held in memory during re-encryption.
It returns ErrInvalidFormat, ErrVersionMismatch, ErrAuthFailed, ErrChecksumMismatch, or ErrCorrupted from the decrypt step, or any encrypt error from the re-encrypt step.
func ReKeyContext ¶ added in v1.1.1
func ReKeyContext(ctx context.Context, dst io.Writer, src io.Reader, oldPassword, newPassword []byte, config *Config) error
ReKeyContext is a context-aware wrapper around ReKey. It cancels streaming re-key if the context is done before completion.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func ReKeyFile ¶ added in v1.1.1
ReKeyFile decrypts a file with oldPassword and re-encrypts it with newPassword. If dest is empty, the source file is overwritten in place.
The in-place case (source == dest) is implemented as a write to a sibling tempfile followed by Shred(source) + atomic rename. This guarantees the source is preserved if the rekey fails partway: the old behavior was to os.Create(dest) which truncates the file to zero bytes before any decryption runs, leaving the user with an empty file and a "wrong password" error.
It returns errors from os.Open/os.Create, or any error from ReKey (ErrInvalidFormat, ErrAuthFailed, etc.).
Example ¶
dir, err := os.MkdirTemp("", "cipherlock")
if err != nil {
return
}
defer os.RemoveAll(dir)
src := filepath.Join(dir, "secret.txt")
os.WriteFile(src, []byte("my secret data"), 0644)
encrypted := src + ".encrypted"
oldPass := []byte("old-password")
EncryptFile(src, encrypted, oldPass, nil)
newPass := []byte("new-password")
if err := ReKeyFile(encrypted, "", oldPass, newPass, nil); err != nil {
return
}
func SerializeX25519Identity ¶ added in v1.1.1
func SerializeX25519Identity(identity *X25519Identity, passphrase []byte) ([]byte, error)
SerializeX25519Identity serializes an identity's private key to a PEM-like armored format. If passphrase is non-nil, the key is encrypted with Argon2id + AES-256-GCM.
func Shred ¶ added in v1.1.0
Shred securely overwrites a file with random data followed by zeros, then removes it.
Example ¶
dir, err := os.MkdirTemp("", "cipherlock")
if err != nil {
return
}
defer os.RemoveAll(dir)
path := filepath.Join(dir, "secret.txt")
os.WriteFile(path, []byte("sensitive data"), 0644)
if err := Shred(path); err != nil {
return
}
func ShredWith ¶ added in v1.2.0
func ShredWith(path string, fn ShredProgressFn) error
ShredWith is like Shred but calls fn after each write to report progress. fn may be nil.
func Unarmor ¶ added in v1.1.0
Unarmor reads ASCII-armor encoded data from r and returns the decoded bytes. It buffers the entire stream into memory; for large armored inputs use NewUnarmorReader to stream the decoded bytes into a downstream reader.
It returns ErrNotArmored if the input does not contain a valid armor header, or a base64 decode error if the encapsulated data is malformed.
func UnarmorBytes ¶ added in v1.1.0
UnarmorBytes decodes ASCII-armor encoded data and returns the original bytes.
It returns ErrNotArmored if the data does not contain a valid armor header, or a base64 decode error if the encapsulated portion is malformed.
Example ¶
var encrypted bytes.Buffer
Encrypt(&encrypted, bytes.NewReader([]byte("secret")), []byte("mypass"), nil)
var armored bytes.Buffer
Armor(&armored, encrypted.Bytes())
raw, err := UnarmorBytes(armored.Bytes())
if err != nil {
return
}
var plaintext bytes.Buffer
if err := Decrypt(&plaintext, bytes.NewReader(raw), []byte("mypass")); err != nil {
return
}
Types ¶
type Config ¶
type Config struct {
SaltLen int
Time uint32
Memory uint32
Threads uint8
KeyLen uint32
Checksum bool
ChunkSize int
FileMeta *FileMeta
Compression bool
}
Config holds encryption parameters including Argon2id key derivation settings, checksum behavior, chunk size, optional file metadata, and compression.
func (*Config) ApplyProfile ¶ added in v1.1.1
ApplyProfile applies non-zero Profile fields to the Config. Only Time, Memory, Threads, and Checksum are applied; zero values are skipped.
type FileMeta ¶ added in v1.1.1
FileMeta contains metadata about an encrypted file including its name, size, and modification time.
func DecryptAsymmetricWithMeta ¶ added in v1.2.0
func DecryptAsymmetricWithMeta(dst io.Writer, src io.Reader, identity *X25519Identity) (*FileMeta, error)
DecryptAsymmetricWithMeta is the metadata-aware form of DecryptAsymmetric. The returned *FileMeta is non-nil when the encrypted file was created with FileMeta attached (original filename, size, modification time).
func DecryptFileWithMeta ¶ added in v1.1.1
DecryptFileWithMeta is the metadata-aware form of DecryptFile. The returned *FileMeta is non-nil only when the source was a v0x06 or v0x07 container with a FileMeta attached.
It returns errors from os.Open/os.Create, or any error returned by DecryptWithMeta (see that function for details).
func DecryptStreamMeta
deprecated
added in
v1.1.1
DecryptStreamMeta decrypts a stream-format cipherlock file (v0x05, v0x06, or v0x07) and returns the FileMeta attached at encrypt time. The plaintext is streamed to dst. The returned *FileMeta is nil if the source had no metadata.
Deprecated: DecryptStreamMeta is identical to DecryptWithMeta. Prefer DecryptWithMeta.
It returns ErrInvalidFormat, ErrVersionMismatch, ErrAuthFailed, or ErrChecksumMismatch on failure.
func DecryptStreamMulti ¶ added in v1.1.1
DecryptStreamMulti handles the v0x07 streaming multi-recipient body. The magic header and version byte have already been consumed; r contains the recipient list followed by the chunked body. Returns the FileMeta when present.
It returns ErrAuthFailed on wrong password or tampered ciphertext, or ErrCorrupted for malformed input.
func DecryptStreamMultiFromReader ¶ added in v1.1.1
DecryptStreamMultiFromReader is a convenience wrapper for DecryptStreamMulti that reads and validates the magic + version prefix.
It returns ErrInvalidFormat if src does not start with the cipherlock magic, or ErrVersionMismatch for an unrecognized version.
func DecryptStreamV2 ¶ added in v1.1.1
DecryptStreamV2 decrypts a v0x06 stream-format cipherlock file. The returned FileMeta is non-nil only if the source file was encrypted with a FileMeta attached.
It returns ErrInvalidFormat, ErrAuthFailed, ErrCorrupted, or ErrChecksumMismatch.
func DecryptWithMeta ¶ added in v1.1.1
DecryptWithMeta is the metadata-aware form of Decrypt. The returned *FileMeta is non-nil only when the source was encrypted with v0x06 or v0x07 and had a FileMeta attached; v0x02 through v0x05 return nil. It exists so that downstream code can recover the original filename and modification time without an extra ReadStreamMetaWithPassword call.
It returns ErrInvalidFormat if src does not start with the cipherlock magic, ErrVersionMismatch for an unrecognized format version, ErrAuthFailed on wrong password or tampered ciphertext, or ErrChecksumMismatch if the embedded SHA-256 checksum does not match the decrypted plaintext.
func DecryptWithMetaContext ¶ added in v1.1.1
func DecryptWithMetaContext(ctx context.Context, dst io.Writer, src io.Reader, password []byte) (*FileMeta, error)
DecryptWithMetaContext is a context-aware wrapper around DecryptWithMeta. It cancels decryption if the context is done before completion and returns the FileMeta (if present, v0x06/v0x07 only) alongside the decrypt error.
NOTE: Context cancellation does not interrupt an in-progress Argon2id key derivation. The spawned goroutine runs the KDF to completion even after ctx is cancelled.
func ReadStreamMeta ¶ added in v1.1.1
ReadStreamMeta reads the FileMeta from a stream-format cipherlock header without decrypting the data. Returns nil if the file is not in stream format or has no metadata. For files that use the v0x06 or v0x07 format (which store metadata as an encrypted chunk) it returns ErrEncryptedMeta; callers should use ReadStreamMetaWithPassword in that case.
func ReadStreamMetaWithPassword ¶ added in v1.1.1
ReadStreamMetaWithPassword reads the FileMeta from any stream-format cipherlock header (v0x05, v0x06, v0x07) by supplying a password. For v0x05 files the password is unused and the metadata is read in cleartext. For v0x06 / v0x07 files the password and KDF are required to unseal the metadata chunk. Returns ErrAuthFailed if the password does not unlock a v0x06 or v0x07 file. Returns nil (no error) if the file has no metadata attached.
type Profile ¶ added in v1.1.1
type Profile struct {
Time uint32 `json:"time"`
Memory uint32 `json:"memory"`
Threads uint8 `json:"threads"`
Checksum bool `json:"checksum"`
Compression bool `json:"compression"`
}
Profile defines Argon2id parameters that can be applied to a Config. Fields are JSON-tagged for serialization.
type ShredProgressFn ¶ added in v1.2.0
type X25519Identity ¶ added in v1.1.1
type X25519Identity struct {
PrivateKey []byte // 32 bytes seed/scalar
PublicKey []byte // 32 bytes point
}
X25519Identity is a private key that can decrypt data encrypted to its public key.
func DeserializeX25519Identity ¶ added in v1.1.1
func DeserializeX25519Identity(data, passphrase []byte) (*X25519Identity, error)
DeserializeX25519Identity deserializes an identity from the PEM-like armored format. If the identity was encrypted, passphrase must be provided.
func GenerateX25519Keypair ¶ added in v1.1.1
func GenerateX25519Keypair() (*X25519Identity, error)
GenerateX25519Keypair generates a new X25519 key pair from crypto/rand.
func IdentityFromSSHPrivateKey ¶ added in v1.2.0
func IdentityFromSSHPrivateKey(pemData []byte) (*X25519Identity, error)
IdentityFromSSHPrivateKey parses a PEM-encoded SSH private key (Ed25519) and returns an X25519Identity derived from it. Ed25519 and X25519 share the same curve (Curve25519); the seed is converted via SHA-512 + standard X25519 clamping. The resulting identity can be used to decrypt files that were encrypted to the derived X25519 public key.
For RSA and ECDSA keys, it returns ErrUnsupportedKeyType.
func X25519IdentityFromPrivateKey ¶ added in v1.1.1
func X25519IdentityFromPrivateKey(privKey []byte) (*X25519Identity, error)
X25519IdentityFromPrivateKey derives the public key from a private key seed.
type X25519Recipient ¶ added in v1.1.1
type X25519Recipient struct {
PublicKey []byte // 32 bytes
}
X25519Recipient is a public key that can encrypt data for its corresponding identity.
func NewX25519Recipient ¶ added in v1.1.1
func NewX25519Recipient(pubKey []byte) (*X25519Recipient, error)
NewX25519Recipient creates a recipient from a raw 32-byte public key.