[!NOTE|label:references:]

basic knowledge

[!NOTE|label:references:]

  • to show --dump-options: gpg --dump-options
FLAG MEANING FLAG CONSTANT COMMENTS
[C] Certification 0x01 PUBKEY_USAGE_CERT 认证其他秘钥/给其他证书签名
[S] Signing 0x02 PUBKEY_USAGE_SIG 签名,如给文件添加数字签名, 给 git commit 签名
[A] Authenticate 0x20 PUBKEY_USAGE_AUTH 身份验证, 如 ssh 登录
[E] Encryption 0x04 or 0x08 PUBKEY_USAGE_ENC 加密, 如给文件加密, 给邮件加密
ABBREVIATION NAME
pub public key
sec secret key
sub public subkey
ssb secret subkey
fpr fingerprint
TYPE IDENTIFIER PURPOSE
master key sec key management, sign subkeys, encrypt subkeys
signing subkey ssb [S] git commit signing
encryption subkey ssb [E] file encryption and decrypt
gpg list packages
$ gpg --list-packets test.sig.txt
# off=0 ctb=a3 tag=8 hlen=1 plen=0 indeterminate
:compressed packet: algo=1
# off=2 ctb=90 tag=4 hlen=2 plen=13
:onepass_sig packet: keyid FFB1BEE8152BF644
  version 3, sigclass 0x00, digest 10, pubkey 22, last=1
# off=17 ctb=ac tag=11 hlen=2 plen=19
:literal data packet:
  mode b (62), created 1772105311, name="test.txt",
  raw data: 5 bytes
# off=38 ctb=88 tag=2 hlen=2 plen=117
:signature packet: algo 22, keyid FFB1BEE8152BF644                                  # secret key id
  version 4, created 1772105311, md5len 0, sigclass 0x00
  digest algo 10, begin of digest 4c bd
  hashed subpkt 33 len 21 (issuer fpr v4 145709648350D6FF157BAF20FFB1BEE8152BF644)  # fingerprint
  hashed subpkt 2 len 4 (sig created 2026-02-26)                                    # timestamp
  subpkt 16 len 8 (issuer key ID FFB1BEE8152BF644)                                  # secret key id
  data: [251 bits]
  data: [253 bits]

create new key

[!NOTE|label:references:]

$ gpg --full-generate-key
  • or
    $ gpg --batch --gen-key <<EOF
    %no-protection
    Key-Type:1
    Key-Length:2048
    Subkey-Type:1
    Subkey-Length:2048
    Name-Real: <John Doe>
    Name-Email: <john.doe@domain.com>
    Expire-Date:0
    EOF
    

create new subkey

[!NOTE|label:key type]

  • (10) ECC (sign only) : for git commit signing - [S] or [A]
  • (12) ECC (encrypt only) : for file encryption ( i.e.: pass tool ) - [E]

non-interactive mode

[!TIP] must with fingerprint of the primary key

# [S]
$ gpg --quick-add-key 7C0BF765E462F5A6C4A45FAF335A865859218D02 ed25519 sign 0

# [S]
$ gpg --quick-add-key 7C0BF765E462F5A6C4A45FAF335A865859218D02 ed25519 auth 0

# [SA]
$ gpg --quick-add-key 7C0BF765E462F5A6C4A45FAF335A865859218D02 ed25519 sign,auth 0

signing subkey

[!NOTE|label:before new subkey added]

$ gpg --list-keys --keyid-format long 335A865859218D02
pub   ed25519/335A865859218D02 2026-02-26 [SCA]
      7C0BF765E462F5A6C4A45FAF335A865859218D02
uid                 [ultimate] marslo <marslo@domain.com>
sub   cv25519/A03D9828C2C5B8DC 2026-02-26 [E]
# interactive mode - [S]
$ gpg --edit-key 335A865859218D02 addkey save
gpg> addkey
✓ (10) ECC (sign only)(1) Curve 255190
✓ Y
✓ Y
gpg> save

# result
$ gpg --list-keys --keyid-format long 335A865859218D02
pub   ed25519/335A865859218D02 2026-02-26 [SCA]
      7C0BF765E462F5A6C4A45FAF335A865859218D02
uid                 [ultimate] marslo <marslo@domain.com>
sub   cv25519/A03D9828C2C5B8DC 2026-02-26 [E]
sub   ed25519/19298D1B0CE81049 2026-02-26 [S]        # new [S] subkey

