Documentation
¶
Overview ¶
Copyright © 2025 Logicos Software
atomic.go implements atomic file write operations.
This module provides safe file writing by:
- Writing to a temporary file in the same directory
- Using atomic rename to replace the target file
- Cleaning up temporary files on failure
- Preserving original file on any error
This prevents partial/corrupt files from being written in case of errors, power loss, or crashes during encryption/decryption.
Copyright © 2025 Logicos Software ¶
d.go implements the 'd' command - a quick/shorthand version of 'decrypt'.
This command provides a simplified interface for common decryption use cases:
- Minimal flags required (just the input file)
- Automatic output filename (removes .ykc extension or adds .dec)
- Optional in-place decryption with -F flag
The 'd' command is designed for everyday use, while 'decrypt' provides the full command interface with explicit input/output flags.
Troubleshooting tips are included in the command help for common errors.
Copyright © 2025 Logicos Software ¶
decrypt.go implements the 'decrypt' command for file decryption.
This module provides file decryption using the YubiKey's private key to perform ECDH key agreement. The decryption process:
- Parse the file header to extract cryptographic parameters
- Perform ECDH using the YubiKey (requires PIN + touch)
- Derive the wrap key from the shared secret
- Optionally incorporate the passphrase if the file was encrypted with one
- Unwrap the file key using ChaCha20-Poly1305
- Stream-decrypt all chunks using the file key
Security Requirements:
- YubiKey must be present and contain the matching private key
- Correct PIV PIN must be entered
- Physical touch of the YubiKey is required
- If passphrase was used during encryption, it must be provided
Copyright © 2025 Logicos Software ¶
e.go implements the 'e' command - a quick/shorthand version of 'encrypt'.
This command provides a simplified interface for common encryption use cases:
- Minimal flags required (just the input file)
- Automatic output filename (adds .ykc extension)
- Uses sensible defaults (slot 9d, ChaCha20, 1 MiB chunks)
- Optional in-place encryption with -F flag
The 'e' command is designed for everyday use, while 'encrypt' provides full control over all encryption parameters.
Copyright © 2025 Logicos Software ¶
encrypt.go implements the 'encrypt' command for file encryption.
This module provides full-featured file encryption using ECDH key agreement with a YubiKey-stored public key (or a provided recipient string). The encryption process:
- Generates an ephemeral EC key pair
- Performs ECDH with the recipient's public key to derive a shared secret
- Uses HKDF to derive a wrap key from the shared secret
- Optionally incorporates a passphrase using Argon2id
- Generates a random file key and wraps it with ChaCha20-Poly1305
- Stream-encrypts the file in chunks using the file key
File Format:
- Magic header "YKCRYPT1" + version + metadata
- Ephemeral public key for ECDH
- Salt values for key derivation
- Wrapped file key (encrypted with AEAD)
- Sequence of length-prefixed encrypted chunks
- Zero-length end marker
Copyright © 2025 Logicos Software ¶
errors.go implements structured error types for better UX.
This module provides:
- Categorized error types (YubiKey, File, Crypto, Input)
- User-friendly error messages with troubleshooting hints
- Error wrapping with context preservation
- Retry suggestions for transient errors
Copyright © 2025 Logicos Software ¶
export.go implements the 'export' command for exporting recipient strings.
The recipient string contains the public key information needed to encrypt files for a particular YubiKey. Once exported, the recipient string can be:
- Shared with others who want to encrypt files for you
- Stored in a configuration file for automated encryption
- Used on systems where the YubiKey is not available
The recipient string format is: ykcrypt1:<slotHex>:<curveId>:<base64PublicKey>
This allows encryption without the YubiKey present - only decryption requires the physical YubiKey (with PIN and touch).
Copyright © 2025 Logicos Software ¶
init.go implements the 'init' command for provisioning PIV slots.
This command generates a new EC key pair on the YubiKey's secure element and stores a self-signed certificate containing the public key. The certificate enables later retrieval of the public key for encryption operations without requiring the YubiKey to perform cryptographic operations.
The generated key uses:
- ECDH-capable elliptic curve key (P-256 or P-384)
- PIN policy: Always required (protects against unauthorized use)
- Touch policy: Always required (prevents remote/automated attacks)
Copyright © 2025 Logicos Software ¶
multirecipient.go implements multiple recipient encryption support.
This module provides:
- Multi-recipient file format (YKCRYPT2)
- Wrapped key blocks for each recipient
- Re-wrapping without re-encrypting payload
- Recipient rotation (add/remove recipients)
File Format for Multi-Recipient (YKCRYPT2):
- Magic header "YKCRYPT2" (8 bytes)
- Version (1 byte)
- CipherID (1 byte)
- Flags (1 byte)
- Metadata section (authenticated, optional)
- Number of recipients (2 bytes)
- For each recipient:
- RecipientBlock (slot, curve, ephemeral pub, wrapped key)
- NoncePrefix + ChunkSize
- Encrypted chunks (same as YKCRYPT1)
This allows adding/removing recipients by re-wrapping the file key without decrypting and re-encrypting the entire payload.
Copyright © 2025 Logicos Software ¶
rewrap.go implements the 'rewrap' command for recipient management.
This command allows:
- Adding new recipients to an encrypted file
- Removing recipients from an encrypted file
- Re-wrapping the file key without re-encrypting the payload
This is useful for:
- Key rotation (add new key, remove old key)
- Sharing files with additional users
- Revoking access for specific recipients
Copyright © 2025 Logicos Software ¶
Package cmd implements all CLI commands for ykcrypt using the Cobra library.
This package provides:
- init: Provision PIV slots with EC keys
- encrypt/e: Encrypt files using ECDH key agreement
- decrypt/d: Decrypt files using YubiKey
- export: Export recipient public key strings
- version: Display version information
All cryptographic operations use industry-standard algorithms:
- ECDH with P-256 or P-384 curves for key agreement
- XChaCha20-Poly1305 or AES-256-GCM for symmetric encryption
- HKDF-SHA256 for key derivation
- Argon2id for passphrase-based key stretching
Package cmd provides utility functions, types, and constants for ykcrypt.
This file contains:
- Version information variables (set via ldflags)
- File format constants (magic bytes, curve IDs, cipher IDs)
- Header struct and serialization/deserialization
- Recipient string parsing and generation
- Cryptographic utility functions (key derivation, AEAD creation)
- YubiKey interaction helpers
- Error handling utilities
Copyright © 2025 Logicos Software ¶
version.go implements the 'version' command.
This command displays version information for ykcrypt, including:
- Semantic version number
- Git commit hash
- Build timestamp
- Go compiler version
Version information is embedded at build time via ldflags:
go build -ldflags "-X ykcrypt/cmd.Version=1.0.0 \
-X ykcrypt/cmd.GitCommit=$(git rev-parse HEAD) \
-X ykcrypt/cmd.BuildTime=$(date -Iseconds) \
-X ykcrypt/cmd.GoVersion=$(go version)"
Index ¶
- Constants
- Variables
- func CipherName(cipherID uint8) string
- func CopyFileAtomic(src, dst string) error
- func CurveFromID(id uint8) (ecdh.Curve, error)
- func DeriveWrapKey(sharedSecret, salt, passSalt []byte, passphrase string) ([]byte, error)
- func Execute()
- func ExitWithClassifiedError(err error)
- func ExitWithError(err error)
- func ExitWithErrorMsg(format string, args ...any)
- func MakeChunkNonce(prefix []byte, idx uint64, cipherID uint8) []byte
- func MakeContainerCert(pub *ecdsa.PublicKey, cn string) ([]byte, *x509.Certificate, error)
- func MakePINPromptAuth(prompt func() (string, error)) piv.KeyAuth
- func MustPromptPassphrase(prompt string) string
- func MustRand(n int) []byte
- func NewFileAEAD(fileKey []byte, cipherID uint8) (cipher.AEAD, error)
- func NoncePrefixSize(cipherID uint8) int
- func OpenYubiKey(reader string) (*piv.YubiKey, func(), error)
- func ParseCipherName(name string) (uint8, error)
- func ParseManagementKey(s string) ([]byte, error)
- func ParseSlot(s string) (piv.Slot, error)
- func PromptHidden(prompt string) (string, error)
- func ReadU16Bytes(r io.Reader) ([]byte, error)
- func RecipientFromECDSAPublicKey(slot piv.Slot, pub *ecdsa.PublicKey) (string, error)
- func SlotFromKey(k uint32) (piv.Slot, error)
- func UnwrapKeyFromBlock(block *RecipientBlock, ecdhFunc func(*ecdh.PublicKey) ([]byte, error), ...) ([]byte, error)
- func WriteFileAtomic(path string, data []byte, allowOverwrite bool) error
- func WriteU16Bytes(w io.Writer, b []byte) error
- type AtomicWriter
- type ErrorCategory
- type Header
- type Metadata
- type MultiHeader
- type Recipient
- type RecipientBlock
- type YKCryptError
- func ClassifyError(err error) *YKCryptError
- func ErrAtomicWriteFailed(path string, cause error) *YKCryptError
- func ErrDecryptionFailed(cause error) *YKCryptError
- func ErrEmptyPassphrase() *YKCryptError
- func ErrFileAlreadyExists(path string) *YKCryptError
- func ErrFileNotFound(path string, cause error) *YKCryptError
- func ErrFilePermission(path string, cause error) *YKCryptError
- func ErrInvalidChunkSize(size int) *YKCryptError
- func ErrInvalidMagic(got string) *YKCryptError
- func ErrInvalidRecipient(details string) *YKCryptError
- func ErrInvalidVersion(version uint8) *YKCryptError
- func ErrKeyUnwrapFailed(cause error) *YKCryptError
- func ErrNoRecipientMatch() *YKCryptError
- func ErrTruncatedHeader(cause error) *YKCryptError
- func ErrUnsupportedCipher(cipherID uint8) *YKCryptError
- func ErrUnsupportedCurve(curveID uint8) *YKCryptError
- func ErrYubiKeyConditionsNotSatisfied(cause error) *YKCryptError
- func ErrYubiKeyNotFound() *YKCryptError
- func ErrYubiKeyPINBlocked(cause error) *YKCryptError
- func ErrYubiKeySlotEmpty(slot string, cause error) *YKCryptError
- func ErrYubiKeyTouchTimeout(cause error) *YKCryptError
- func ErrYubiKeyWrongPIN(retries int, cause error) *YKCryptError
Constants ¶
const ( CipherChaCha20 uint8 = 1 // XChaCha20-Poly1305 (default, 256-bit key, 192-bit nonce) CipherAES256 uint8 = 2 // AES-256-GCM (256-bit key, 96-bit nonce) )
Cipher identifiers for symmetric encryption. These are stored in the header to identify which cipher was used.
Variables ¶
var ( Version = "dev" // Semantic version (e.g., "1.0.0") BuildTime = "unknown" // Build timestamp GitCommit = "unknown" // Git commit hash GoVersion = "unknown" // Go compiler version )
Version information variables. These are set via ldflags during the build process:
go build -ldflags "-X ykcrypt/cmd.Version=1.0.0 -X ykcrypt/cmd.GitCommit=abc123 ..."
Functions ¶
func CipherName ¶
CipherName returns a human-readable name for a cipher ID. Used for display purposes in logs and error messages.
func CopyFileAtomic ¶
CopyFileAtomic copies a file atomically to a new location. It reads from src and writes atomically to dst.
func CurveFromID ¶
CurveFromID returns the ECDH curve corresponding to a curve ID. Supports P-256 (curveP256=1) and P-384 (curveP384=2).
Returns error for unsupported curve IDs.
func DeriveWrapKey ¶
DeriveWrapKey derives a 256-bit wrap key from the ECDH shared secret. The derivation uses HKDF-SHA256 with the provided salt and a fixed info string.
If a passphrase is provided, the key is further processed:
- Argon2id is used to derive a key from the passphrase
- HMAC-SHA256 combines the HKDF output with the passphrase-derived key
This provides defense in depth - an attacker needs both the YubiKey (for ECDH) and the passphrase to derive the correct wrap key.
Parameters:
- sharedSecret: ECDH shared secret from key agreement
- salt: Random salt for HKDF (from header)
- passSalt: Random salt for Argon2id (from header, empty if no passphrase)
- passphrase: User passphrase (empty if not using second factor)
Returns the 32-byte wrap key or error.
func Execute ¶
func Execute()
Execute adds all child commands to the root command and sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd. If an error occurs during command execution, the program exits with status code 1.
func ExitWithClassifiedError ¶
func ExitWithClassifiedError(err error)
ExitWithClassifiedError prints a classified error with hints and exits.
func ExitWithError ¶
func ExitWithError(err error)
ExitWithError prints an error message to stderr and exits with code 1. Does nothing if err is nil.
This is the standard way to handle fatal errors in ykcrypt commands.
func ExitWithErrorMsg ¶
ExitWithErrorMsg formats and prints an error message to stderr, then exits with code 1. Uses fmt.Sprintf-style formatting.
This is the standard way to handle fatal errors with custom messages.
func MakeChunkNonce ¶
MakeChunkNonce creates a unique nonce for encrypting a specific chunk. The nonce is constructed from a random prefix and the chunk index.
For XChaCha20-Poly1305 (24-byte nonce):
- Bytes 0-15: Random prefix
- Bytes 16-23: Big-endian chunk index
For AES-256-GCM (12-byte nonce):
- Bytes 0-3: Random prefix (first 4 bytes)
- Bytes 4-11: Big-endian chunk index
This construction ensures each chunk has a unique nonce while being deterministic for the same prefix and index (needed for random access).
func MakeContainerCert ¶
MakeContainerCert creates a self-signed certificate containing an EC public key. This is used to store the YubiKey's public key in the slot certificate, enabling later retrieval without needing attestation.
The certificate is signed by an ephemeral software CA key (not the YubiKey) because the YubiKey's ECDH key cannot perform signing operations.
Parameters:
- pub: The ECDSA public key to embed in the certificate
- cn: Common Name for the certificate subject
Returns:
- der: DER-encoded certificate bytes
- cert: Parsed X.509 certificate
- err: Error if certificate creation fails
The certificate is valid for 20 years from creation.
func MakePINPromptAuth ¶
MakePINPromptAuth creates a piv.KeyAuth with a PIN prompt callback. The callback is invoked when a PIV operation requires PIN authentication.
This allows lazy PIN prompting - the PIN is only requested when needed, and can be cached by the callback for subsequent operations.
func MustPromptPassphrase ¶
MustPromptPassphrase prompts for a passphrase and exits on error or empty input. Used when a passphrase is required (e.g., encryption with -p flag).
func MustRand ¶
MustRand generates n cryptographically secure random bytes. Panics (via ExitWithError) if the random source fails.
This is used for generating salts, nonces, and file keys.
func NewFileAEAD ¶
NewFileAEAD creates an AEAD cipher for file content encryption. The cipher is selected based on the cipher ID from the header.
Supported ciphers:
- CipherChaCha20 (1): XChaCha20-Poly1305 with 24-byte nonces
- CipherAES256 (2): AES-256-GCM with 12-byte nonces
Both use 256-bit keys and provide authenticated encryption.
func NoncePrefixSize ¶
NoncePrefixSize returns the required random nonce prefix size for a cipher.
The prefix is combined with a chunk counter to create unique nonces:
- XChaCha20-Poly1305: 16 bytes prefix + 8 bytes counter = 24 bytes total
- AES-256-GCM: 4 bytes prefix + 8 bytes counter = 12 bytes total
func OpenYubiKey ¶
OpenYubiKey opens a connection to a YubiKey.
If reader is non-empty, opens that specific reader. Otherwise, scans for available smart card readers and opens the first one with "yubikey" in the name (case-insensitive).
Returns:
- yk: The opened YubiKey handle
- closeFn: A function to close the connection (call with defer)
- err: Error if no YubiKey found or connection failed
func ParseCipherName ¶
ParseCipherName converts a user-provided cipher name to a cipher ID. Accepts various common aliases for each cipher.
ChaCha20 aliases: chacha, chacha20, xchacha20, xchacha20-poly1305 AES-256 aliases: aes, aes256, aes-256, aes-256-gcm, aes256gcm
Returns error for unrecognized cipher names.
func ParseManagementKey ¶
ParseManagementKey parses a management key from hex string or "default". The management key is required for key generation and certificate operations.
If the input is "default" (case-insensitive), returns piv.DefaultManagementKey. Otherwise, expects 48 hex characters (24 bytes) with optional "0x" prefix.
Returns error if the hex is invalid or wrong length.
func ParseSlot ¶
ParseSlot converts a slot name/ID string to a piv.Slot. Accepts both hex IDs (9a, 9c, 9d, 9e) and friendly names.
Supported slots:
- 9a / auth / authentication: PIV Authentication
- 9c / sig / signature: Digital Signature
- 9d / km / keymgmt / keymanagement: Key Management (default for ykcrypt)
- 9e / cardauth / cardauthentication: Card Authentication
Returns error for unsupported slot names.
func PromptHidden ¶
PromptHidden prompts the user for input without echoing to the terminal. This is used for PIN and passphrase entry.
If stdin is a terminal, uses terminal.ReadPassword for secure input. Falls back to normal reading if not a terminal (e.g., piped input).
Returns the trimmed input string or error.
func ReadU16Bytes ¶
ReadU16Bytes reads a length-prefixed byte slice from a reader. It expects a 2-byte little-endian length followed by that many bytes.
Returns nil slice (not error) if length is zero. Returns error on read failure or unexpected EOF.
func RecipientFromECDSAPublicKey ¶
RecipientFromECDSAPublicKey creates a recipient string from an ECDSA public key. The recipient string format is: ykcrypt1:<slotHex>:<curveId>:<base64PublicKey>
The public key is encoded in SEC1 uncompressed point format and base64-encoded. Returns error if the curve is not supported (only P-256 and P-384).
func SlotFromKey ¶
SlotFromKey converts a PIV slot key value to a piv.Slot. The slot key is the numeric identifier stored in the file header.
This is the inverse of piv.Slot.Key - it maps key values back to slots. Returns error for unsupported slot keys.
func UnwrapKeyFromBlock ¶
func UnwrapKeyFromBlock(block *RecipientBlock, ecdhFunc func(*ecdh.PublicKey) ([]byte, error), passphrase string) ([]byte, error)
UnwrapKeyFromBlock attempts to unwrap the file key from a recipient block.
func WriteFileAtomic ¶
WriteFileAtomic writes data to a file atomically.
func WriteU16Bytes ¶
WriteU16Bytes writes a length-prefixed byte slice to a writer. The length is encoded as a 2-byte little-endian unsigned integer, followed by the actual bytes.
Maximum supported length is 65535 bytes (0xFFFF). Returns an error if the slice is too large or if writing fails.
Types ¶
type AtomicWriter ¶
type AtomicWriter struct {
// contains filtered or unexported fields
}
AtomicWriter provides atomic file write operations. It writes to a temporary file and atomically renames on Close.
func NewAtomicWriter ¶
func NewAtomicWriter(targetPath string, allowOverwrite bool) (*AtomicWriter, error)
NewAtomicWriter creates a new AtomicWriter for the given target path. The file will be written to a temporary location and atomically renamed to the target path when Close() is called successfully.
The temporary file is created in the same directory as the target to ensure atomic rename is possible (same filesystem).
If the target file already exists and allowOverwrite is false, returns an error.
func (*AtomicWriter) Abort ¶
func (w *AtomicWriter) Abort()
Abort cancels the write operation and removes the temp file. Use this when an error occurs during writing.
func (*AtomicWriter) Close ¶
func (w *AtomicWriter) Close() error
Close closes the writer. If Commit hasn't been called, it commits first. If any error occurred during writing, the temp file is removed.
func (*AtomicWriter) Commit ¶
func (w *AtomicWriter) Commit() error
Commit atomically renames the temp file to the target. This should be called after all writes are complete but before Close. Close will also call Commit if it hasn't been called.
type ErrorCategory ¶
type ErrorCategory int
ErrorCategory represents the type of error for classification.
const ( // ErrCategoryUnknown for unclassified errors. ErrCategoryUnknown ErrorCategory = iota // ErrCategoryYubiKey for YubiKey-related errors. ErrCategoryYubiKey // ErrCategoryFile for file system errors. ErrCategoryFile // ErrCategoryCrypto for cryptographic errors. ErrCategoryCrypto // ErrCategoryInput for user input validation errors. ErrCategoryInput // ErrCategoryFormat for file format errors. ErrCategoryFormat )
func (ErrorCategory) String ¶
func (c ErrorCategory) String() string
String returns a human-readable category name.
type Header ¶
type Header struct {
Version uint8 // File format version (currently 1)
CurveID uint8 // Elliptic curve identifier (curveP256 or curveP384)
CipherID uint8 // Cipher identifier (CipherChaCha20 or CipherAES256)
SlotKey uint32 // PIV slot key identifier (e.g., 0x9d for Key Management)
Flags uint8 // Feature flags (e.g., flagHasPassphrase)
EphPub []byte // Ephemeral public key bytes (SEC1 uncompressed format)
Salt []byte // HKDF salt for wrap key derivation (16 bytes)
PassSalt []byte // Argon2id salt for passphrase (16 bytes, empty if no passphrase)
NoncePrefix []byte // Nonce prefix for chunk encryption (16 bytes for ChaCha, 4 for AES)
ChunkSize uint32 // Plaintext chunk size in bytes
WrapNonce []byte // Nonce for key wrapping AEAD (12 bytes)
WrappedKey []byte // Encrypted file key (32 bytes + 16 bytes auth tag)
}
Header represents the encrypted file header. It contains all metadata needed to decrypt the file, including:
- Version and algorithm identifiers
- Ephemeral public key for ECDH
- Salt values for key derivation
- The wrapped (encrypted) file key
The header is serialized at the beginning of every encrypted file and is used as additional authenticated data (AAD) for chunk encryption.
func ParseHeader ¶
ParseHeader reads and parses an encrypted file header from a buffered reader. It validates the magic bytes and extracts all header fields.
Returns:
- h: The parsed Header struct
- fullHeader: Complete header bytes (for use as AAD in chunk decryption)
- wrapAAD: Header prefix bytes (for use as AAD in key unwrapping)
- err: Error if parsing fails (e.g., invalid magic, unexpected EOF)
If the magic bytes don't match, returns a user-friendly error message suggesting the file may already be decrypted.
func (Header) MarshalFull ¶
MarshalFull serializes the complete header including the wrapped key. This is written to the beginning of the encrypted file and is also used as AAD for chunk encryption.
Returns the complete serialized header or an error if serialization fails.
func (Header) MarshalPrefixAAD ¶
MarshalPrefixAAD serializes the header up to (but not including) the wrapped key. This prefix is used as Additional Authenticated Data (AAD) for the key wrapping operation, binding the wrapped key to the header contents.
Returns the serialized prefix bytes or an error if serialization fails.
type Metadata ¶
type Metadata struct {
Flags uint16 // Which optional fields are present
Filename string // Original filename (if preserved)
Timestamp time.Time // Encryption timestamp
Comment string // User-provided comment
}
Metadata holds authenticated metadata about the encrypted file.
func ParseMetadata ¶
ParseMetadata deserializes metadata from a reader.
func (*Metadata) MarshalMetadata ¶
MarshalMetadata serializes metadata to bytes.
type MultiHeader ¶
type MultiHeader struct {
Version uint8 // Format version (2)
CipherID uint8 // Cipher identifier
Flags uint8 // Global flags
Metadata *Metadata // Authenticated metadata (optional)
Recipients []*RecipientBlock // Wrapped keys for each recipient
NoncePrefix []byte // Nonce prefix for chunks
ChunkSize uint32 // Chunk size
}
MultiHeader represents the multi-recipient file header.
func ParseMultiHeader ¶
func ParseMultiHeader(br *bufio.Reader) (*MultiHeader, []byte, error)
ParseMultiHeader parses a multi-recipient header.
func (*MultiHeader) MarshalMultiHeader ¶
func (h *MultiHeader) MarshalMultiHeader() ([]byte, error)
MarshalMultiHeader serializes the complete multi-recipient header.
type Recipient ¶
type Recipient struct {
SlotKey uint32 // PIV slot key identifier (e.g., 0x9d)
CurveID uint8 // Elliptic curve identifier
PubKeyBytes []byte // SEC1 uncompressed public key bytes
}
Recipient represents the public key information needed for encryption. It encapsulates the slot identifier, curve type, and public key bytes. Recipients can be serialized to/from recipient strings for easy sharing.
func ParseRecipient ¶
ParseRecipient parses a recipient string into a Recipient struct. Expected format: ykcrypt1:<slotHex>:<curveId>:<base64PublicKey>
Example: ykcrypt1:9d:1:BGx...base64...
Returns error if format is invalid or base64 decoding fails.
func RecipientFromCert ¶
RecipientFromCert extracts a Recipient from an X.509 certificate. The certificate must contain an ECDSA public key on a supported curve.
This is used to get the recipient from a YubiKey slot's certificate.
type RecipientBlock ¶
type RecipientBlock struct {
SlotKey uint32 // PIV slot key identifier
CurveID uint8 // Elliptic curve identifier
EphPub []byte // Ephemeral public key for this recipient
Salt []byte // HKDF salt (16 bytes)
PassSalt []byte // Passphrase salt (16 bytes, empty if no passphrase)
WrapNonce []byte // Nonce for key wrapping (12 bytes)
WrappedKey []byte // Encrypted file key
Flags uint8 // Per-recipient flags (e.g., has passphrase)
}
RecipientBlock contains the wrapped key for one recipient.
func FindMatchingRecipient ¶
func FindMatchingRecipient( recipients []*RecipientBlock, mySlotKey uint32, ecdhFunc func(*ecdh.PublicKey) ([]byte, error), getPassphrase func() string, ) ([]byte, *RecipientBlock, error)
FindMatchingRecipient finds and decrypts for a matching recipient.
func ParseRecipientBlock ¶
func ParseRecipientBlock(r io.Reader) (*RecipientBlock, error)
ParseRecipientBlock deserializes a recipient block.
func WrapKeyForRecipient ¶
func WrapKeyForRecipient(fileKey []byte, recipient Recipient, passphrase string) (*RecipientBlock, error)
WrapKeyForRecipient wraps the file key for a single recipient.
func (*RecipientBlock) MarshalRecipientBlock ¶
func (rb *RecipientBlock) MarshalRecipientBlock() ([]byte, error)
MarshalRecipientBlock serializes a recipient block.
type YKCryptError ¶
type YKCryptError struct {
Category ErrorCategory
Message string
Hint string
Cause error
IsRetryable bool
}
YKCryptError is a structured error with category, message, and hints.
func ClassifyError ¶
func ClassifyError(err error) *YKCryptError
ClassifyError attempts to categorize a generic error into a YKCryptError. It inspects error messages for known patterns from the piv-go library.
func ErrAtomicWriteFailed ¶
func ErrAtomicWriteFailed(path string, cause error) *YKCryptError
ErrAtomicWriteFailed indicates atomic write operation failed.
func ErrDecryptionFailed ¶
func ErrDecryptionFailed(cause error) *YKCryptError
ErrDecryptionFailed indicates decryption/authentication failed.
func ErrEmptyPassphrase ¶
func ErrEmptyPassphrase() *YKCryptError
ErrEmptyPassphrase indicates an empty passphrase was entered.
func ErrFileAlreadyExists ¶
func ErrFileAlreadyExists(path string) *YKCryptError
ErrFileAlreadyExists indicates the output file already exists.
func ErrFileNotFound ¶
func ErrFileNotFound(path string, cause error) *YKCryptError
ErrFileNotFound indicates the file doesn't exist.
func ErrFilePermission ¶
func ErrFilePermission(path string, cause error) *YKCryptError
ErrFilePermission indicates permission denied.
func ErrInvalidChunkSize ¶
func ErrInvalidChunkSize(size int) *YKCryptError
ErrInvalidChunkSize indicates an invalid chunk size.
func ErrInvalidMagic ¶
func ErrInvalidMagic(got string) *YKCryptError
ErrInvalidMagic indicates the file doesn't have valid magic bytes.
func ErrInvalidRecipient ¶
func ErrInvalidRecipient(details string) *YKCryptError
ErrInvalidRecipient indicates an invalid recipient string.
func ErrInvalidVersion ¶
func ErrInvalidVersion(version uint8) *YKCryptError
ErrInvalidVersion indicates an unsupported file format version.
func ErrKeyUnwrapFailed ¶
func ErrKeyUnwrapFailed(cause error) *YKCryptError
ErrKeyUnwrapFailed indicates the file key couldn't be unwrapped.
func ErrNoRecipientMatch ¶
func ErrNoRecipientMatch() *YKCryptError
ErrNoRecipientMatch indicates none of the recipients match this YubiKey.
func ErrTruncatedHeader ¶
func ErrTruncatedHeader(cause error) *YKCryptError
ErrTruncatedHeader indicates the file header is incomplete.
func ErrUnsupportedCipher ¶
func ErrUnsupportedCipher(cipherID uint8) *YKCryptError
ErrUnsupportedCipher indicates an unsupported cipher.
func ErrUnsupportedCurve ¶
func ErrUnsupportedCurve(curveID uint8) *YKCryptError
ErrUnsupportedCurve indicates an unsupported elliptic curve.
func ErrYubiKeyConditionsNotSatisfied ¶
func ErrYubiKeyConditionsNotSatisfied(cause error) *YKCryptError
ErrYubiKeyConditionsNotSatisfied indicates policy requirements weren't met.
func ErrYubiKeyNotFound ¶
func ErrYubiKeyNotFound() *YKCryptError
ErrYubiKeyNotFound indicates no YubiKey was detected.
func ErrYubiKeyPINBlocked ¶
func ErrYubiKeyPINBlocked(cause error) *YKCryptError
ErrYubiKeyPINBlocked indicates the PIN is blocked.
func ErrYubiKeySlotEmpty ¶
func ErrYubiKeySlotEmpty(slot string, cause error) *YKCryptError
ErrYubiKeySlotEmpty indicates no key exists in the slot.
func ErrYubiKeyTouchTimeout ¶
func ErrYubiKeyTouchTimeout(cause error) *YKCryptError
ErrYubiKeyTouchTimeout indicates the user didn't touch in time.
func ErrYubiKeyWrongPIN ¶
func ErrYubiKeyWrongPIN(retries int, cause error) *YKCryptError
ErrYubiKeyWrongPIN indicates incorrect PIN with remaining retries.
func (*YKCryptError) Error ¶
func (e *YKCryptError) Error() string
Error implements the error interface.
func (*YKCryptError) FullError ¶
func (e *YKCryptError) FullError() string
FullError returns the error with hint if available.
func (*YKCryptError) Unwrap ¶
func (e *YKCryptError) Unwrap() error
Unwrap returns the underlying cause for error chain inspection.