GPG Encryption Behavior: Why Files Are Encrypted with Subkeys Instead of Primary Keys


2 views

When examining your keyring with gpg --list-keys --keyid-format LONG, you'll notice usage flags like:

pub   rsa4096/YYYYYYYY 2023-01-01 [SCA]
      Key fingerprint = 1234 5678 90AB CDEF 1234  5678 90AB CDEF 1234 5678
uid         [ultimate] Alice Developer (Work Key) 
sub   rsa2048/XXXXXXXX 2023-01-01 [E]

The [E] flag indicates this subkey is specifically designated for encryption operations, while the primary key has [SCA] (Sign, Certify, Authenticate) capabilities. This separation is by design in modern GPG/PGP implementations.

GPG automatically selects the most appropriate key based on:

  • Key usage flags (primary keys often lack encryption capability)
  • Key strength (newer subkeys may use stronger algorithms)
  • Revocation status
  • Expiration dates

The encryption subkey is typically preferred because:

  1. It allows key revocation without losing access to historical messages
  2. Enables key rotation while maintaining the same identity
  3. Provides better security through algorithm agility

If you absolutely need to encrypt to the primary key (for legacy system compatibility), use:

gpg --encrypt --recipient YYYY --throw-keyids --no-auto-key-locate file.txt

Alternatively, you can modify the recipient's key preferences:

gpg --edit-key collaborator@example.com
> showpref
> setpref SHA256 AES256 AES192 AES 3DES SHA1 SHA384 SHA512 SHA224
> updpref
> save

Here's a script that ensures encryption uses the primary key when needed:

#!/bin/bash
# encrypt-to-primary.sh
RECIPIENT="collaborator@example.com"

# Get primary key ID
PRIMARY_KEY=$(gpg --list-keys --with-colons "$RECIPIENT" | \
  awk -F: '/^pub:/ { print $5 }')

# Encrypt using explicit key selection
gpg --encrypt --recipient "$PRIMARY_KEY" \
    --output "${1}.gpg" "$1"

echo "Encrypted $1 using primary key $PRIMARY_KEY"

To debug why GPG selects specific keys:

gpg --debug-all --encrypt --recipient collaborator@example.com file.txt 2>&1 | \
  grep -i "using\|selected"

Common output patterns to look for:

gpg: DBG: pkd.c:392: looking at subkey XXXXXXXX
gpg: DBG: pkd.c:407: subkey XXXXXXXX has usage 0x0C (encrypt)
gpg: DBG: pkd.c:422: selected subkey XXXXXXXX (E)

When working with GPG, you'll notice it has a hierarchical key structure:

Primary Key (YYYY)
├── Subkey 1 (XXXX) [Encryption]
├── Subkey 2 [Signing]
└── Subkey 3 [Authentication]

The message gpg: using subkey XXXX instead of primary key YYYY indicates GPG is following its designed behavior. The primary key typically has usage flags SCA (Sign, Certify, Authenticate), while encryption subkeys are marked with E.

There are several technical reasons for this behavior:

  • Security: If an encryption subkey is compromised, you can revoke just that subkey without affecting your entire identity
  • Key Rotation: Easier to rotate encryption keys periodically while keeping the same primary key
  • Performance: Encryption subkeys often use faster algorithms than primary keys

While this is generally good practice, it can cause issues with:

1. Legacy systems expecting primary key encryption
2. Automated tools with strict key validation
3. Some PGP implementations that don't properly handle subkeys

If you absolutely need to encrypt to the primary key, you can use:

gpg --encrypt --recipient YYYY --no-encrypt-to file.txt

Or modify your gpg.conf:

no-encrypt-to
no-auto-key-locate

When working with teams:

  1. Verify all subkeys have proper usage flags
  2. Ensure all systems can handle subkey encryption
  3. Consider creating a shared encryption policy document

To inspect key capabilities:

gpg --list-keys --with-subkey-fingerprints
gpg --edit-key YYYY
> showpref

You should see output like:

pub   rsa4096/YYYY  [SCA]
      Key fingerprint = ABCD 1234...
uid        [ultimate] John Doe <john@example.com>
sub   rsa2048/XXXX  [E]
      Key fingerprint = EFGH 5678...

For systems that can't handle subkeys, you might need to:

# Export just the primary key
gpg --export YYYY > primary_key.pub

# Or create a key without subkeys
gpg --quick-gen-key "Temp User" rsa4096
gpg --export TEMP_KEY > temp_key.pub