crypto

package
v0.0.0-...-101d28d Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SessionKeyContext     = "ARKFILE_SESSION_KEY"
	JWTSigningContext     = "ARKFILE_JWT_SIGNING"
	TOTPEncryptionContext = "ARKFILE_TOTP_ENCRYPTION"
)

Session key contexts for domain separation

View Source
const (
	// TOTP key contexts for domain separation
	TOTPMasterKeyContext = "ARKFILE_TOTP_MASTER_KEY"
	TOTPUserKeyContext   = "ARKFILE_TOTP_USER_KEY"
)
View Source
const MaxPasswordBytes = 1024

MaxPasswordBytes is the defense-in-depth limit for password inputs to Argon2id. This prevents absurdly long inputs from wasting memory on string allocation. The primary enforcement is in the validation layer (password_validation.go); this is a safety net in case validation is bypassed.

Variables

View Source
var ShareKDFParams = struct {
	Memory      uint32
	Iterations  uint32
	Parallelism uint8
	SaltLength  uint32
	KeyLength   uint32
}{}

ShareKDFParams defines the Argon2id parameters for share key derivation These MUST match the client-side parameters in share-crypto.ts Loaded from crypto/argon2id-params.json

Functions

func AesGcmNonceSize

func AesGcmNonceSize() int

AesGcmNonceSize returns the AES-GCM nonce size in bytes

func AesGcmOverhead

func AesGcmOverhead() int

AesGcmOverhead returns the per-chunk AES-GCM overhead (nonce + tag) in bytes

func AesGcmTagSize

func AesGcmTagSize() int

AesGcmTagSize returns the AES-GCM authentication tag size in bytes

func CalculateFileHash

func CalculateFileHash(data []byte) string

CalculateFileHash computes SHA-256 hash of file content

func CalculateFileHashFromPath

func CalculateFileHashFromPath(filePath string) (string, error)

CalculateFileHashFromPath computes SHA-256 hash of a file on disk

func CreateAAD

func CreateAAD(shareID, fileID string) []byte

CreateAAD creates the Additional Authenticated Data for envelope encryption AAD = share_id + file_id (UTF-8 encoded concatenation) This binds the encrypted envelope to specific share_id and file_id

func CreateEnvelope

func CreateEnvelope(keyType string) []byte

CreateEnvelope creates an envelope header for FEK-based encryption keyType: "account" or "custom"

func CreateShareEnvelope

func CreateShareEnvelope(fek, downloadToken []byte, filename string, sizeBytes int64, sha256hex string) ([]byte, error)

CreateShareEnvelope creates a Share Envelope JSON payload with file metadata. The metadata (filename, sizeBytes, sha256) allows share recipients to preview file info before downloading and verify integrity after decryption.

func DecodeBase64

func DecodeBase64(s string) ([]byte, error)

DecodeBase64 decodes base64 string to bytes

func DecryptFEK

func DecryptFEK(encryptedFEK []byte, password []byte, username string) ([]byte, string, error)

DecryptFEK decrypts a File Encryption Key (FEK) using a key derived from the user's password via Argon2ID. Returns the decrypted FEK and the key type.

func DecryptFile

func DecryptFile(encryptedData []byte, fek []byte) ([]byte, error)

DecryptFile decrypts file data using a FEK (File Encryption Key)

func DecryptFileMetadata

func DecryptFileMetadata(filenameNonce, encryptedFilename, sha256Nonce, encryptedSHA256 []byte, password string, username string) (string, string, error)

DecryptFileMetadata decrypts encrypted filename and SHA256 metadata using stored password This function works with separate nonce and encrypted data fields as stored in the database The server stores nonces and encrypted data separately, so we need to combine them for DecryptGCM

func DecryptGCM

func DecryptGCM(data, key []byte) ([]byte, error)

DecryptGCM decrypts data using AES-256-GCM Expects: nonce + ciphertext + tag (all concatenated)

func DecryptGCMWithAAD

func DecryptGCMWithAAD(data, key, aad []byte) ([]byte, error)

DecryptGCMWithAAD decrypts data using AES-256-GCM with Additional Authenticated Data AAD must match the value used during encryption or decryption will fail Expects: nonce + ciphertext + tag (all concatenated)

func DecryptMetadataWithDerivedKey

func DecryptMetadataWithDerivedKey(derivedKey []byte, nonce, encryptedData []byte) ([]byte, error)

