crypto

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Jan 4, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package crypto provides NaCl SecretBox encryption for secure data storage.

This package implements symmetric encryption using NaCl SecretBox (XSalsa20 + Poly1305), which provides authenticated encryption. It is designed for encrypting sensitive data like OAuth tokens that need to be stored securely and decrypted later.

Security Properties

  • Confidentiality: XSalsa20 stream cipher with 256-bit key
  • Integrity: Poly1305 MAC prevents tampering
  • Nonce: 192-bit random nonce generated per encryption (no reuse risk)

Output Format

Encrypted data is returned as Base64(nonce || ciphertext), where:

  • nonce: 24 bytes (randomly generated)
  • ciphertext: secretbox.Seal output (plaintext + 16 bytes overhead)

Usage Example

// Create encryptor from Base64-encoded key
encryptor, err := crypto.NewEncryptorFromBase64(os.Getenv("ENCRYPTION_KEY"))
if err != nil {
    log.Fatal(err)
}

// Encrypt sensitive data
encrypted, err := encryptor.Encrypt(oauthToken)
if err != nil {
    return err
}

// Store encrypted in database...

// Later, decrypt
decrypted, err := encryptor.Decrypt(encrypted)
if err != nil {
    return err
}

Key Generation

Generate a 32-byte Base64-encoded key using openssl:

openssl rand -base64 32

Thread Safety

All Encryptor implementations are safe for concurrent use. A single Encryptor instance can be shared across goroutines.

Key Management

Keys should be managed securely:

  • Store in environment variables or secret managers (AWS Secrets Manager, HashiCorp Vault)
  • Never commit keys to source control
  • Use different keys for different environments
  • Plan for key rotation (re-encrypt existing data when rotating)

Key Rotation

To rotate encryption keys in production without service disruption:

  1. Generate new key: openssl rand -base64 32

  2. Deploy collector with BOTH keys (old for decrypt, new as fallback)

  3. Deploy web with new key (encrypts with new key)

  4. Run batch re-encryption of existing database tokens:

    oldEnc, _ := crypto.NewEncryptorFromBase64(oldKey) newEnc, _ := crypto.NewEncryptorFromBase64(newKey) decrypted, _ := oldEnc.Decrypt(ciphertext) newCiphertext, _ := newEnc.Encrypt(decrypted)

  5. Remove old key from collector after re-encryption completes

Error Handling

Wrap errors with service context for debugging distributed systems:

plaintext, err := enc.Decrypt(token)
if err != nil {
    return fmt.Errorf("decrypt token [user=%s service=%s]: %w",
        userID, "collector", err)
}

Memory Safety

For long-lived server processes, call Close() when done with an Encryptor to zero sensitive key material from memory:

enc, _ := crypto.NewEncryptorFromBase64(key)
defer enc.Close()

Index

Constants

View Source
const (
	// KeyLength is the required length of encryption keys in bytes.
	KeyLength = 32
)

Variables

View Source
var (
	// ErrInvalidKeyLength indicates the encryption key is not 32 bytes.
	ErrInvalidKeyLength = errors.New("crypto: invalid key length (expected 32 bytes)")

	// ErrDecryptionFailed indicates authentication or decryption failed.
	// This error is returned when the ciphertext cannot be authenticated,
	// typically due to wrong key or corrupted data.
	ErrDecryptionFailed = errors.New("crypto: decryption failed")

	// ErrInvalidCiphertext indicates the ciphertext is malformed.
	// This includes invalid base64 encoding or insufficient length.
	ErrInvalidCiphertext = errors.New("crypto: invalid ciphertext")

	// ErrEmptyPlaintext indicates an attempt to encrypt empty data.
	ErrEmptyPlaintext = errors.New("crypto: empty plaintext")
)

Sentinel errors for encryption operations.

Functions

This section is empty.

Types

type Encryptor

type Encryptor interface {
	// Encrypt encrypts plaintext and returns Base64-encoded ciphertext.
	// The output format is: Base64(nonce || encrypted_data)
	// Returns ErrEmptyPlaintext if plaintext is empty.
	Encrypt(plaintext string) (string, error)

	// Decrypt decrypts Base64-encoded ciphertext and returns plaintext.
	// Returns ErrInvalidCiphertext if input is malformed.
	// Returns ErrDecryptionFailed if authentication fails.
	Decrypt(ciphertext string) (string, error)

	// Close zeros the encryption key from memory.
	// After calling Close, the Encryptor should not be used.
	// This is recommended for long-lived server processes to minimize
	// the window during which keys are exposed in memory.
	Close() error
}

Encryptor provides symmetric encryption for sensitive data. All implementations MUST be safe for concurrent use.

func NewEncryptor

func NewEncryptor(key string) (Encryptor, error)

NewEncryptor creates a new Encryptor with the given 32-byte string key. Returns ErrInvalidKeyLength if the key is not exactly 32 bytes.

func NewEncryptorFromBase64

func NewEncryptorFromBase64(encodedKey string) (Encryptor, error)

NewEncryptorFromBase64 creates a new Encryptor from a Base64-encoded key. The decoded key must be exactly 32 bytes. Returns ErrInvalidKeyLength if the key is invalid or not 32 bytes.

Jump to

Keyboard shortcuts

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