new auth subkey

[!TIP|label:select sign or/and auth capability]

Possible actions for this ECC key: Sign Authenticate
Current allowed actions: Sign

   (S) Toggle the sign capability
   (A) Toggle the authenticate capability
   (Q) Finished
  • OPTIONS:
    • (S): disable sign capability, result: Current allowed actions: Authenticate
    • (A): enable authenticate capability, result: Current allowed actions: Sign Authenticate
# interactive mode - [SA]
$ gpg --expert --edit-key 335A865859218D02 addkey
✓ (11) ECC (set your own capabilities)(A) Toggle the authenticate capability  # insert S to disable sign capability; insert A to enable authenticate capability
# result: Current allowed actions: Sign Authenticate(Q) Finished
✓ (1) Curve 255190 = key does not expire
✓ Y
✓ Y
# check
$ gpg --list-keys --keyid-format long 335A865859218D02
pub   ed25519/335A865859218D02 2026-02-26 [SCA]
      7C0BF765E462F5A6C4A45FAF335A865859218D02
uid                 [ultimate] marslo <marslo@domain.com>
sub   cv25519/A03D9828C2C5B8DC 2026-02-26 [E]
sub   ed25519/19298D1B0CE81049 2026-02-26 [S]
sub   ed25519/22026B709B13C5C6 2026-02-26 [A]        # new [A] subkey

remove

# with index of the subkey
$ gpg --edit-key 335A865859218D02 'key 2' delkey save
✓ Y
# or
$ printf "key 2\ndelkey\ny\nsave\n" |
  gpg --command-fd 0 --status-fd 1 --edit-key 335A865859218D02

# with fingerprint of the subkey
$ printf "key 60FB7DC32A27F96E\ndelkey\ny\nsave\n" |
  gpg --command-fd 0 --status-fd 1 --edit-key 335A865859218D02

list keys

secret keys

$ gpg --list-secret-keys --keyid-format=long
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
[keyboxd]
---------
sec   ed25519/5**************3 2024-05-08 [SC]
      00D2F41050BF7D9BE6B275455**************3
uid                 [ultimate] marslo <marslo@domain.com>
ssb   cv25519/188C36434D6B9F66 2024-05-08 [E]

$ gpg --list-secret-keys --keyid-format=long --with-subkey-fingerprint

public keys

$ gpg --list-public-keys --keyid-format=long
[keyboxd]
---------
pub   ed25519/5**************4 2024-05-08 [SC]
      6AADCD68E268DEF623C4DD7E5**************4
uid                 [ultimate] marslo <marslo@domain.com>
sub   cv25519/F065036D0FF76ABA 2024-05-08 [E]

$ gpg --list-public-keys --keyid-format=long --with-subkey-fingerprint

list key id

$ gpg --list-keys --with-colons |
      awk -F: '$1 == "pub" && ($2 == "e" || $2 == "r" || $2 == "u") { print $5 }'
  • with fingerprint

    $ gpg --list-secret-keys --with-colons --fingerprint
    sec:u:255:22:5**************4:1715138996:::u:::scESC:::+::ed25519:::0:
    fpr:::::::::6AADCD68E268DEF623C4DD7E5**************4:
    grp:::::::::DA2F273B9FCDBCE44E8F5B1590CC29F774C557A5:
    uid:u::::1715138996::689D1C164C7C46F315D0FF60C5CDE6E509C6D853::marslo <marslo@domain.com>::::::::::0:
    ssb:u:255:18:F065036D0FF76ABA:1715138996::::::e:::+::cv25519::
    fpr:::::::::B6550514914F4E14976755BBF065036D0FF76ABA:
    grp:::::::::C55CD6EE8B06EC939090352069AB9D37CFA0C7FA:
    
    # list fingerprint only
    $ gpg --list-keys --with-colons | awk -F: '$1 == "fpr" { print $10 }'
    6AADCD68E268DEF623C4DD7E5**************4
    B6550514914F4E14976755BBF065036D0FF76ABA
    
    # or
    $ gpg --list-secret-keys --with-colons --fingerprint | sed -n 's/^fpr:::::::::\([[:alnum:]]\+\):/\1/p'
    6AADCD68E268DEF623C4DD7E5**************4
    B6550514914F4E14976755BBF065036D0FF76ABA
    

list public key and account

$ gpg --list-keys --with-colons |
  awk -F: '
    $1 == "pub" {
      key=""
      for ( i=1;i<=NF;i++ ) if ( $i ~ /[A-F0-9]{16}/ ) key=$i
    }
    $1 == "uid" {
      match( $10, /<([^>]+)>/, m )
      if ( key && m[1] ) print key, m[1]
    }'
91B7E555C9B67240 marslo@work.com
335A865859218D02 marslo@domain.com

remove keys

  • remove all keys

    $ gpg --yes --delete-secret-and-public-key "marslo"
    gpg (GnuPG) 2.4.5; Copyright (C) 2024 g10 Code GmbH
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    sec  ed25519/1**************4 2024-05-08 marslo (marslo) <marslo@domain.com>
    
    Delete this key from the keyring? (y/N) y
    This is a secret key! - really delete? (y/N) y
    
    pub  ed25519/1**************4 2024-05-08 marslo (marslo) <marslo@domain.com>
    Delete this key from the keyring? (y/N) y
    
  • or via --batch

    $ gpg --list-keys --with-colons |
          awk -F: '$1 == "pub" && ($2 == "e" || $2 == "r" || $2 == "u") { print $5 }' |
          xargs gpg --batch --yes --delete-secret-and-public-key
    
  • or via fingerprint

    $ gpg --fingerprint --with-colons ${KEY_ID} |
          grep "^fpr" |
          sed -n 's/^fpr:::::::::\([[:alnum:]]\+\):/\1/p' |
          xargs gpg --batch --delete-secret-keys
    

backup and restore keys

[!NOTE|label:references:]

backup and export

backup

  • gpg keys

    $ gpg --output <KEY_ID>.sec.gpg --armor --export-secret-keys --export-options export-backup <KEY_ID>
    # or
    $ gpg --output <KEY_ID>.pub.gpg --armor --export --export-options export-backup <KEY_ID>
    
  • ssh keys

    # -- gpg keys --
    $ gpg --armor --export ${KEY_ID} > ${KEY_ID}-pub.asc
    $ gpg --armor --export-secret-keys ${KEY_ID} > ${KEY_ID}-sec.asc
    
    # -- ssh public key --
    $ COMMENT='marslo@gpg'
    $ echo "$(gpg --export-ssh-key ${KEY_ID} | cut -d' ' -f1,2) ${COMMENT}" > ~/.ssh/"${COMMENT}".pub
    
    # -- trust database --
    $ gpg --export-ownertrust > gpg-ownertrust.txt
    

export

  • export public key

    # public key
    $ gpg --output public.gpg --armor --export <KEY_ID>
    # -- check content --
    $ gpg --armor --export <KEY_ID>
    
    # secret key
    $ gpg --output private.gpg --armor --export-secret-key <KEY_ID>
    # - or -
    $ gpg -o ~/private.asc --export-secret-key <KEY_ID>
    # -- check content --
    $ gpg --armor --export-secret-keys <KEY_ID>
    
  • export and ssh

    $ gpg --export-secret-key <KEY_ID> | ssh othermachine gpg --import
    
  • more

    $ gpg --output public.gpg --export <KEY_ID> && \
      gpg --output - --export-secret-key <KEY_ID> |
          cat public.gpg - |
          gpg --armor --output keys.asc --symmetric --cipher-algo AES256
    

restore and import

[!NOTE|label:references:]