DecryptMetadataWithDerivedKey decrypts file metadata using a pre-derived key Expects separate nonce and encrypted data parameters (split from GCM output).

func DecryptWithNonce

func DecryptWithNonce(ciphertext, key, nonce []byte) ([]byte, error)

DecryptWithNonce decrypts data using AES-256-GCM with a provided nonce This is used when the nonce is stored separately (e.g., in database)

func DeriveAccountPasswordKey

func DeriveAccountPasswordKey(password []byte, username string) []byte

DeriveAccountPasswordKey derives a key from an account password

func DeriveArgon2IDKey

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

DeriveArgon2IDKey derives a key using Argon2ID with specified parameters

func DeriveCustomPasswordKey

func DeriveCustomPasswordKey(password []byte, username string) []byte

DeriveCustomPasswordKey derives a key from a custom file password

func DeriveJWTSigningMaterial

func DeriveJWTSigningMaterial(sessionKey []byte, username string) ([]byte, error)

DeriveJWTSigningMaterial derives JWT signing material from session key This provides domain separation for JWT tokens

func DeriveSessionKey

func DeriveSessionKey(opaqueExportKey []byte, context string) ([]byte, error)

DeriveSessionKey derives a session key from OPAQUE export key with domain separation

func DeriveShareKey

func DeriveShareKey(password string, saltBase64 string) ([]byte, error)

DeriveShareKey derives a 256-bit key from a password and salt using Argon2id. This function is used by the CLI client (cmd/arkfile-client) and tests only. It is NEVER called from server handlers -- all share key derivation for clients happens client-side in TypeScript or Go CLI client utils.

func DeriveTOTPUserKey

func DeriveTOTPUserKey(username string) ([]byte, error)

DeriveTOTPUserKey derives a user-specific TOTP encryption key from the master key This key remains consistent for the user across all sessions

func EncodeBase64

func EncodeBase64(data []byte) string

EncodeBase64 encodes bytes to base64 string

func EncryptFEK

func EncryptFEK(fek []byte, password []byte, username, keyType string) ([]byte, error)

EncryptFEK encrypts a File Encryption Key (FEK) using a key derived from the user's password via Argon2ID. This creates the "Owner Envelope".

func EncryptFile

func EncryptFile(data []byte, fek []byte, keyType string) ([]byte, error)

EncryptFile encrypts file data using a FEK (File Encryption Key) The keyType parameter indicates what password type will be used to encrypt the FEK

func EncryptGCM

func EncryptGCM(data, key []byte) ([]byte, error)

EncryptGCM encrypts data using AES-256-GCM Returns: nonce + ciphertext + tag (all concatenated)

func EncryptGCMWithAAD

func EncryptGCMWithAAD(data, key, aad []byte) ([]byte, error)

EncryptGCMWithAAD encrypts data using AES-256-GCM with Additional Authenticated Data AAD is authenticated but not encrypted - used to bind ciphertext to context Returns: nonce + ciphertext + tag (all concatenated)

func EnvelopeHeaderSize

func EnvelopeHeaderSize() int

EnvelopeHeaderSize returns the envelope header size in bytes (chunk 0 only)

func FormatFileSize

func FormatFileSize(bytes int64) string

FormatFileSize converts bytes to human-readable format

func GenerateAESKey

func GenerateAESKey() ([]byte, error)

GenerateAESKey generates a cryptographically secure 256-bit AES key

func GenerateDownloadToken

func GenerateDownloadToken() ([]byte, error)

GenerateDownloadToken generates a cryptographically secure 32-byte Download Token

func GenerateFEK

func GenerateFEK() ([]byte, error)

GenerateFEK generates a cryptographically secure 32-byte File Encryption Key

func GenerateRandomBytes

func GenerateRandomBytes(n int) []byte

GenerateRandomBytes generates cryptographically secure random bytes

func GenerateShareSalt

func GenerateShareSalt() (string, error)

GenerateShareSalt generates a random 32-byte salt for share key derivation

func GenerateTestFileContent

func GenerateTestFileContent(size int64, pattern FilePattern) ([]byte, error)

GenerateTestFileContent creates deterministic test file content

func GenerateTestFileToPath

func GenerateTestFileToPath(filePath string, size int64, pattern FilePattern) (string, error)

GenerateTestFileToPath creates a test file directly to disk for memory efficiency

