or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

acme.mdencryption.mdhashing.mdindex.mdnacl.mdopenpgp.mdpublic-key.mdssh.mdutilities.md
tile.json

encryption.mddocs/

Symmetric Encryption

This document covers symmetric encryption algorithms including modern stream ciphers (ChaCha20, Salsa20) and legacy block ciphers provided by golang.org/x/crypto.

Modern Stream Ciphers

Package: golang.org/x/crypto/chacha20poly1305

ChaCha20-Poly1305 is an authenticated encryption with associated data (AEAD) algorithm defined in RFC 8439. It provides both confidentiality and authenticity.

Constants

const (
    KeySize    = 32 // Key size in bytes
    NonceSize  = 12 // Nonce size for ChaCha20-Poly1305
    NonceSizeX = 24 // Nonce size for XChaCha20-Poly1305
    Overhead   = 16 // Authentication tag overhead in bytes
)

Functions

// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
func New(key []byte) (cipher.AEAD, error)

// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
// XChaCha20-Poly1305 is a variant with a larger nonce size that requires less nonce management.
func NewX(key []byte) (cipher.AEAD, error)

Usage Example

package main

import (
    "crypto/rand"
    "fmt"
    "golang.org/x/crypto/chacha20poly1305"
)

func main() {
    // Generate a random key
    key := make([]byte, chacha20poly1305.KeySize)
    rand.Read(key)

    // Create AEAD cipher
    aead, err := chacha20poly1305.New(key)
    if err != nil {
        panic(err)
    }

    // Encrypt
    nonce := make([]byte, aead.NonceSize())
    rand.Read(nonce)
    plaintext := []byte("secret message")
    additionalData := []byte("metadata")

    ciphertext := aead.Seal(nil, nonce, plaintext, additionalData)
    fmt.Printf("Ciphertext: %x\n", ciphertext)

    // Decrypt
    decrypted, err := aead.Open(nil, nonce, ciphertext, additionalData)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Decrypted: %s\n", decrypted)

    // XChaCha20-Poly1305 with larger nonce
    xaead, _ := chacha20poly1305.NewX(key)
    xnonce := make([]byte, chacha20poly1305.NonceSizeX)
    rand.Read(xnonce)
    xciphertext := xaead.Seal(nil, xnonce, plaintext, additionalData)
    fmt.Printf("XChaCha20 ciphertext: %x\n", xciphertext)
}

Package: golang.org/x/crypto/chacha20

ChaCha20 is a stream cipher defined in RFC 8439. This provides the unauthenticated stream cipher; use chacha20poly1305 for authenticated encryption.

Constants

const (
    KeySize    = 32 // Key size in bytes
    NonceSize  = 12 // Nonce size for ChaCha20
    NonceSizeX = 24 // Nonce size for XChaCha20
)

Types

// Cipher is a ChaCha20 stream cipher.
type Cipher struct {
    // contains unexported fields
}

// NewUnauthenticatedCipher creates a new ChaCha20 or XChaCha20 stream cipher.
// Nonce size determines variant: 12 bytes for ChaCha20, 24 bytes for XChaCha20.
// The initial counter value is set to 0.
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error)

// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
// behave as if (counter * 64) bytes had been encrypted so far.
func (s *Cipher) SetCounter(counter uint32)

// XORKeyStream XORs each byte in the given slice with a byte from the cipher's key stream.
func (s *Cipher) XORKeyStream(dst, src []byte)

Functions

// HChaCha20 generates a derived key for XChaCha20.
// The key must be 32 bytes and nonce must be 16 bytes.
func HChaCha20(key, nonce []byte) ([]byte, error)

Usage Example

package main

import (
    "crypto/rand"
    "fmt"
    "golang.org/x/crypto/chacha20"
)

func main() {
    key := make([]byte, chacha20.KeySize)
    rand.Read(key)

    nonce := make([]byte, chacha20.NonceSize)
    rand.Read(nonce)

    // Create cipher
    cipher, err := chacha20.NewUnauthenticatedCipher(key, nonce)
    if err != nil {
        panic(err)
    }

    // Encrypt
    plaintext := []byte("secret message")
    ciphertext := make([]byte, len(plaintext))
    cipher.XORKeyStream(ciphertext, plaintext)
    fmt.Printf("Ciphertext: %x\n", ciphertext)

    // Decrypt (create new cipher with same key/nonce)
    cipher2, _ := chacha20.NewUnauthenticatedCipher(key, nonce)
    decrypted := make([]byte, len(ciphertext))
    cipher2.XORKeyStream(decrypted, ciphertext)
    fmt.Printf("Decrypted: %s\n", decrypted)
}

Package: golang.org/x/crypto/salsa20

Salsa20 is a stream cipher designed by Daniel J. Bernstein.

Functions

// XORKeyStream encrypts or decrypts data using Salsa20/20.
// out receives the result, in is the input data.
// nonce must be 8 bytes and key must be 32 bytes.
// The same key/nonce combination must not be reused.
func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte)

Usage Example

package main

import (
    "crypto/rand"
    "fmt"
    "golang.org/x/crypto/salsa20"
)

func main() {
    var key [32]byte
    rand.Read(key[:])

    nonce := make([]byte, 8)
    rand.Read(nonce)

    plaintext := []byte("secret message")
    ciphertext := make([]byte, len(plaintext))

    // Encrypt
    salsa20.XORKeyStream(ciphertext, plaintext, nonce, &key)
    fmt.Printf("Ciphertext: %x\n", ciphertext)

    // Decrypt
    decrypted := make([]byte, len(ciphertext))
    salsa20.XORKeyStream(decrypted, ciphertext, nonce, &key)
    fmt.Printf("Decrypted: %s\n", decrypted)
}

Package: golang.org/x/crypto/salsa20/salsa

Low-level Salsa family operations. Deprecated - use chacha20poly1305 or salsa20 instead.

Variables

var Sigma = [16]byte{'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}

Functions

// Core208 applies the Salsa20/8 core function to the 64-byte array in.
func Core208(out *[64]byte, in *[64]byte)

// HSalsa20 applies the HSalsa20 core function to derive a subkey.
func HSalsa20(out *[32]byte, in *[16]byte, k *[32]byte, c *[16]byte)

// XORKeyStream encrypts or decrypts data using Salsa20.
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte)

Disk Encryption

Package: golang.org/x/crypto/xts

XTS (XEX-based tweaked-codebook mode with ciphertext stealing) is a cipher mode defined in IEEE P1619/D16, designed for disk encryption.

Types

// Cipher is an XTS cipher.
type Cipher struct {
    // contains unexported fields
}

// NewCipher creates a new XTS cipher with the given block cipher and key.
// The key must be twice the block cipher's key size - the first half is used
// for encryption, the second half for tweak generation.
// cipherFunc creates a cipher.Block (e.g., aes.NewCipher).
func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error)

// Encrypt encrypts a sector of data.
// The sector size must be at least 16 bytes and a multiple of the cipher's block size.
// sectorNum is the sector number, used as the tweak.
func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64)

// Decrypt decrypts a sector of data.
// The sector size must be at least 16 bytes and a multiple of the cipher's block size.
// sectorNum is the sector number, used as the tweak.
func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64)

Usage Example

package main

import (
    "crypto/aes"
    "crypto/rand"
    "fmt"
    "golang.org/x/crypto/xts"
)

func main() {
    // XTS requires 2x the key size (32 bytes for AES-128)
    key := make([]byte, 32)
    rand.Read(key)

    // Create XTS cipher
    cipher, err := xts.NewCipher(aes.NewCipher, key)
    if err != nil {
        panic(err)
    }

    // Encrypt a sector (must be at least 16 bytes)
    plaintext := make([]byte, 512) // Typical sector size
    copy(plaintext, []byte("secret data"))

    ciphertext := make([]byte, len(plaintext))
    sectorNum := uint64(0)
    cipher.Encrypt(ciphertext, plaintext, sectorNum)

    fmt.Printf("Encrypted sector: %x...\n", ciphertext[:32])

    // Decrypt
    decrypted := make([]byte, len(ciphertext))
    cipher.Decrypt(decrypted, ciphertext, sectorNum)
    fmt.Printf("Decrypted: %s\n", decrypted[:11])
}

Legacy Block Ciphers (Deprecated)

The following block ciphers are provided for compatibility with legacy systems only. They should not be used in new applications. Use AES (standard library) or ChaCha20-Poly1305 instead.

Package: golang.org/x/crypto/blowfish

Blowfish encryption algorithm. Deprecated - use AES or ChaCha20-Poly1305.

Constants

const BlockSize = 8

Types

// Cipher is an instance of Blowfish encryption.
type Cipher struct {
    // contains unexported fields
}

// NewCipher creates and returns a Cipher.
// The key must be between 1 and 56 bytes.
func NewCipher(key []byte) (*Cipher, error)

// NewSaltedCipher creates a Cipher using the expensive key expansion from bcrypt.
func NewSaltedCipher(key, salt []byte) (*Cipher, error)

func (c *Cipher) BlockSize() int
func (c *Cipher) Encrypt(dst, src []byte)
func (c *Cipher) Decrypt(dst, src []byte)

// KeySizeError reports an invalid key size.
type KeySizeError int

func (k KeySizeError) Error() string

Functions

// ExpandKey performs key expansion.
func ExpandKey(key []byte, c *Cipher)

Package: golang.org/x/crypto/cast5

CAST5 (CAST-128) encryption algorithm (RFC 2144). Deprecated - use AES or ChaCha20-Poly1305.

Constants

const BlockSize = 8
const KeySize = 16

Types

// Cipher is an instance of CAST5 encryption.
type Cipher struct {
    // contains unexported fields
}

// NewCipher creates and returns a new Cipher.
// The key must be 16 bytes.
func NewCipher(key []byte) (c *Cipher, err error)

func (c *Cipher) BlockSize() int
func (c *Cipher) Encrypt(dst, src []byte)
func (c *Cipher) Decrypt(dst, src []byte)

Package: golang.org/x/crypto/tea

TEA (Tiny Encryption Algorithm). Deprecated - use AES or ChaCha20-Poly1305.

Constants

const (
    BlockSize = 8
    KeySize   = 16
)

Functions

// NewCipher creates and returns a cipher.Block.
// The key must be 16 bytes.
func NewCipher(key []byte) (cipher.Block, error)

// NewCipherWithRounds creates a cipher with a custom number of rounds.
// The standard number of rounds is 64.
func NewCipherWithRounds(key []byte, rounds int) (cipher.Block, error)

Package: golang.org/x/crypto/twofish

Twofish encryption algorithm. Deprecated - use AES or ChaCha20-Poly1305.

Constants

const BlockSize = 16

Types

// Cipher is an instance of Twofish encryption.
type Cipher struct {
    // contains unexported fields
}

// NewCipher creates and returns a Cipher.
// The key must be 16, 24, or 32 bytes.
func NewCipher(key []byte) (*Cipher, error)

func (c *Cipher) BlockSize() int
func (c *Cipher) Encrypt(dst, src []byte)
func (c *Cipher) Decrypt(dst, src []byte)

// KeySizeError reports an invalid key size.
type KeySizeError int

func (k KeySizeError) Error() string

Package: golang.org/x/crypto/xtea

XTEA (eXtended TEA) encryption algorithm. Deprecated - use AES or ChaCha20-Poly1305.

Constants

const BlockSize = 8

Types

// Cipher is an instance of XTEA encryption.
type Cipher struct {
    // contains unexported fields
}

// NewCipher creates and returns a Cipher.
// The key must be 16 bytes.
func NewCipher(key []byte) (*Cipher, error)

func (c *Cipher) BlockSize() int
func (c *Cipher) Encrypt(dst, src []byte)
func (c *Cipher) Decrypt(dst, src []byte)

// KeySizeError reports an invalid key size.
type KeySizeError int

func (k KeySizeError) Error() string

Best Practices

Encryption Algorithm Selection

  1. Recommended for new applications:

    • ChaCha20-Poly1305 (authenticated encryption)
    • AES-GCM from standard library (authenticated encryption)
  2. Never use without authentication:

    • Raw ChaCha20, Salsa20, or any block cipher in ECB/CBC mode
    • Always use AEAD modes (Authenticated Encryption with Associated Data)
  3. Avoid:

    • All legacy ciphers (Blowfish, CAST5, TEA, Twofish, XTEA)
    • 8-byte block ciphers (vulnerable to Sweet32 attack)

Nonce Management

  1. Never reuse a key/nonce combination
  2. For ChaCha20-Poly1305: Use random nonces (12 bytes)
  3. For XChaCha20-Poly1305: Use random nonces (24 bytes, more secure)
  4. Alternative: Use a counter if you can guarantee uniqueness

Key Generation

  1. Always use crypto/rand for key generation
  2. Key sizes:
    • ChaCha20/Salsa20: 32 bytes (256 bits)
    • AES: 16, 24, or 32 bytes (128, 192, or 256 bits)

Performance Considerations

  1. ChaCha20-Poly1305 is faster than AES-GCM on systems without AES hardware acceleration
  2. AES-GCM is faster on systems with AES-NI instruction set
  3. BLAKE2 (from hashing.md) is faster than SHA-2 for authenticated encryption constructions

Security Notes

  1. 8-byte block ciphers (Blowfish, CAST5, TEA, XTEA) are vulnerable to birthday attacks after ~32GB of data with the same key (Sweet32 CVE-2016-2183)
  2. CBC mode without authentication is vulnerable to padding oracle attacks
  3. Always authenticate: Use AEAD modes or combine encryption with HMAC (encrypt-then-MAC)
  4. Key derivation: Never use passwords directly as keys; use a KDF from hashing.md