analyst @ nohacky :~/briefings $
cat / briefings / linux-cryptography-guide
analyst@nohacky:~/briefings/linux-cryptography-guide.html
reading mode 14 min read
category linux
published March 2025
read_time 14 min

Linux Cryptography Guide: Encryption, Hashing, and Key Management

Linux ships with a powerful cryptographic toolchain built right into its core utilities. From protecting files with GPG to hardening SSH access and encrypting full disks with LUKS, knowing how these tools work — and when to use each one — is foundational to operating securely on any Linux system.

Cryptography on Linux is not a single tool or library — it is a layered ecosystem of utilities, each serving distinct roles in confidentiality, integrity, and authentication. Whether you are a sysadmin hardening servers, a penetration tester validating controls, or a developer protecting sensitive data at rest and in transit, fluency with Linux cryptographic tools translates directly into stronger security posture. This guide covers the practical commands and concepts that security practitioners use day to day.

Symmetric Encryption with OpenSSL

OpenSSL is the most widely deployed cryptographic library on Linux systems and exposes a command-line interface for a broad range of operations. For symmetric encryption — where the same key encrypts and decrypts — the openssl enc subcommand is your primary tool.

The following encrypts a file using AES-256-CBC with a password-derived key. The -pbkdf2 flag enables Password-Based Key Derivation Function 2, which is the current best practice and replaces the older MD5-based derivation that was the default before OpenSSL 1.1.1:

# Encrypt a file
$ openssl enc -aes-256-cbc -pbkdf2 -salt -in plaintext.txt -out encrypted.enc

# Decrypt
$ openssl enc -d -aes-256-cbc -pbkdf2 -in encrypted.enc -out decrypted.txt
warning

Avoid -aes-256-ecb (Electronic Codebook mode). ECB mode encrypts identical plaintext blocks to identical ciphertext blocks, leaking patterns about the underlying data. Always prefer CBC, CTR, or GCM modes.

For authenticated encryption — where the ciphertext includes a tag verifying it has not been tampered with — use AES-256-GCM. OpenSSL supports this through the same enc interface and through its EVP API in code. When writing scripts that will protect sensitive data long-term, GCM is the stronger choice because it provides both confidentiality and integrity verification in a single pass.

Generating Random Keys and IVs

When you need a high-entropy key or initialization vector outside of a password-based workflow, openssl rand produces cryptographically secure random bytes:

# Generate a 32-byte (256-bit) key in hex
$ openssl rand -hex 32

# Generate a 16-byte IV in hex
$ openssl rand -hex 16

# Base64-encoded 32-byte key (useful for environment variables)
$ openssl rand -base64 32

Asymmetric Encryption and GPG

GNU Privacy Guard (GPG) implements the OpenPGP standard and handles asymmetric key operations including key generation, file encryption, digital signatures, and the web of trust model. It is installed by default on most Linux distributions and is the standard tool for email encryption, package signing, and secure file transfer between parties.

Key Generation

Generating a new GPG keypair with the interactive interface is the recommended approach for first-time users. For automation and scripting, the --batch flag accepts a parameter file:

# Interactive key generation (recommended for new keys)
$ gpg --full-generate-key

# List your public keys
$ gpg --list-keys

# List your private (secret) keys
$ gpg --list-secret-keys --keyid-format LONG
note

Choose Ed25519 for new keys when your GPG version supports it (2.1+). Ed25519 provides equivalent security to RSA-3072 with dramatically shorter key material and faster signing operations. RSA-4096 remains acceptable but is slower and produces larger signatures.

Encrypting and Decrypting Files

To encrypt a file for a specific recipient, you need their public key imported into your keyring. GPG then encrypts the file such that only the holder of the corresponding private key can decrypt it:

# Encrypt for a recipient (by email or key ID)
$ gpg --encrypt --recipient recipient@example.com secret.txt
# Output: secret.txt.gpg

# Encrypt for yourself (useful for backups)
$ gpg --encrypt --recipient your@email.com backup.tar.gz

# Decrypt
$ gpg --decrypt secret.txt.gpg > secret.txt

# Symmetric encryption with GPG (passphrase-based, no keypair needed)
$ gpg --symmetric --cipher-algo AES256 secret.txt

Signing and Verifying

Digital signatures with GPG prove the origin and integrity of a file. A detached signature keeps the signature in a separate file, which is the standard approach for distributing signed software packages:

# Create a detached signature
$ gpg --detach-sign --armor release.tar.gz
# Output: release.tar.gz.asc