func GenerateUserKeySalt

func GenerateUserKeySalt(username, keyType string) []byte

GenerateUserKeySalt generates a deterministic salt based on username and key type

func GetEmbeddedArgon2ParamsJSON

func GetEmbeddedArgon2ParamsJSON() []byte

GetEmbeddedArgon2ParamsJSON returns the raw embedded JSON for API serving

func GetEmbeddedChunkingParamsJSON

func GetEmbeddedChunkingParamsJSON() []byte

GetEmbeddedChunkingParamsJSON returns the raw embedded JSON for API serving

func GetEmbeddedPasswordRequirementsJSON

func GetEmbeddedPasswordRequirementsJSON() []byte

GetEmbeddedPasswordRequirementsJSON returns the raw embedded JSON for API serving

func GetTOTPMasterKeyStatus

func GetTOTPMasterKeyStatus() (bool, int)

GetTOTPMasterKeyStatus returns information about the TOTP master key

func HashDownloadToken

func HashDownloadToken(downloadTokenBase64 string) (string, error)

HashDownloadToken creates a SHA-256 hash of the download token The download token is derived from the share key: HKDF(share_key, "download_token", 32)

func InitKeyManager

func InitKeyManager(db *sql.DB) error

InitKeyManager initializes the global KeyManager. It expects ARKFILE_MASTER_KEY to be set in the environment.

func InitializeTOTPMasterKey

func InitializeTOTPMasterKey() error

InitializeTOTPMasterKey loads or generates the TOTP master key using KeyManager

func KeyTypeForContext

func KeyTypeForContext(passwordType string) (byte, error)

KeyTypeForContext returns the envelope key type byte for a given password context

func ParseEnvelope

func ParseEnvelope(envelope []byte) (version byte, keyType string, err error)

ParseEnvelope parses an envelope header and returns the key type

func ParseSizeString

func ParseSizeString(sizeStr string) (int64, error)

ParseSizeString converts human-readable size strings to bytes

func PlaintextChunkSize

func PlaintextChunkSize() int64

PlaintextChunkSize returns the plaintext chunk size in bytes from the embedded config

func SecureClear

func SecureClear(data []byte)

SecureClear securely clears sensitive data from memory

func SecureCompare

func SecureCompare(a, b []byte) bool

SecureCompare performs constant-time comparison of two byte slices

func SecureZeroSessionKey

func SecureZeroSessionKey(sessionKey []byte)

SecureZeroSessionKey securely clears session key material

func SecureZeroTOTPKey

func SecureZeroTOTPKey(key []byte)

SecureZeroTOTPKey clears a TOTP key from memory

func ValidateSessionKey

func ValidateSessionKey(sessionKey []byte) error

ValidateSessionKey checks if a session key has the expected properties

func VerifyDownloadToken

func VerifyDownloadToken(downloadTokenBase64 string, expectedHashBase64 string) (bool, error)

VerifyDownloadToken verifies a download token against its hash

func VerifyFileIntegrity

func VerifyFileIntegrity(filePath string, expectedHash string, expectedSize int64) error

VerifyFileIntegrity verifies a file matches expected hash and size

Types

type AesGcmParams

type AesGcmParams struct {
	NonceSizeBytes int `json:"nonceSizeBytes"`
	TagSizeBytes   int `json:"tagSizeBytes"`
	KeySizeBytes   int `json:"keySizeBytes"`
}

AesGcmParams represents AES-GCM configuration

type ChunkInfo

type ChunkInfo struct {
	Index int    `json:"index"`
	File  string `json:"file"`
	Hash  string `json:"hash"`
	Size  int    `json:"size"`
}

ChunkInfo represents metadata for a single encrypted chunk

type ChunkManifest

type ChunkManifest struct {
	Envelope    string      `json:"envelope"`
	TotalChunks int         `json:"total_chunks"`
	ChunkSize   int         `json:"chunk_size"`
	Chunks      []ChunkInfo `json:"chunks"`
}

ChunkManifest represents metadata for chunked encryption

func (*ChunkManifest) ToJSON

func (m *ChunkManifest) ToJSON() ([]byte, error)

ToJSON serializes the manifest to JSON

type ChunkingParams

type ChunkingParams struct {
	PlaintextChunkSizeBytes int64          `json:"plaintextChunkSizeBytes"`
	Envelope                EnvelopeParams `json:"envelope"`
	AesGcm                  AesGcmParams   `json:"aesGcm"`
}

