GnuPG can lock a file with a passphrase alone, without a key pair or a recipient. The gpg encrypt file command for that is gpg -c, and gpg -d reverses it. To gpg encrypt folder contents you need one extra step, because gpg reads a single stream of bytes. Every command and output below comes from GnuPG 2.4.4 on Linux in a throwaway GNUPGHOME.
GPG encrypt file with a passphrase: symmetric mode
With -c (long form --symmetric), gpg derives the key from a passphrase instead of someone's public key, which is all gpg symmetric encryption means. Interactively it asks twice in a pinentry dialog and writes the result next to the original:
$ gpg -c notes.txt
$ stat -c '%s %n' notes.txt notes.txt.gpg
28 notes.txt
104 notes.txt.gpgThe 76 extra bytes hold packet headers, the salt, a random prefix, the file name and an integrity check. That overhead barely grows with the file, so it only looks large on 28 bytes of text.
The plaintext notes.txt is still there: gpg never deletes its input. -o other.gpg picks another output name.
What GnuPG 2.4 picks by default
Older guides argue about CAST5 versus AES, but the file answers the question; --list-packets decodes its structure (it needs the passphrase to show the inner packets):
$ gpg --list-packets notes.txt.gpg 2>/dev/null | grep -v '^#'
:symkey enc packet: version 4, cipher 9, aead 0, s2k 3, hash 10
salt 337147B9C4886529, count 58720256 (252)
:encrypted data packet:
length: 87
mdc_method: 2
:compressed packet: algo=1
:literal data packet:
mode b (62), created 1793859473, name="notes.txt",
raw data: 28 bytescipher 9 is AES256, s2k 3 is the iterated and salted passphrase-to-key mode, hash 10 is SHA512, and mdc_method: 2 means the data carries a modification detection code, so tampering makes decryption fail loudly. The iteration count is calibrated to your machine's speed; three test runs on one laptop gave 52428800, 58720256 and 65011712. The literal packet even carries the original file name, inside the encryption.

--cipher-algo selects another cipher. gpg --version lists them, and 2.4.4 offers AES, TWOFISH, CAMELLIA and a few legacy ones.
$ gpg --cipher-algo CAMELLIA256 -o notes.cam.gpg -c notes.txt
$ gpg -d notes.cam.gpg > /dev/null
gpg: CAMELLIA256.CFB encrypted data
gpg: encrypted with 1 passphraseThe choice is recorded in the file, so the recipient runs a plain gpg -d. AES256 is a sensible default to keep.
How to gpg decrypt file contents again
gpg -d writes the plaintext to standard output; status messages go to standard error, so they do not end up in the data:
$ gpg -d notes.txt.gpg
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase
card PIN 0000, do not shareTo gpg decrypt file contents into a file of your choice, add -o: gpg -o notes.txt -d notes.txt.gpg. Plain gpg notes.txt.gpg also works; gpg prints WARNING: no command supplied. Trying to guess what you mean ... and writes notes.txt. If that file already exists, an interactive gpg asks before overwriting, and in --batch mode it stops with handle plaintext failed: General error, which here means only that the target file is in the way.
GPG encrypt folder contents on Linux with tar
To gpg encrypt folder trees, the directory has to become a single file first, because gpg only ever reads one input stream. The two-step version from older tutorials packs, then encrypts:
$ tar czf secret.tar.gz secret/
$ gpg -c secret.tar.gzIt works, but leaves an unencrypted secret.tar.gz next to the encrypted copy.
The tar gz encrypt Linux pipe: no plaintext copy on disk
The tar gz encrypt Linux pipe needs no temporary file. With -f -, tar writes to standard output and gpg reads the pipe, so no intermediate file exists:
$ tar czf - secret | gpg -c -o secret.tar.gz.gpg
$ file secret.tar.gz.gpg
secret.tar.gz.gpg: PGP symmetric key encrypted data - AES with 256-bit key salted & iterated - SHA512 .gpg normally compresses before encrypting (the compressed packet in the listing above), but here --list-packets showed no compressed packet at all: gpg recognized the gzip stream and skipped its own pass, so the z in tar does the real work. Restoring is the same pipe in reverse; tar tzf - lists the contents first:
$ gpg -d secret.tar.gz.gpg | tar tzf -
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase
secret/
secret/a.txt
secret/sub/
secret/sub/b.txt
$ gpg -d secret.tar.gz.gpg | tar xzf - -C restore-C restore extracts into an existing directory instead of overwriting the current secret/. In the test, diff -r secret restore/secret reported no differences.
The gpg-agent passphrase cache trap
Encrypt a file, decrypt it to check, and gpg does not ask for the passphrase at all. Nothing is broken: gpg-agent handles every passphrase prompt and caches what you type. For symmetric files the gpg manual says the cache is keyed on the message's salt, so it applies to that specific file. A logging pinentry made the behavior visible: the first decrypt opened pinentry, a second decrypt a few seconds later did not, and encrypting a file and then decrypting the same file did not ask either. The default lifetime, from gpgconf --list-options gpg-agent, is 600 seconds (default-cache-ttl) with a hard cap of 7200 (max-cache-ttl).
Two ways out:
$ gpgconf --reload gpg-agent # forget everything cached now
$ gpg --no-symkey-cache -c notes.txt # do not cache it on this callAfter the reload, the next gpg decrypt file call prompted again. --no-symkey-cache works per call: a file encrypted with it prompted on its first decrypt, but that decrypt, run without the option, cached the passphrase for the next one.