# Verify a detached signature
$ gpg --verify release.tar.gz.asc release.tar.gz

# Sign and encrypt in a single operation
$ gpg --sign --encrypt --recipient recipient@example.com document.pdf

Hashing and File Integrity

Cryptographic hash functions produce a fixed-length digest of arbitrary input. The same input always produces the same digest, and any modification to the input — even a single bit — produces a completely different digest. On Linux, hash verification is built into the standard utilities.

Core Hashing Commands

# SHA-256 hash of a file
$ sha256sum filename.iso

# SHA-512 hash
$ sha512sum filename.iso

# Verify against a published checksum file
$ sha256sum -c SHA256SUMS

# MD5 (legacy — do not use for security purposes)
$ md5sum filename

# Generate hashes for all files in a directory
$ find /path/to/dir -type f -exec sha256sum {} \; > checksums.txt
critical

MD5 and SHA-1 are cryptographically broken for collision resistance. Do not use them to verify the integrity of software downloads, certificates, or any security-sensitive data. SHA-256 is the current minimum; SHA-512 is preferred for high-assurance contexts. SHA-3 (Keccak) is available via openssl dgst -sha3-256 on OpenSSL 1.1.1+.

OpenSSL Digest Commands

OpenSSL provides its own hashing interface through the dgst subcommand, which supports a wider range of algorithms and integrates easily into signing workflows:

# SHA-256 via OpenSSL
$ openssl dgst -sha256 filename

# HMAC-SHA256 (keyed hash for message authentication)
$ openssl dgst -sha256 -hmac "secretkey" filename

# SHA3-256 (requires OpenSSL 1.1.1+)
$ openssl dgst -sha3-256 filename

SSH Key Management

SSH key authentication replaces password-based logins with asymmetric cryptography. The private key never leaves your machine; the server holds only your public key. When you connect, the server issues a cryptographic challenge that only your private key can solve, proving identity without transmitting a secret.

Generating SSH Keys

# Ed25519 (preferred — fast, small, strong)
$ ssh-keygen -t ed25519 -C "your@email.com"

# RSA-4096 (compatible with older servers)
$ ssh-keygen -t rsa -b 4096 -C "your@email.com"

# ECDSA P-384
$ ssh-keygen -t ecdsa -b 384 -C "your@email.com"

# Specify output file (useful for multiple keys)
$ ssh-keygen -t ed25519 -f ~/.ssh/work_key -C "work@company.com"
note

Always set a passphrase on your private key. A passphrase encrypts the private key file at rest, meaning an attacker who obtains the file cannot use it without also knowing the passphrase. Use ssh-add and the SSH agent to cache the decrypted key in memory during a session so you are not prompted repeatedly.

Deploying and Managing Keys

# Copy public key to a remote server
$ ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server

# Manual method (append public key to authorized_keys)
$ cat ~/.ssh/id_ed25519.pub | ssh user@server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

# View fingerprint of a key (useful for verification)
$ ssh-keygen -lf ~/.ssh/id_ed25519.pub

# Change passphrase on existing private key
$ ssh-keygen -p -f ~/.ssh/id_ed25519

# Convert OpenSSH key to PEM format (for compatibility)
$ ssh-keygen -p -m PEM -f ~/.ssh/id_rsa

Auditing Authorized Keys

On servers you administer, regularly audit ~/.ssh/authorized_keys for all users to detect unauthorized additions. Each line in that file represents a principal allowed to authenticate as that user — any unexpected entry is a potential backdoor:

# List all authorized_keys files on the system
$ find /home -name "authorized_keys" 2>/dev/null
$ find /root -name "authorized_keys" 2>/dev/null

# Show key fingerprints from an authorized_keys file
$ ssh-keygen -lf /home/user/.ssh/authorized_keys

TLS Certificates with OpenSSL

OpenSSL handles the full lifecycle of X.509 certificates used in TLS — from generating certificate signing requests (CSRs) to inspecting certificates on live servers. These skills are essential for managing internal PKI, testing configurations, and diagnosing certificate errors.

Generating Keys and CSRs

# Generate a private key and CSR in one command
$ openssl req -newkey rsa:4096 -keyout server.key -out server.csr \
  -subj "/CN=example.com/O=My Org/C=US"

# Generate a self-signed certificate (for testing/internal use)
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
  -days 365 -nodes -subj "/CN=localhost"

# Generate an Ed25519 private key
$ openssl genpkey -algorithm Ed25519 -out ed25519.key

Inspecting Certificates