ChunkingParams represents the unified chunking configuration

func GetChunkingParams

func GetChunkingParams() (*ChunkingParams, error)

GetChunkingParams returns the parsed chunking parameters from the embedded JSON

func MustGetChunkingParams

func MustGetChunkingParams() *ChunkingParams

MustGetChunkingParams returns the parsed chunking parameters or panics on error. Use this only during initialization where failure should be fatal.

type DecryptedFileMetadata

type DecryptedFileMetadata struct {
	FileID       string `json:"file_id"`
	StorageID    string `json:"storage_id"`
	PasswordHint string `json:"password_hint"`
	PasswordType string `json:"password_type"`
	Filename     string `json:"filename"`
	SHA256       string `json:"sha256"`
	SizeBytes    int64  `json:"size_bytes"`
	SizeReadable string `json:"size_readable"`
	UploadDate   string `json:"upload_date"`
}

DecryptedFileMetadata represents decrypted file metadata

type EnvelopeParams

type EnvelopeParams struct {
	Version         int            `json:"version"`
	HeaderSizeBytes int            `json:"headerSizeBytes"`
	KeyTypes        KeyTypeMapping `json:"keyTypes"`
}

EnvelopeParams represents envelope header configuration

type FilePattern

type FilePattern string

FilePattern represents different test file content patterns

const (
	PatternSequential FilePattern = "sequential"
	PatternRepeated   FilePattern = "repeated"
	PatternRandom     FilePattern = "random"
	PatternZeros      FilePattern = "zeros"
)

type KeyManager

type KeyManager struct {
	// contains filtered or unexported fields
}

KeyManager handles the lifecycle of system secrets using Envelope Encryption.

func GetKeyManager

func GetKeyManager() (*KeyManager, error)

GetKeyManager returns the global KeyManager instance.

func (*KeyManager) DecryptSystemKey

func (km *KeyManager) DecryptSystemKey(encryptedKey, nonce []byte, keyType string) ([]byte, error)

DecryptSystemKey decrypts an encrypted key using the Master Key.

func (*KeyManager) DeleteKey

func (km *KeyManager) DeleteKey(keyID string) error

DeleteKey removes a key from the database.

func (*KeyManager) EncryptSystemKey

func (km *KeyManager) EncryptSystemKey(rawKey []byte, keyType string) ([]byte, []byte, error)

EncryptSystemKey encrypts a raw key using the Master Key (via a derived wrapping key).

func (*KeyManager) GetKey

func (km *KeyManager) GetKey(keyID string, keyType string) ([]byte, error)

GetKey retrieves and decrypts a key from the database. Returns error if key not found.

func (*KeyManager) GetOrGenerateKey

func (km *KeyManager) GetOrGenerateKey(keyID string, keyType string, keySize int) ([]byte, error)

GetOrGenerateKey retrieves a key from the DB or generates/stores it if missing. This function is safe for concurrent access across multiple instances. It uses database transactions to ensure only one instance generates a key during initial deployment, preventing race conditions in multi-instance scenarios.

keyID: Unique identifier for the key (e.g., "jwt_signing_key_v1") keyType: Type of key for derivation context (e.g., "jwt", "totp") keySize: Size of key to generate if missing

func (*KeyManager) StoreKey

func (km *KeyManager) StoreKey(keyID string, keyType string, rawKey []byte) error

StoreKey encrypts and stores a key in the database. It overwrites any existing key with the same ID.

type KeyTypeMapping

type KeyTypeMapping struct {
	Account int `json:"account"`
	Custom  int `json:"custom"`
}

KeyTypeMapping maps password context names to envelope key type bytes

type PasswordRequirements

type PasswordRequirements struct {
	MinAccountPasswordLength    int    `json:"minAccountPasswordLength"`
	MinCustomPasswordLength     int    `json:"minCustomPasswordLength"`
	MinSharePasswordLength      int    `json:"minSharePasswordLength"`
	MaxPasswordLength           int    `json:"maxPasswordLength"`
	MinCharacterClassesRequired int    `json:"minCharacterClassesRequired"`
	SpecialCharacters           string `json:"specialCharacters"`
}

PasswordRequirements holds password validation configuration

func GetPasswordRequirements

