age Encryption — Bash Functions for Encrypt/Decrypt

Two small bash functions that wrap age — a modern, audited file-encryption tool from Filippo Valsorda — into a one-shot tar + encrypt and decrypt + extract workflow against a passphrase. They live in your shell config (.bashrc or .zshrc) and give you portable, password-protected archives without dragging in GPG or a key management story.

Threat model: at-rest protection for directories you carry around on laptops, USB sticks, or sync to consumer cloud storage (Dropbox, iCloud, Google Drive). Attacker has the encrypted file but not the passphrase. The passphrase strength is the whole game — use a long, random one (a passphrase manager entry or a 6+ word diceware string).

What it produces: a single <dir>.tar.gz.age file. The tar.gz step keeps directory structure and permissions; the .age layer is the X25519 / scrypt-passphrase encryption envelope.


Install age:

# macOS
brew install age

# Debian / Ubuntu
sudo apt install age

# Verify
age --version


Drop into ~/.bashrc (or ~/.zshrc):

Click Copy in the top-right of the block, then paste the whole thing at the bottom of your shell config. Open a new shell or run source ~/.bashrc and you'll have en and de available everywhere.

#--------------------------------------------------------------------------------------------------------#
# Encrypt a directory with age (passphrase) -> <dir>.tar.gz.age
# Usage: en Notes/
#--------------------------------------------------------------------------------------------------------#
en() {
    if [ -z "$1" ]; then
        echo "Usage: en <directory>"
        return 1
    fi
    if ! command -v age >/dev/null; then
        echo "age not installed. Run: brew install age"
        return 1
    fi
    local src="${1%/}"
    if [ ! -d "$src" ]; then
        echo "Error: '$src' is not a directory"
        return 1
    fi
    local out="${src}.tar.gz.age"
    if [ -e "$out" ]; then
        echo "Error: '$out' already exists"
        return 1
    fi
    echo "Encrypting '$src' -> '$out'"
    echo "  $ tar czf - $src | age -p -o $out"
    if tar czf - "$src" | age -p -o "$out"; then
        echo "✓ Done: $(ls -lh "$out" | awk '{print $5"  "$NF}')"
    else
        echo "✗ Failed"
        rm -f "$out"
        return 1
    fi
}

#--------------------------------------------------------------------------------------------------------#
# Decrypt an age file and extract its tar -> current directory
# Usage: de notes.tar.gz.age
#--------------------------------------------------------------------------------------------------------#
de() {
    if [ -z "$1" ]; then
        echo "Usage: de <file.tar.gz.age>"
        return 1
    fi
    if ! command -v age >/dev/null; then
        echo "age not installed. Run: brew install age"
        return 1
    fi
    if [ ! -f "$1" ]; then
        echo "Error: '$1' not found"
        return 1
    fi
    echo "Decrypting '$1' -> current directory"
    echo "  $ age -d $1 | tar xzf -"
    if age -d "$1" | tar xzf -; then
        echo "✓ Extracted"
    else
        echo "✗ Failed"
        return 1
    fi
}
#--------------------------------------------------------------------------------------------------------#


Usage:

# Encrypt a directory (you'll be prompted for a passphrase, twice)
en Notes/
# Encrypting 'Notes' -> 'Notes.tar.gz.age'
#   $ tar czf - Notes | age -p -o Notes.tar.gz.age
# Enter passphrase (leave empty to autogenerate a secure one):
# Confirm passphrase:
# ✓ Done: 142K  Notes.tar.gz.age

# Decrypt + extract back into current directory
de Notes.tar.gz.age
# Decrypting 'Notes.tar.gz.age' -> current directory
#   $ age -d Notes.tar.gz.age | tar xzf -
# Enter passphrase:
# ✓ Extracted


What the functions guard against:


Operational notes:


Where this fits in the security model:

This is layer 4 (Data Protection — At Rest) of the defense-in-depth model: a passphrase-protected envelope around files you don't trust the storage layer (laptop, USB, consumer cloud) to guard for you. It is intentionally not a substitute for KMS-backed envelope encryption when the data lives inside a cloud account — for that, see AWS KMS, Snowflake's encryption key hierarchy, or Databricks CMKs.

↑ Back to Top