# Inspect a certificate file
$ openssl x509 -in cert.pem -text -noout

# Check a live server's certificate
$ openssl s_client -connect example.com:443 -servername example.com 
warning

The -nodes flag in certificate generation stands for "no DES" — it outputs the private key unencrypted. Only use this for testing environments. Production private keys should always be passphrase-protected or stored in an HSM or secrets manager.

Full Disk Encryption with LUKS

Linux Unified Key Setup (LUKS) is the standard for full disk and partition encryption on Linux. It uses a layered key structure — the master key encrypts the partition, and one or more user passphrases or key files unlock the master key. This means you can add or remove access credentials without re-encrypting the entire disk.

Setting Up a LUKS Container

# Format a partition with LUKS (LUKS2 is default on modern systems)
$ sudo cryptsetup luksFormat /dev/sdX

# Open (decrypt) the container and map it
$ sudo cryptsetup luksOpen /dev/sdX my_volume

# Create a filesystem on the decrypted device
$ sudo mkfs.ext4 /dev/mapper/my_volume

# Mount it
$ sudo mount /dev/mapper/my_volume /mnt/secure

# Close when done
$ sudo umount /mnt/secure
$ sudo cryptsetup luksClose my_volume

Managing LUKS Keys

LUKS supports up to 8 key slots per partition (32 with LUKS2). Each slot can hold an independent passphrase or key file, and any one of them can unlock the volume:

# Add a new passphrase to an existing LUKS device
$ sudo cryptsetup luksAddKey /dev/sdX

# Remove a passphrase (requires knowing another valid passphrase)
$ sudo cryptsetup luksRemoveKey /dev/sdX

# View LUKS header information (active slots, cipher, key size)
$ sudo cryptsetup luksDump /dev/sdX

# Backup the LUKS header (critical — losing the header = losing all data)
$ sudo cryptsetup luksHeaderBackup /dev/sdX --header-backup-file luks-header.bak
critical

Always back up the LUKS header to a separate, secure location immediately after creating a LUKS volume. If the header becomes corrupted — which can happen from a power failure during a write — the entire volume becomes unrecoverable without a backup, regardless of whether you know the passphrase.

Password Hashing for Storage

Storing passwords as plaintext or with unsalted hashes is a critical vulnerability. Linux uses salted, iterated hashing algorithms in /etc/shadow, and understanding these formats helps when auditing system configurations or implementing application-level password storage.

# Generate a SHA-512 hashed password (as used in /etc/shadow)
$ openssl passwd -6 "mypassword"

# SHA-256 format
$ openssl passwd -5 "mypassword"

# Using Python's passlib-compatible crypt for bcrypt
$ python3 -c "import crypt; print(crypt.crypt('mypassword', crypt.mksalt(crypt.METHOD_SHA512)))"

# Inspect the hash format in /etc/shadow (requires root)
$ sudo grep username /etc/shadow
The shadow file format uses $id$salt$hash — where $6$ is SHA-512, $5$ is SHA-256, $2b$ is bcrypt, and $y$ is yescrypt (default on Debian 11+ and Fedora 35+). — Linux-PAM documentation

Yescrypt is the current state-of-the-art for Linux password hashing. It is memory-hard, meaning it is computationally expensive to attack with GPUs or ASICs, and it supports higher cost factors than bcrypt. If your distribution supports it, prefer yescrypt for new deployments.

Key Takeaways

  1. Use modern algorithms: AES-256-GCM for symmetric encryption, Ed25519 or RSA-4096 for asymmetric keys, SHA-256 or SHA-512 for hashing. Retire MD5, SHA-1, and DES wherever they appear.
  2. Protect private keys: Always passphrase-protect private keys and private key files. Use the SSH agent to avoid repeated passphrase entry in active sessions without leaving keys unprotected.
  3. LUKS header backups are non-negotiable: A corrupted LUKS header without a backup is permanent data loss. Back up the header immediately and store it separately from the encrypted volume.
  4. Audit key material regularly: Review SSH authorized_keys files, GPG keyrings, and LUKS key slots periodically to remove stale or unauthorized credentials. A key that should no longer have access but does is an open door.
  5. Authenticated encryption matters: Encryption alone does not prevent tampering. Use AES-GCM or HMAC-authenticated modes so that any modification to ciphertext is detected on decryption.

The Linux cryptographic toolchain is mature and capable, but it only provides protection when applied correctly and consistently. The commands in this guide are starting points — building them into scripts, automation pipelines, and operational checklists is what turns individual knowledge into systematic security.

— end of briefing