Scripts: batch mode and loopback pinentry
A script that has to gpg encrypt file contents cannot answer a pinentry window. Since GnuPG 2.1, gpg reads a passphrase from options only together with --batch and --pinentry-mode loopback. The safest form reads it from a file only the script's user can read:
$ chmod 600 ~/.backup-pass
$ gpg --batch --pinentry-mode loopback --passphrase-file ~/.backup-pass -c notes.txt--passphrase-file reads only the first line. Passing --passphrase 'correct horse' instead puts the secret into shell history and into the process list, readable by other users while gpg runs. The gpg man page calls that option "of very questionable security on a multi-user system." --passphrase-fd 0 suits a secret piped in from a password manager.
Symmetric or public key?
gpg symmetric encryption leaves one problem open: the shared passphrase has to reach the other person somehow. Public-key encryption avoids that: you encrypt to the recipient's key, and only their private key can decrypt.
$ gpg -e -r [email protected] -o notes.pk.gpg notes.txt
$ gpg -d notes.pk.gpg
gpg: encrypted with cv25519 key, ID B30DE64E910FCC69, created 2026-11-05
"Alice Example <[email protected]>"
card PIN 0000, do not shareThe test key was a fresh ed25519/cv25519 pair from gpg --quick-gen-key. Because it advertises AEAD support, --list-packets showed an aead encrypted packet (OCB mode) rather than the CFB packet that -c writes. For a one-off file, -c is simpler; for regular exchanges with the same people, swap keys once. Copying keys between your own machines is easier with an SSH config alias in place, since scp uses the same short names.
ASCII armor for mail and chat
--armor (-a) wraps the binary output in base64 text with a -----BEGIN PGP MESSAGE----- header, written to notes.txt.asc. It survives copy and paste into a mail body or a text file committed to Git (the Githug levels are a quick way to practice the Git side), and gpg -d reads it like the binary form.
Deleting the plaintext afterwards
rm only removes the directory entry. shred -u notes.txt overwrites the file's blocks before unlinking it, but its manual warns that shred relies on the assumption "that the file system and hardware overwrite data in place", and many platforms do not. Copy-on-write filesystems such as Btrfs write new blocks instead of overwriting, SSDs remap writes for wear leveling, and snapshots keep their own copies.
The tar gz encrypt Linux pipe sidesteps this for the tarball, which never touches the disk. The original folder is a different matter, and on an SSD there is no command that can prove its old blocks are gone. Whether that matters depends on who might ever hold the drive.