func GetPasswordRequirements() *PasswordRequirements

GetPasswordRequirements returns the loaded password requirements (panics if not loaded)

func LoadPasswordRequirements

func LoadPasswordRequirements() (*PasswordRequirements, error)

LoadPasswordRequirements loads password requirements from embedded config The JSON is embedded at build time from crypto/password-requirements.json.

type PasswordValidationResult

type PasswordValidationResult struct {
	MeetsRequirement bool              `json:"meets_requirements"`
	Requirements     RequirementChecks `json:"requirements"`
	Reasons          []string          `json:"reasons,omitempty"`
}

PasswordValidationResult represents the result of password validation

func ValidateAccountPassword

func ValidateAccountPassword(password string) *PasswordValidationResult

ValidateAccountPassword validates account passwords using config requirements

func ValidateCustomPassword

func ValidateCustomPassword(password string) *PasswordValidationResult

ValidateCustomPassword validates custom passwords using config requirements

func ValidatePassword

func ValidatePassword(password string, minLength int, maxLength int, minClasses int, specialChars string) *PasswordValidationResult

ValidatePassword performs deterministic password validation. Pass = (length >= minLength) AND (length <= maxLength) AND (character classes met >= minCharacterClassesRequired) maxLength of 0 means no maximum is enforced.

func ValidateSharePassword

func ValidateSharePassword(password string) *PasswordValidationResult

ValidateSharePassword validates share passwords using config requirements

type RequirementChecks

type RequirementChecks struct {
	Length          RequirementStatus `json:"length"`
	Uppercase       RequirementStatus `json:"uppercase"`
	Lowercase       RequirementStatus `json:"lowercase"`
	Number          RequirementStatus `json:"number"`
	Special         RequirementStatus `json:"special"`
	ClassCount      int               `json:"class_count"`
	ClassesRequired int               `json:"classes_required"`
}

RequirementChecks tracks individual password requirements

type RequirementStatus

type RequirementStatus struct {
	Met     bool   `json:"met"`
	Current int    `json:"current,omitempty"`
	Needed  int    `json:"needed,omitempty"`
	Message string `json:"message"`
}

RequirementStatus represents the status of a single requirement

type SessionKeyInfo

type SessionKeyInfo struct {
	Username  string
	DerivedAt int64  // Unix timestamp
	Context   string // The context used for derivation
	KeyLength int    // Length in bytes
	IsValid   bool   // Whether the key passed validation
}

SessionKeyInfo contains metadata about a session key

func CreateSessionKeyInfo

func CreateSessionKeyInfo(username, context string, sessionKey []byte) SessionKeyInfo

CreateSessionKeyInfo creates metadata for a session key

type ShareEnvelope

type ShareEnvelope struct {
	FEK           string `json:"fek"`                  // base64-encoded FEK
	DownloadToken string `json:"download_token"`       // base64-encoded Download Token
	Filename      string `json:"filename,omitempty"`   // plaintext filename (for share recipient preview)
	SizeBytes     int64  `json:"size_bytes,omitempty"` // file size in bytes (for share recipient preview)
	SHA256        string `json:"sha256,omitempty"`     // plaintext SHA256 hex digest (for share recipient integrity verification)
}

ShareEnvelope represents the decrypted content of a Share Envelope This is a JSON structure containing the FEK, Download Token, and file metadata. File metadata (filename, size, sha256) is included so share recipients can:

  • Preview the file before downloading (filename, size)
  • Verify integrity after decryption (sha256)

The metadata is protected by the same AES-GCM-AAD encryption as the FEK, so only someone with the share password can access it.

func ParseShareEnvelope

func ParseShareEnvelope(envelopeJSON []byte) (*ShareEnvelope, error)

ParseShareEnvelope parses a Share Envelope JSON payload

type UnifiedArgonProfile

type UnifiedArgonProfile struct {
	Time    uint32 // iterations
	Memory  uint32 // KB
	Threads uint8  // parallelism
	KeyLen  uint32 // output length in bytes
}

UnifiedArgonProfile defines Argon2ID parameters for all file encryption contexts

var (
	// UnifiedArgonSecure is the profile for all file encryption contexts
	// SINGLE SOURCE OF TRUTH: Embedded from crypto/argon2id-params.json at build time
	UnifiedArgonSecure UnifiedArgonProfile
)

Jump to

Keyboard shortcuts

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