restore

  • ssh keys

    # gpg keys
    $ gpg --import ./*.asc
    
    # trust database
    $ gpg --import-ownertrust < gpg-ownertrust.txt
    
  • import

    # private key
    $ gpg --import private.gpg
    
    # public key
    $ gpg --import public.gpg
    

trust key

TRUST LEVEL DESCRIPTION
1 Don't know
2 Do NOT trust
3 Marginally trust
4 Fully trust
5 / 6 Ultimately trust
# i.e.: the 2nd key
$ PUB_KEY_ID=$(gpg --list-keys --with-colons | awk -F: '/^pub:/ {getline; print $10}' | sed -n '2p')
$ echo "${PUB_KEY_ID}:6:" | gpg --import-ownertrust
  • interactive mode

    $ gpg --edit-key 5**************4 trust quit
      1 = I don't know or won't say
      2 = I do NOT trust
      3 = I trust marginally
      4 = I trust fully
      5 = I trust ultimately
      m = back to the main menu
    
    gpg> Your decision? 5
    gpg> Do you really want to set this key to ultimate trust? (y/N) y
    
    # check key again
    $ gpg --list-keys
    gpg: checking the trustdb
    gpg: marginals needed: 3  completes needed: 1  trust model: pgp
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    /home/marslo/.gnupg/pubring.kbx
    -------------------------------
    pub   ed25519 2024-05-08 [SC]
          6AADCD68E268DEF623C4DD7E5**************4
    uid           [ultimate] marslo <marslo@domain.com>
    sub   cv25519 2024-05-08 [E]
    

recover from backup keys

$ gpg --import-options restore --import backupkeys.gpg

usage

[!NOTE|label:references:]

sign file

[!TIP|label:encrypt string:]

$ bash -c 'echo "test" | gpg --armor --sign --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02'
-----BEGIN PGP MESSAGE-----

owGbwMvMwCX2f+O+F6La31wYT3MnMWQuUH9SklpcwtVRysIgxsUgK6bIIhLOmdIc
cO2/aPV6BZhiViaQSgYuTgGYSO9xRoaT+VctFpu/XOQzm0vuJ0/dyugdq2rbZ767
a/bgx5HbjP2djAyPn2UvOXtKu6Fo+1yO59uOen3k+rDG8G3T6TmGhadF7Bx4AA==
=RwCr
-----END PGP MESSAGE-----

check content with gpg info

$ gpg --list-packets test.sig.txt
$ echo 'test' > test.txt

# without `--armor` option, the output file is binary format
$ gpg --sign --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02 --output test.sig.txt test.txt
$ file test.sig.txt
test.sig.txt: data
$ cat test.sig.txt | od -c | head -1
0000000   � 001 233   �   �   �   �   %   � 177   �   � 027   �   �   �

# with `--armor` option, the output file is ASCII format
$ gpg --armor --sign --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02 --output test.sig.txt test.txt
$ file test.sig.txt
test.sig.txt: PGP message Compressed Data (old)
$ cat test.sig.txt | od -c | head -2
0000000   -   -   -   -   -   B   E   G   I   N       P   G   P       M
0000020   E   S   S   A   G   E   -   -   -   -   -  \n  \n   o   w   G

sign file with clearsign

[!TIP]

  • --clear-sign / --clearsign option is used to create a cleartext signature
$ echo 'test' > test.txt

# output - `test.txt.asc` (by default)
$ gpg --local-user FFB1BEE8152BF644 --clear-sign test.txt
# output - `test.txt.sig` ( customized )
$ gpg --local-user FFB1BEE8152BF644 --output test.txt.sig --clearsign test.txt

$ ls -Altrh test.txt*
-rw-r--r-- 1 marslo staff   5 Feb 26 02:46 test.txt
-rw-r--r-- 1 marslo staff 282 Feb 26 03:13 test.txt.asc

$ cat test.txt.asc
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

test
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQQUVwlkg1DW/xV7ryD/sb7oFSv2RAUCaaAqwQAKCRD/sb7oFSv2
RAq5AQCKKpDSn5SG7gcq9/dQegTjALJXYX7HfpZo5fMUF76j5wD/VlRgNggILp09
Ystg6x4mulroIe/i04jqp3Hpwkuu7Q4=
=/B9O
-----END PGP SIGNATURE-----

verify

$ gpg --verify --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02 test.sig.txt
gpg: Signature made Thu Feb 26 03:06:21 2026 PST
gpg:                using EDDSA key 145709648350D6FF157BAF20FFB1BEE8152BF644
gpg: Good signature from "marslo <marslo@domain.com>" [ultimate]

# with details
$ gpg --status-fd=1 --verify --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02 test.sig.txt
[GNUPG:] NEWSIG
gpg: Signature made Thu Feb 26 03:28:31 2026 PST
gpg:                using EDDSA key 145709648350D6FF157BAF20FFB1BEE8152BF644
[GNUPG:] KEY_CONSIDERED 7C0BF765E462F5A6C4A45FAF335A865859218D02 0
[GNUPG:] SIG_ID 0LEJonm9f6A4Hyv7rQXOyQsr1tQ 2026-02-26 1772105311
[GNUPG:] GOODSIG FFB1BEE8152BF644 marslo <marslo@domain.com>
gpg: Good signature from "marslo <marslo@domain.com>" [ultimate]
[GNUPG:] VALIDSIG 145709648350D6FF157BAF20FFB1BEE8152BF644 2026-02-26 1772105311 0 4 0 22 10 00 7C0BF765E462F5A6C4A45FAF335A865859218D02
[GNUPG:] KEY_CONSIDERED 7C0BF765E462F5A6C4A45FAF335A865859218D02 0
[GNUPG:] TRUST_ULTIMATE 0 pgp

decrypt file

$ gpg --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02 --output test.out.txt --decrypt test.sig.txt
gpg: Signature made Thu Feb 26 03:28:31 2026 PST
gpg:                using EDDSA key 145709648350D6FF157BAF20FFB1BEE8152BF644
gpg: Good signature from "marslo <marslo@domain.com>" [ultimate]

$ md5sum test.out.txt test.txt
d8e8fca2dc0f896fd7cb4cb0031ba249  test.out.txt
d8e8fca2dc0f896fd7cb4cb0031ba249  test.txt

sign and encrypt file

[!NOTE|label:references:]

  • local user ( for sign )

    $ gpg --list-keys --keyid-format long 7C0BF765E462F5A6C4A45FAF335A865859218D02
    pub   ed25519/335A865859218D02 2026-02-26 [SCA]
         7C0BF765E462F5A6C4A45FAF335A865859218D02
    uid                 [ultimate] marslo <marslo@domain.com>
    sub   cv25519/A03D9828C2C5B8DC 2026-02-26 [E]
    sub   ed25519/FFB1BEE8152BF644 2026-02-26 [SA]
    
  • recipient ( for encrypt )

    $ gpg --list-keys --keyid-format long  302C7795D25A5749FAA7212791B7E555C9B67240
    pub   ed25519/91B7E555C9B67240 2026-02-26 [SCA]
          302C7795D25A5749FAA7212791B7E555C9B67240
    uid                 [ultimate] marslo <marslo@work.com>
    sub   cv25519/634119494722F716 2026-02-26 [E]
    
  • sign and encrypt file

    $ echo 'test' > test.txt
    
    # sign and encrypt
    $ gpg --armor --sign --encrypt \
          --local-user 7C0BF765E462F5A6C4A45FAF335A865859218D02 \
          --recipient 302C7795D25A5749FAA7212791B7E555C9B67240 \
          --output test.enc.txt \
          test.txt
    
    # or with LONG_ID
    $ gpg --armor --sign --encrypt \
          --local-user FFB1BEE8152BF644 \
          --recipient 91B7E555C9B67240 \
          --output test.enc.txt \
          test.txt
    
    $ cat test.enc.txt
    -----BEGIN PGP MESSAGE-----
    
    hF4DY0EZSUci9xYSAQdA1W9caMvcD88Lf3tiTekuIvOuS8evHPPnfVLqxprr+www
    gCoZyUJRaQqqABqopJz3eWekC0bNidjLaprj8urmugweuyUVlgUMLzz4tBc4/wPu
    1MANAQkCENPL2MlAuISRKfH3Q/P5EdL/2tVcpLWnN+GnuxwQJd/IKPPKtVdpXjh2
    tNylc2kzZQx3PGdpzrGm8sDublWSO/xu/MyiCXt4UvqdRoHZt+l5GbGhCr60IvkR
    Cms4O/8CuKCUFL1iu3m0rrwoUWP7SHynaHb1rmCi/t9QZhv8rTq21zC0O1+s4pjz
    hWxmAi/8fR90n/jN8XSMnjva/W5/85eISfLNxHxjIEeDYGghy5TX9Gv5CxxYvNvI
    7bASbvqs3odqbxvDPfrqiQ==
    =8FtL
    -----END PGP MESSAGE-----
    
  • decrypt and verify file

    $ gpg --local-user 91B7E555C9B67240 --output test.out.txt --decrypt test.enc.txt
    gpg: encrypted with cv25519 key, ID 634119494722F716, created 2026-02-26
          "marslo <marslo@work.com>"
    gpg: Signature made Thu Feb 26 02:49:18 2026 PST
    gpg:                using EDDSA key 145709648350D6FF157BAF20FFB1BEE8152BF644
    gpg: Good signature from "marslo <marslo@domain.com>" [ultimate]
    
    $ cat test.out.txt
    test
    
    $ sha256sum test.out.txt test.txt
    f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2  test.out.txt
    f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2  test.txt
    

git ssh commit signing

[!NOTE|label:references:]

Copyright © marslo 2020-2025 all right reserved,powered by GitbookLast Modified: 2026-02-26 04:14:24

results matching ""

    No results matching ""