age: Simple, Modern, and Secure File Encryption

repository·main·Indexed 12 days ago

https://github.com/filosottile/age

A secure file encryption tool, format, and Go library designed for UNIX-style composability and small, explicit keys. It supports encryption via public keys, passphrases, and SSH keys, and includes post-quantum key support in v1.3.0+. The toolset includes the `age` CLI for encryption/decryption, `age-keygen` for key generation, and `age-inspect` for viewing encrypted file metadata.

Tokens
12.9K
Snippets
55
Records
66
Agent score
91%

What's inside age

  1. Quickstart: Encrypt and Decrypt a file

    main

    To use age, first generate a key pair, then encrypt a file using a recipient public key, and finally decrypt it using your identity file.

    1. Generate a key: age-keygen -o key.txt
    2. Encrypt: tar cvz ~/data | age -r <PUBLIC_KEY> > data.tar.gz.age
    3. Decrypt: age --decrypt -i key.txt data.tar.gz.age > data.tar.gz
    # Generate key
    $ age-keygen -o key.txt
    
    # Encrypt a tarball to a recipient
    $ tar cvz ~/data | age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age
    
    # Decrypt the file
    $ age --decrypt -i key.txt data.tar.gz.age > data.tar.gz
  2. Use post-quantum keys

    main

    To protect against future quantum computer attacks, you can generate hybrid post-quantum keys using the -pq flag with age-keygen. Post-quantum identities start with AGE-SECRET-KEY-PQ-1... and recipients with age1pq1....

    Note: Support for post-quantum keys requires age v1.3.0 or later. For older versions, use the age-plugin-pq binary.

    $ age-keygen -pq -o key.txt
    $ age-keygen -y key.txt > recipient.txt
    $ age -R recipient.txt example.jpg > example.jpg.age
    $ age -d -i key.txt example.jpg.age > example.jpg
  3. Install age

    main

    You can install age using various package managers depending on your operating system:

    • macOS/Linux (Homebrew): brew install age
    • macOS (MacPorts): port install age
    • Windows (winget): winget install --id FiloSottile.age
    • Windows (Chocolatey): choco install age.portable
    • Windows (Scoop): scoop bucket add extras && scoop install age
    • Alpine Linux: apk add age
    • Arch Linux: pacman -S age
    • Debian 12+ / Ubuntu 22.04+: apt install age
    • Debian 11 (Bullseye): apt install age/bullseye-backports (requires enabling backports)
    • Fedora 33+: dnf install age
    • Gentoo: emerge app-crypt/age
    • Guix: guix package -i age
    • NixOS / Nix: nix-env -i age
    • openSUSE Tumbleweed: zypper install age
    • Void Linux: xbps-install age
    • FreeBSD: pkg install age (security/age)
    • OpenBSD 6.7+: pkg_add age (security/age)

    Alternatively, you can download pre-built binaries or build from source using Go:

    go install filippo.io/age/cmd/...@latest
    brew install age
  4. Read passphrase from a file descriptor with AGE_PASSPHRASE_FD

    main
    If you prefer not to pass the passphrase as a plain string in an environment variable (to avoid shell history leaks), you can use AGE_PASSPHRASE_FD. This variable should contain the integer value of a file descriptor that holds the passphrase. The plugin will read the content from that descriptor and strip trailing newlines.
  5. Extend age with Plugins

    main

    The age tool can be extended via plugins. A plugin is only loaded if a corresponding recipient or identity is specified in the command.

    • Plugin Recipient: Starts with age1<pluginname>1.
    • Plugin Identity: Starts with AGE-PLUGIN-<PLUGINNAME>-1.

    When a plugin is invoked, age searches for age-plugin-<name> in the system PATH and executes it. The plugin handles the header encryption/decryption and may request user input.

    Common Plugin Patterns:

    • Hardware Keys: Plugins like age-plugin-yubikey allow using hardware-backed identities.
    • Symmetric Encryption: Some plugins might only provide an identity (for encryption) or require the -j flag (for decryption).
  6. Implement a plugin client using Recipient and Identity

    main

    To integrate an external identity provider or key management system with age, you can use the plugin package to implement age.Recipient or age.Identity.

    • Use Recipient when you want to encrypt data for a specific recipient (e.g., a public key stored in a plugin).
    • Use Identity when you want to decrypt data using a plugin-managed identity (e.g., a hardware token or an SSH key).

    Both types require a *ClientUI to handle user interactions (like prompts or confirmations) that the plugin might request during the (un)wrapping process.

    import "filippo.io/age/plugin"
    
    // For encryption (Recipient)
    recipient, err := plugin.NewRecipient("age1pluginname1...", ui)
    
    // For decryption (Identity)
    identity, err := plugin.NewIdentity("AGE-PLUGIN-NAME-1...", ui)
  7. Compare native keys vs batchpass plugin

    main

    While batchpass enables passphrase-based automation, the age ecosystem recommends using native keys for non-interactive workflows.

    Native Key Pattern (Recommended):

    1. Generate a key: age-keygen -o key.txt
    2. Store the identity string in an environment variable: export AGE_SECRET=$(cat key.txt)
    3. Encrypt/Decrypt using the identity: age -e -i <(echo "$AGE_SECRET") file.txt

    Batchpass Pattern: Use batchpass only when you specifically need scrypt-based passphrase protection and want to automate the entry of that passphrase via environment variables.

  8. Understand Recipients and Identities

    main

    In age, there is a fundamental distinction between Recipients and Identities:

    • Recipients are public values (like public keys) that define who can decrypt a file. A file can be encrypted to multiple recipients simultaneously.
    • Identities are private values (like private keys) that allow a user to decrypt a file encrypted to the corresponding recipient.

    Supported Key Types

    Native Keys

    Generated via age-keygen. They provide strong encryption and come in two flavors:

    • Classic Keys: Start with age1. Identity starts with AGE-SECRET-KEY-1.
    • Post-Quantum (PQ) Hybrid Keys: Start with age1pq1. Identity starts with AGE-SECRET-KEY-PQ-1. These are recommended for future-proofing against quantum computers.

    Note: A file cannot be encrypted to both PQ and classic keys at once, as this would negate the PQ security benefits.

    SSH Keys

    age supports RSA (min 2048 bits) and Ed25519 SSH keys.

    • Recipient format: An SSH public key in authorized_keys format (e.g., ssh-rsa ... or ssh-ed25519 ...).
    • Identity format: An SSH private key file passed to -i.
    • Limitation: Hardware tokens (YubiKeys) or ssh-agent are not supported for SSH identities. Use native keys or plugins for hardware support.
  9. Encrypt files with age

    main

    To encrypt a file, use the age command. By default, age operates in encryption mode. You must specify at least one recipient using -r (a single recipient string) or -R (a file containing one recipient per line).

    If no output file is specified with -o, the encrypted data is sent to standard output. If no input file is specified, age reads from standard input.

    Key Encryption Options:

    • -r, --recipient=RECIPIENT: Specify a single recipient (e.g., a native key or SSH public key).
    • -R, --recipients-file=PATH: Specify a file containing multiple recipients, one per line. Lines starting with # or empty lines are ignored. If PATH is -, recipients are read from stdin.
    • -p, --passphrase: Encrypt using a passphrase requested interactively. This cannot be combined with recipient flags. age can auto-generate a secure passphrase if you leave the prompt empty.
    • -a, --armor: Output the encrypted data in an ASCII-only "armored" encoding (a strict version of PEM with type AGE ENCRYPTED FILE).
    • -o, --output=OUTPUT: Write the result to a specific file, overwriting it if it exists.
    # Encrypt a file to a single recipient and save to a file
    age -o example.jpg.age -r age1pq167[...] example.jpg
    
    # Encrypt using a passphrase
    age -p secrets.txt > secrets.txt.age
    
    # Encrypt to multiple recipients from a file
    age -R recipients.txt example.jpg > example.jpg.age
  10. Generate new age key pairs with age-keygen

    main

    Use age-keygen to generate new native age identity key pairs. By default, it generates a traditional identity and outputs it to standard output. The output includes the public key and the creation timestamp as comments. If the output is redirected away from a terminal, the public key is printed to standard error.

    # Generate a new traditional identity
    $ age-keygen
    
    # Generate a new post-quantum identity
    $ age-keygen -pq
  11. Use age-plugin-batchpass for non-interactive passphrase encryption

    main

    The age-plugin-batchpass plugin allows you to perform passphrase-based encryption and decryption non-interactively by providing the passphrase through environment variables. This is useful for automation where you want to avoid manual password entry.

    Warning: In most cases, using native age keys is preferred over passphrases for automation. You can achieve non-interactive encryption with native keys by storing a secret identity in an environment variable.

    To use the plugin, invoke the age CLI with the -j batchpass flag and provide the passphrase via AGE_PASSPHRASE or AGE_PASSPHRASE_FD.

    # Encrypting a file
    AGE_PASSPHRASE=password age -e -j batchpass file.txt > file.txt.age
    
    # Decrypting a file
    AGE_PASSPHRASE=password age -d -j batchpass file.txt.age > file.txt
  12. Use the age-plugin-batchpass plugin

    main

    The age-plugin-batchpass plugin enables non-interactive passphrase-based encryption and decryption for the age CLI by using environment variables. This is useful for automation where a human cannot manually enter a passphrase.

    Warning: For most automated use cases, it is recommended to use native keys (identity strings) instead of passphrases to avoid the performance overhead of scrypt and the security risks of managing passphrases in scripts.

    age -e -j batchpass file.txt > file.txt.age
    age -d -j batchpass file.txt.age > file.txt