GnuPG

Generate new Offline Key

This instructions are for generating a master key that can be kept offline. For day-to-day work (signing, encrypting and authenticating) subkeys are generated that can be moved to an online machine or smartcard. The subkeys have a short lifetime allowing to rotate the keys frequently. Because the master key remains the same, your identity won’t change.

Important

Clocks on offline machines tend to drift out of sync and batteries deplete. Do check if the time is correct:

date
  1. Generate Master (Certify) Key

    Generate new key with only certify capibility. This key is used later on to certifiy our subkeys with encrypt, sign and authentice capability respectively:

    $ gpg --expert --full-generate-key
    gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Please select what kind of key you want:
       (1) RSA and RSA (default)
       (2) DSA and Elgamal
       (3) DSA (sign only)
       (4) RSA (sign only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
       (9) ECC and ECC
      (10) ECC (sign only)
      (11) ECC (set your own capabilities)
      (13) Existing key
    Your selection? 11
    
    Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
    Current allowed actions: Sign Certify
    
       (S) Toggle the sign capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? s
    
    Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
    Current allowed actions: Certify
    
       (S) Toggle the sign capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? q
    Please select which elliptic curve you want:
       (1) Curve 25519
       (3) NIST P-256
       (4) NIST P-384
       (5) NIST P-521
       (6) Brainpool P-256
       (7) Brainpool P-384
       (8) Brainpool P-512
       (9) secp256k1
    Your selection? 8
    Please specify how long the key should be valid.
             0 = key does not expire
          <n>  = key expires in n days
          <n>w = key expires in n weeks
          <n>m = key expires in n months
          <n>y = key expires in n years
    Key is valid for? (0)
    Key does not expire at all
    Is this correct? (y/N) y
    
    GnuPG needs to construct a user ID to identify your key.
    
    Real name: Peter Gerber
    Email address: peter@arbitrary.ch
    Comment:
    You selected this USER-ID:
        "Peter Gerber <peter@arbitrary.ch>"
    
    Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    gpg: key 4A72372BAF48DADE marked as ultimately trusted
    gpg: directory '/home/user/.gnupg/openpgp-revocs.d' created
    gpg: revocation certificate stored as '/home/user/.gnupg/openpgp-revocs.d/E6BFD964AA7CEBD360537DDB4A72372BAF48DADE.rev'
    public and secret key created and signed.
    
    pub   brainpoolP512r1 2020-12-31 [C]
          E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    uid                      Peter Gerber <peter@arbitrary.ch>
    
    gpg> quit
    Save changes? (y/N) y
    

    Replace the ID in the example, E6BFD964AA7CEBD360537DDB4A72372BAF48DADE, with the actual ID in the commands below.

  2. Create Subkeys

    Key for encrypting:

    $ gpg --expert --edit-key E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Secret key is available.
    
    sec  brainpoolP512r1/4A72372BAF48DADE
         created: 2020-12-31  expires: never       usage: C
         trust: ultimate      validity: ultimate
    [ultimate] (1). Peter Gerber <peter@arbitrary.ch>
    
    gpg> addkey
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
      (10) ECC (sign only)
      (11) ECC (set your own capabilities)
      (12) ECC (encrypt only)
      (13) Existing key
    Your selection? 12
    Please select which elliptic curve you want:
       (1) Curve 25519
       (3) NIST P-256
       (4) NIST P-384
       (5) NIST P-521
       (6) Brainpool P-256
       (7) Brainpool P-384
       (8) Brainpool P-512
       (9) secp256k1
    Your selection? 1
    Please specify how long the key should be valid.
             0 = key does not expire
          <n>  = key expires in n days
          <n>w = key expires in n weeks
          <n>m = key expires in n months
          <n>y = key expires in n years
    Key is valid for? (0) 400
    Key expires at Fri 04 Feb 2022 01:02:42 PM CET
    Is this correct? (y/N) y
    Really create? (y/N) y
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    
    sec  brainpoolP512r1/4A72372BAF48DADE
         created: 2020-12-31  expires: never       usage: C
         trust: ultimate      validity: ultimate
    ssb  cv25519/EA5164ADF741144D
         created: 2020-12-31  expires: 2022-02-04  usage: E
    [ultimate] (1). Peter Gerber <peter@arbitrary.ch>
    

    Key for signing:

    gpg> addkey
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
      (10) ECC (sign only)
      (11) ECC (set your own capabilities)
      (12) ECC (encrypt only)
      (13) Existing key
    Your selection? 11
    
    Possible actions for a ECDSA/EdDSA key: Sign Authenticate
    Current allowed actions: Sign
    
       (S) Toggle the sign capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection?
    Please select which elliptic curve you want:
       (1) Curve 25519
       (3) NIST P-256
       (4) NIST P-384
       (5) NIST P-521
       (6) Brainpool P-256
       (7) Brainpool P-384
       (8) Brainpool P-512
       (9) secp256k1
    Your selection? 1
    Please specify how long the key should be valid.
             0 = key does not expire
          <n>  = key expires in n days
          <n>w = key expires in n weeks
          <n>m = key expires in n months
          <n>y = key expires in n years
    Key is valid for? (0) 400
    Key expires at Fri 04 Feb 2022 01:02:56 PM CET
    Is this correct? (y/N) y
    Really create? (y/N) y
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    
    sec  brainpoolP512r1/4A72372BAF48DADE
         created: 2020-12-31  expires: never       usage: C
         trust: ultimate      validity: ultimate
    ssb  cv25519/EA5164ADF741144D
         created: 2020-12-31  expires: 2022-02-04  usage: E
    ssb  ed25519/A9BC0494BD1AE92E
         created: 2020-12-31  expires: 2022-02-04  usage: S
    [ultimate] (1). Peter Gerber <peter@arbitrary.ch>
    

    Key for authenticating:

    gpg> addkey
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
      (10) ECC (sign only)
      (11) ECC (set your own capabilities)
      (12) ECC (encrypt only)
      (13) Existing key
    Your selection? 11
    
    Possible actions for a ECDSA/EdDSA key: Sign Authenticate
    Current allowed actions: Sign
    
       (S) Toggle the sign capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? s
    
    Possible actions for a ECDSA/EdDSA key: Sign Authenticate
    Current allowed actions:
    
       (S) Toggle the sign capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? a
    
    Possible actions for a ECDSA/EdDSA key: Sign Authenticate
    Current allowed actions: Authenticate
    
       (S) Toggle the sign capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? q
    Please select which elliptic curve you want:
       (1) Curve 25519
       (3) NIST P-256
       (4) NIST P-384
       (5) NIST P-521
       (6) Brainpool P-256
       (7) Brainpool P-384
       (8) Brainpool P-512
       (9) secp256k1
    Your selection? 1
    Please specify how long the key should be valid.
             0 = key does not expire
          <n>  = key expires in n days
          <n>w = key expires in n weeks
          <n>m = key expires in n months
          <n>y = key expires in n years
    Key is valid for? (0) 400
    Key expires at Fri 04 Feb 2022 01:03:14 PM CET
    Is this correct? (y/N) y
    Really create? (y/N) y
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    
    sec  brainpoolP512r1/4A72372BAF48DADE
         created: 2020-12-31  expires: never       usage: C
         trust: ultimate      validity: ultimate
    ssb  cv25519/EA5164ADF741144D
         created: 2020-12-31  expires: 2022-02-04  usage: E
    ssb  ed25519/A9BC0494BD1AE92E
         created: 2020-12-31  expires: 2022-02-04  usage: S
    ssb  ed25519/01E26E0AAE5D9796
         created: 2020-12-31  expires: 2022-02-04  usage: A
    [ultimate] (1). Peter Gerber <peter@arbitrary.ch>
    
    gpg> quit
    Save changes? (y/N) y
    
  3. Check and update preferences

    The public key has information in it about supported algorithms known as preferences in GnuPG. As new more-secure algorithms are supported and some become insecure, it a good idea to check and if needed update the preferences once in a while.

    Get preferences:

    $ gpg --batch --edit-key E6BFD964AA7CEBD360537DDB4A72372BAF48DADE showpref
    Secret key is available.
    
    sec  ed25519/FED9093FB3BCD2D7
         created: 2021-01-02  expires: never       usage: C
         trust: ultimate      validity: ultimate
    [ultimate] (1). Test Test <test@example.com>
    
    [ultimate] (1). Test Test <test@example.com>
         Cipher: AES256, AES192, AES, 3DES
         Digest: SHA512, SHA384, SHA256, SHA224, SHA1
         Compression: ZLIB, BZIP2, ZIP, Uncompressed
         Features: MDC, Keyserver no-modify
    

    List supported algorithms:

    $ gpg --version
    Supported algorithms:
    Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
    Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
            CAMELLIA128, CAMELLIA192, CAMELLIA256
    Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
    Compression: Uncompressed, ZIP, ZLIB, BZIP2
    

    Update preferences:

    $ gpg --edit-key E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    Secret key is available.
    
    sec  ed25519/FED9093FB3BCD2D7
         created: 2021-01-02  expires: never       usage: C
         trust: ultimate      validity: ultimate
    [ultimate] (1). Test Test <test@example.com>
    gpg> setpref AES256 AES192 SHA512 SHA384 Uncompressed ZLIB
    Set preference list to:
         Cipher: AES256, AES192, 3DES
         Digest: SHA512, SHA384, SHA1
         Compression: Uncompressed, ZLIB
         Features: MDC, Keyserver no-modify
    Really update the preferences? (y/N) y
    
    sec  ed25519/FED9093FB3BCD2D7
         created: 2021-01-02  expires: never       usage: C
         trust: ultimate      validity: ultimate
    [ultimate] (1). Test Test <test@example.com>
    
    gpg> q
    Save changes? (y/N) y
    

    List algorithms in preferred order.

    Warning

    Preferences are used to decide what algorithms to use when encrypting a message for you.

    As a result, it’s crucial that …

    1. … all the OpenPGP implementation you use (on your notebook, mobile, etc.) support these algorithms. You may not be able to decrypt some messages otherwise.

    2. … you make sure to keep less-modern algorithms in the preferences for a while. Keep in mind that people sending you a message must support at least one of the ciphers, digest and compression algorithms in your preferences.

  4. Verify Correctness

    Check the keys have the right capabilities:

    $ gpg -K E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    sec#  brainpoolP512r1 2020-12-31 [C]                         <-- [C]ertify
          E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    uid           [ultimate] Peter Gerber <peter@arbitrary.ch>
    ssb   cv25519 2020-12-31 [E] [expires: 2022-02-04]           <-- [E]ncrypt
    ssb   ed25519 2020-12-31 [S] [expires: 2022-02-04]           <-- [S]ign
    ssb   ed25519 2020-12-31 [A] [expires: 2022-02-04]           <-- [A]uthenticate
    
  5. Export Public Key:

    $ gpg -a --export E6BFD964AA7CEBD360537DDB4A72372BAF48DADE >public
    
  6. Export Secret Subkeys:

    $ gpg -a --export-secret-subkeys E6BFD964AA7CEBD360537DDB4A72372BAF48DADE > secret
    

    Only exports the subkey. These keys are intended to be moved to an online machine or smartcard.

  7. Copy Revokation Certificate:

    $ cp .gnupg/openpgp-revocs.d/E6BFD964AA7CEBD360537DDB4A72372BAF48DADE.rev revocation
    

    Backup this certificate in case you need to be able revoke the certificate after loosing the master key, the smartcard or the PIN/password to access it.

  8. Export Secret Keys including Master Key:

    $ gpg -a --export-secret E6BFD964AA7CEBD360537DDB4A72372BAF48DADE > secret_master
    

    Backup this key but this key should not be moved onto an online machine.

Publish Key via WKD

Web Key Directory (WKD) is a simple way to make PGP keys discoverable via a /.well-known/ URL. Current version of GnuPG will attempt to fetch a missing key via WKD automatically should it be missing locally.

See also GnuPG wiki and the specification.

  1. Create policy:

    $ mkdir -p ${WEB_SERVER_ROOT}/.well-known/openpgpkey/
    $ touch ${WEB_SERVER_ROOT}/.well-known/openpgpkey/policy
    

    An empty policy simply indicates support for WKD.

    This needs to be served at https://${DOMAIN}/ where the ${DOMAIN} is the domain of the e-mail address used by the PGP identity.

  2. Create key file

    Get the WKD hash (bold) which is later used as filename:

    $ gpg --with-wkd-hash -k E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    pub   brainpoolP512r1 2020-12-31 [C]
          E6BFD964AA7CEBD360537DDB4A72372BAF48DADE
    uid           [ unknown] Peter Gerber <tor@arbitrary.ch>
                  wbipms79hu4uh1xpsodr369nqi38s8wa@arbitrary.ch
    uid           [ unknown] Peter Gerber <peter@arbitrary.ch>
                  jqbz8wys6j5irhca8bp4qm64b9ii5eyi@arbitrary.ch
    sub   cv25519 2020-12-31 [E] [expires: 2022-02-04]
    sub   ed25519 2020-12-31 [S] [expires: 2022-02-04]
    sub   ed25519 2020-12-31 [A] [expires: 2022-02-04]

    For this example, we’ll ignore the second hash for tor@arbitrary.ch.

    $ mkdir -p ${WEB_SERVER_ROOT}/.well-known/openpgpkey/hu
    $ gpg --export E6BFD964AA7CEBD360537DDB4A72372BAF48DADE \
         >${WEB_SERVER_ROOT}/.well-known/openpgpkey/hu/jqbz8wys6j5irhca8bp4qm64b9ii5eyi
    
  3. Configure web server

    Set the following headers:

    Name

    Value

    Content-Type

    application/octet-stream

    Access-Control-Allow-Origin

    *

    Example Apache2:

    <Location /.well-known/openpgpkey/hu/>
        ForceType application/octet-stream
        Header always set Access-Control-Allow-Origin "*"
    </Location>
    

    Example Nginx:

    location /.well-known/openpgpkey/hu/ {
        default_type        "application/octet-stream";
        add_header          Access-Control-Allow-Origin * always;
    }
    

    Reload the configuration as needed.

  4. Validate the setup

    Try fetching the key:

    wget -S --spider https://arbitrary.ch/.well-known/openpgpkey/hu/jqbz8wys6j5irhca8bp4qm64b9ii5eyi
    

    Use this online validator.

Keep key in TPM

Starting with GnuPG 2.3, it is possible keep keys in a TPM.

See: