Encrypt files with age
Encrypt files with age: generate a key, encrypt to one or more recipients or SSH keys, use a passphrase, and encrypt whole directories through tar.
Updated
in short
Generate a key with age-keygen -o key.txt, encrypt with age -r <public key>, and decrypt with age -d -i key.txt. Use -p when you want a passphrase instead of a key.
age encrypts a file to one or more public keys (recipients) and decrypts it with the matching private key (identity). Keys are short strings, there is no keyring and no config file, and it reads from standard input and writes to standard output, so it fits into pipes.
This guide covers keys, passphrases, SSH keys, recipient files, text-safe output and encrypting a directory with tar.
Tools used
Before you start
- macOS, Linux, BSD or Windows
- For the SSH key steps: an
ssh-ed25519orssh-rsakey pair
Steps
Step 1: Install age
age is packaged for most systems. Debian 12+, Ubuntu 22.04+ and Fedora carry it in the default repositories. The package installs both
ageandage-keygen.sh# macOS or Linux with Homebrew brew install age # Debian 12+ / Ubuntu 22.04+ sudo apt install age # Fedora sudo dnf install age # Arch Linux sudo pacman -S age # Windows winget install --id FiloSottile.ageshage --versionStep 2: Generate a key pair
age-keygen -owrites the private key to a new file with0600permissions and prints the public key. It refuses to overwrite an existing file. The public key starts withage1and is safe to share; the file holds the secret key, which starts withAGE-SECRET-KEY-1.age-keygen -yprints the public key again from the key file.shmkdir -p ~/.config/age age-keygen -o ~/.config/age/key.txtoutputPublic key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
shage-keygen -y ~/.config/age/key.txtStep 3: Encrypt and decrypt with a key
-rtakes a public key and can be repeated; every listed recipient can decrypt the file on their own.-osets the output file; without it age writes to standard output. To decrypt, pass-dand the key file with-i.shage -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p -o notes.txt.age notes.txtsh# two recipients age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \ -r age1lggyhqrw2nlhcxprm67z43rta597azn8gknawjehu9d9dl0jq3yqqvfafg \ -o notes.txt.age notes.txtshage -d -i ~/.config/age/key.txt -o notes.txt notes.txt.ageStep 4: Use a recipients file
With more than one or two recipients, list the public keys in a file, one per line, and pass it with
-R. Empty lines and lines starting with#are ignored.-Rcan be repeated and combined with-r.shcat > recipients.txt <<'EOF' # Alice age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p # Bob age1lggyhqrw2nlhcxprm67z43rta597azn8gknawjehu9d9dl0jq3yqqvfafg EOF age -R recipients.txt -o notes.txt.age notes.txtStep 5: Encrypt to SSH keys
age accepts
ssh-ed25519andssh-rsapublic keys as recipients and the matching private key file as the identity. Keys held inssh-agentor on hardware tokens are not supported. An SSH public key file works with-R, and so does a GitHub.keysURL piped in with-R -(the input file must then be given as an argument).Files encrypted to an SSH key carry a tag that links them to that public key.
shage -R ~/.ssh/id_ed25519.pub -o notes.txt.age notes.txt age -d -i ~/.ssh/id_ed25519 -o notes.txt notes.txt.agesh# encrypt to the SSH keys on a GitHub profile curl -s https://github.com/<user>.keys | age -R - -o notes.txt.age notes.txtStep 6: Encrypt with a passphrase
-pasks for a passphrase on the terminal and offers to generate one if you leave it empty. It cannot be combined with-r,-Ror-i. Decryption detects passphrase files on its own, so runage -dwithout-i.shage -p -o secrets.txt.age secrets.txtoutputEnter passphrase (leave empty to autogenerate a secure one):
shage -d -o secrets.txt secrets.txt.ageoutputEnter passphrase:
Step 7: Produce text-safe output with
-aEncrypted files are binary.
-a(--armor) writes a PEM-style text block instead, for pasting into an email, chat or a YAML file. Decryption detects armor automatically.shage -a -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p notes.txtoutput-----BEGIN AGE ENCRYPTED FILE----- ... -----END AGE ENCRYPTED FILE-----
Step 8: Encrypt a directory with tar
age encrypts a single stream, so archive a directory with tar first. Both directions work in a pipe without writing the unencrypted archive to disk.
shtar czf - ~/documents | age -R recipients.txt > documents.tar.gz.ageshage -d -i ~/.config/age/key.txt documents.tar.gz.age | tar xzf -
Troubleshooting
refusing to output binary to the terminal: add-o file, redirect with>, or use-a.no identity matched any of the recipients: the file was not encrypted to the key you passed with-i.file is passphrase-encrypted but identities were specified: drop-iand runage -dalone.-p/--passphrase can't be combined with -r/--recipient: use either a passphrase or recipients, not both.- SSH key in
ssh-agentor on a YubiKey: age cannot use it. Pass a private key file, or use a native age key.
Tips
- age 1.3.0+ supports post-quantum keys:
age-keygen -pq. Their public keys are about 2000 characters long. - A key file can itself be passphrase-protected:
age-keygen | age -p > key.age, then decrypt with-i key.age. - age 1.3.0+ ships
age-inspect, which shows the recipient types and sizes of an encrypted file without decrypting it.
FAQ
- Should I use a key or a passphrase?
- Use a key for anything a script or another person decrypts; it needs no prompt and supports multiple recipients. Use a passphrase for a one-off file you will decrypt yourself.
- Can I add a recipient to a file that is already encrypted?
- No. The recipient list is fixed at encryption time. Decrypt the file and encrypt it again with the new recipient list.
- Can I encrypt a file to myself without the public key?
- Yes. With `-e` set explicitly, `-i` encrypts to the identity in the key file: `age -e -i key.txt file.txt > file.txt.age`.