gpg
Following is the configuration of my ~/.config/isyncrc file:
# twine ========================================================
# 1. Configure the remote server
IMAPAccount twine
Host twineintlcom.securemail.hk
User alowree@twineintl.com
# Works on macOS only
# PassCmd "security find-generic-password -a 'alowree@twineintl.com' -s 'neomutt-twine' -w"
# Works on both macOS and Arch Linux
PassCmd "pass Email/alowree@twineintl.com"
Port 993
TLSType IMAPS
AuthMechs PLAIN
# SystemCertificates no
# CertificateFile ~/.maildir/certificates/root-certificates.pem
# 2. Configure the remote store
IMAPStore twine-remote
Account twine
# 3. Configure the local mail store
MaildirStore twine-local
Path ~/.maildir/twine/
Inbox ~/.maildir/twine/INBOX
SubFolders Verbatim
# 4. Connect them with a channel
# Channel connecting <acount-name>-remote to <acount-name>-local
Channel twine
Far :twine-remote:
Near :twine-local:
Patterns *
Sync All
Expunge Both
Create Near
Remove Near
SyncState *
CopyArrivalDate yes
ExpireUnread yes
# ==============================================================As you can see, currently I use the app keychain to manage passwords on macOS, and I use it inside the isyncrc config file to retrieve password for my primary email account. Now that I have another newly installed Arch Linux, and I intend to converge my Neomutt configurations into the same one set, which is "gpg+pass" based and can be fully shared between macOS and Arch Linux, so that I don't have to maintain two different sets of configurations between the two operating systems.
Generate one detailed tutorial to introduce GPG and some use cases, then another tutorial about the unix password manager pass. Then combine the two for the actually implementation inside my neomuttrc configuration files. So there are going to be three parts in total, GPG, pass, and then the combination of the two. In order to make the tutorials full of details, your first output should be focus on GPG only.
This is an excellent plan. Moving to a pass + GPG setup is the definitive way to have a unified, secure, and scriptable configuration across macOS and Arch Linux. Since pass is essentially a wrapper for GPG, we must start by getting GPG configured perfectly on both systems.
Here is Part 1 of your tutorial, focused solely on GPG.
1.1 What is GPG and Why is it the Right Choice?
GnuPG (GPG) is a free implementation of the OpenPGP standard. At its core, it is a cryptography tool that allows for secure communication and data storage.
For your specific use case (converging NeoMutt configs), we care about two specific features:
- Asymmetric Encryption: GPG uses a Public Key to encrypt data (locking it) and a Private Key to decrypt it (unlocking it). This means you can safely store an encrypted file in your Dropbox or GitHub repo because only your Private Key can unlock it.
- The Agent: GPG comes with a background service called
gpg-agent. It caches your passphrase for a set amount of time. Once you unlock your key,passandmbsynccan retrieve passwords without prompting you every single time.
1.2 Installation (macOS vs. Arch Linux)
We need the same version of GPG on both systems to avoid compatibility headaches.
On Arch Linux: Open a terminal and run:
sudo pacman -S gnupgOn macOS: You have two options. Option A is the standard command line tool (via Homebrew). Option B is the GPG Suite (which includes a GUI key manager and better macOS integration). I strongly recommend Option B for macOS users because it handles passphrase caching in the login keychain more gracefully.
Option A (Homebrew):
bashbrew install gnupgOption B (GPG Suite - Recommended):
bashbrew install --cask gpg-suiteNote: If you use GPG Suite, you will use their GUI to manage keys, but the terminal commands remain exactly the same.
I took Option A on my macOS machine, because I felt comfortable working inside the terminal and wanted to experience the very basic gnupg utiliy in the first place.
1.3 Creating Your Master Key Pair
We will create a key that never expires. While security purists prefer expiration, for email setup maintenance, a non-expiring key simplifies the process (provided you keep it safe).
Run the following command on either macOS or Arch (it is identical):
gpg --full-generate-keyYou will be guided through a prompt. Here is exactly what to choose for email compatibility:
- Kind of key: Select
1(RSA and RSA) (default). - Keysize: Enter
4096. (Whilepassworks with 2048, 4096 is the modern standard for email encryption). - Expiration: Enter
0(Key does not expire). - Real name: Enter your full name (e.g.,
Alowree XU). - Email address: Enter
alowree@twineintl.com(This must match the email in yourisyncrc). - Comment: (Optional, e.g.,
Email Key).
Finally, you will be asked for a passphrase.
- Security: This is the master key to your digital identity. Make it long and strong.
- Usability: Because we will cache this, you will only type it once per login session.
1.4 Finding Your Key ID
pass doesn't care about your name; it cares about a specific ID. List your keys to find it.
gpg --list-secret-keys --keyid-format LONGYou will see output similar to this:
sec rsa4096/AAAAAAAAAAAAAAAA 2024-01-01 [SC]
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid [ultimate] Alex Lowree <alowree@twineintl.com>
ssb rsa4096/BBBBBBBBBBBBBBBB 2024-01-01 [E]The string next to rsa4096/ is your Key ID. In this example, it is AAAAAAAAAAAAAAAA (the last 16 characters of the fingerprint).
Copy this Key ID. You will need it to initialize pass in Part 2.
1.5 The "Headless" Challenge (Crucial for Arch Linux)
There is a common trap on Arch Linux (and sometimes macOS) where GPG cannot find your terminal to ask for the passphrase.
If you run a command and get gpg: decryption failed: No secret key or Inappropriate ioctl for device, your GPG_TTY variable is not set.
The Fix: Add this line to your shell config file (~/.zshrc if you use Zsh, or ~/.bashrc for Bash):
export GPG_TTY=$(tty)After adding it, restart your terminal or run source ~/.zshrc.
1.6 Configuring the Agent (Killing the Pop-ups)
The goal is to enter your passphrase once when you log in, not every time mbsync runs.
Create the configuration file ~/.gnupg/gpg-agent.conf:
nano ~/.gnupg/gpg-agent.confPaste these settings:
# How long (in seconds) the password stays in memory after last use
default-cache-ttl 28800
# Max time the password stays in memory regardless of activity
max-cache-ttl 86400
# The program that asks for the password
pinentry-program /usr/bin/pinentry-tty- For macOS (GPG Suite): Change the last line to
pinentry-program /usr/local/bin/pinentry-macto get a native Mac dialog box. - For Arch:
pinentry-ttyworks perfectly in the terminal.
Restart the Agent:
gpgconf --kill gpg-agent1.7 Testing Your Setup
Before moving to pass, let's ensure the encryption works.
Export your Public Key (You don't need this now, but it validates the key):
bashgpg --export --armor alowree@twineintl.com > my-public-key.ascTest Encryption/Decryption:
bashecho "Secret testing" > test.txt gpg --encrypt --recipient alowree@twineintl.com test.txt rm test.txt gpg --decrypt test.txt.gpgIf you see
Secret testingprinted to the screen, your GPG is configured perfectly for Arch Linux, macOS, and your upcomingpasssetup.
In Part 2, we will take this GPG key and use it to initialize pass, migrating your Keychain password into a simple, syncable file structure.
Welcome to the first part of your cross-OS convergence setup. Moving away from platform-specific tools like macOS Keychain and toward a unified command-line architecture gives you immense flexibility.
Before we can use pass to feed your passwords to isync/mbsync and neomutt, we need a firm foundation in GnuPG (Gnu Privacy Guard). GPG handles the actual cryptographic heavy lifting (encryption, decryption, and key management) under the hood.
1. What is GPG and Asymmetric Cryptography?
Unlike standard password-based encryption (symmetric encryption) where the same key locks and unlocks data, GPG is predominantly based on asymmetric cryptography (public-key cryptography).
- The Public Key: Think of this as an open padlock. You can hand copies of it to anyone. They use it to encrypt data meant for you or to verify things signed by you.
- The Private Key: This is the physical key that opens that padlock. Never share this. You protect it with a strong passphrase, and it is used to decrypt data or sign data.
For your specific use case (managing local passwords), you will use your Public Key to lock (encrypt) your email passwords, and your Private Key to unlock (decrypt) them whenever neomutt or mbsync requests them.
2. Setting Up GPG on macOS and Arch Linux
Because we are aiming for a unified configuration, we want to install GPG on both environments so that they behave identically.
Installation
- On Arch Linux:
sudo pacman -S gnupg pinentry- On macOS (via Homebrew):
brew install gnupg pinentry-macGenerating Your Key Pair
Run the following command on either machine (we will export it to the other later):
gpg --full-generate-keyWhen prompted, choose the following recommended options:
- Kind of key: Select
(1) RSA and RSA (default)or(9) ECC (Elliptic Curve)if you prefer modern cryptography. RSA (3072 or 4096 bits) is widely supported. - Keysize: If you chose RSA, type
4096. - Validity: Choose
0(key does not expire) for personal password storage convenience, or set a realistic timeline (e.g.,2y). - User ID Details: Enter your real name and the email address matching your configuration (
alowree@twineintl.com). - Passphrase: Enter a strong passphrase. Remember this well. This passphrase will be the master key to unlocking all your passwords.
3. The Magic Component: gpg-agent & Pinentry
If you had to type your long master GPG passphrase every single time mbsync ran a background sync, you would go crazy. That's where gpg-agent comes into play. It caches your decrypted private key in memory so you only have to type your password once per session.
To ensure seamless prompting in both desktop graphical environments and headless TUI terminal sessions, we need to configure gpg-agent.
Create or edit your gpg-agent configuration file:
nano ~/.gnupg/gpg-agent.confAdd the following lines to optimize caching and pinpoint your entry program:
# Cache the passphrase for 1 day (86400 seconds) after last use
default-cache-ttl 86400
max-cache-ttl 86400
# Tell GPG which pinentry program to default to
# (We will use a smart trick to handle macOS vs Arch automatically)Dealing with Cross-OS Pinentry
Because macOS benefits from a native graphical popup (pinentry-mac) and Arch Linux might use a terminal screen (pinentry-curses) or a Linux GUI popup (pinentry-gnome3), it helps to let GPG adapt, or fall back dynamically.
On macOS, ensure your ~/.gnupg/gpg-agent.conf links explicitly to homebrew's variant if it doesn't pop up:
pinentry-program /opt/homebrew/bin/pinentry-macOn Arch Linux, it usually defaults cleanly to standard terminal or desktop prompts. If you run into issues on headless environments, adding pinentry-program /usr/bin/pinentry-curses fixes it.
After editing the configuration, reload the agent:
gpg-connect-agent reloadagent /bye4. Key Syncing: Moving GPG to your second OS
Since you generated your key pair on Machine A, you must securely copy it to Machine B to achieve complete convergence.
Step 1: Export from Machine A
Find your Key ID first:
gpg --list-secret-keys --keyid-format=longLook for the hex string on the sec line (e.g., 3AA5C34371567BD2). Export both your public and private keys to files:
gpg --export -a "alowree@twineintl.com" > public.key
gpg --export-secret-keys -a "alowree@twineintl.com" > private.keyStep 2: Transfer Files Securely
Move public.key and private.key over to your other machine using a secure medium (e.g., scp, a thumb drive, or an encrypted local transfer).
Step 3: Import on Machine B
On the second machine, pull the keys into your local GPG keyring:
gpg --import public.key
gpg --import private.keyStep 4: Establish Trust
By default, GPG treats imported keys with suspicion. You must explicitly mark your own key as trusted on the new machine:
gpg --edit-key "alowree@twineintl.com"You will enter an interactive GPG prompt. Type trust, select option 5 (I trust ultimately), confirm with y, and then type quit.
5. Essential Verification Commands
Before moving on to Part 2 (where we install pass), let's make sure your GPG setup is working exactly as intended by simulating basic text encryption and decryption.
- To Encrypt a Test String:
echo "SecretEmailPassword123" | gpg -e -r "alowree@twineintl.com" > test.gpg- To Decrypt a Test String:
gpg -d test.gpgIf the second command prints SecretEmailPassword123 cleanly (prompting you via a popup window for your passphrase the first time, and succeeding instantly without a prompt the second time), your GPG configuration is flawlessly established.
This completes the first building block. Let me know when you are ready, and we will move to Part 2: Configuring the standard UNIX password manager (pass) using this GPG key.
