[!TIP]
| LETTER | 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 | 加密, 如给文件加密, 给邮件加密 |
generate SCA gpg key
[!TIP]
- encryption method:
- Sign:
ed25519- Encrypt:
cv25519- manual steps:
$ gpg --full-generate-key
- select
(9) ECC (sign and encrypt)- select
(1) Curve 25519- select
0 = key does not expire
$ gpg --batch --passphrase '********' --pinentry-mode loopback --generate-key <<EOF
Key-Type: EDDSA
Key-Curve: ed25519
Subkey-Type: ECDH
Subkey-Curve: cv25519
Name-Real: marslo
Name-Email: marslo@domain.com
Expire-Date: 0
%commit
EOF
gpg: revocation certificate stored as '/Users/marslo/.gnupg/openpgp-revocs.d/8**********************56**************D.rev'
$ gpg --list-secret-keys --keyid-format=long
[keyboxd]
---------
sec ed25519/6**************D 2026-02-12 [SCA]
8**********************56**************D
uid [ultimate] marslo <marslo@domain.com>
ssb cv25519/4**************D 2026-02-12 [E]
backup and restore gpg key
backup
$ KEY_ID=6**************D
# gpg keys
$ gpg --armor --export ${KEY_ID} > ${KEY_ID}-public.asc
$ gpg --armor --export-secret-keys ${KEY_ID} > ${KEY_ID}-secret.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
restore
# gpg keys
$ gpg --import ./*.asc
# trust database
$ gpg --import-ownertrust < gpg-ownertrust.txt
ssh support
generate ssh public key
$ gpg --export-ssh-key 6**************D
# or with comment
$ COMMENT='marslo@gpg'
$ echo "$(gpg --export-ssh-key ${KEY_ID} | cut -d' ' -f1,2) ${COMMENT}" > ~/.ssh/${COMMENT}.pub
start gpg-agent
$ cat ~/.bash_profile
export GPG_TTY=$(tty)
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent
$ cat ~/.ssh/config
HOST *
IdentitiesOnly yes
# using public key as IdentityFile, ssh will compare the fingerprint with ssh agent
IdentityFile ~/.ssh/marslo@gpg.pub
verify fingerprint
# check from public key $ ssh-keygen -f ~/.ssh/marslo@gpg.pub -l 256 SHA256:V6nCfXgETxew3yUk7ids/pL7XH8BZjm4BZlL9hPrk3w marslo@gpg (ED25519) # check from ssh agent $ ssh-add -l -E sha256 256 SHA256:V6nCfXgETxew3yUk7ids/pL7XH8BZjm4BZlL9hPrk3w (none) (ED25519)
authorize public key
$ cat ~/.ssh/${COMMENT}.pub |
ssh <REMOET_SERVER> "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
# or
$ ssh-copy-id -i ~/.ssh/${COMMENT}.pub <REMOET_SERVER>
# verify
$ ssh <REMOET_SERVER>
git support
set config globally
$ git config --global user.signingkey 6**************D
# enable signature automatically
$ git config --global commit.gpgsign true
# for macOS
$ git config --global gpg.program $(which gpg)
setup for multiple accounts and keys
$ cat ~/.gitconfig.d/person
[user]
name = marslo
email = marslo@person.com
signingkey = 6**************D
[commit]
gpgsign = true
[tag]
gpgsign = true
$ cat ~/.gitconfig.d/work
[user]
name = marslo
email = marslo@work.com
signingkey = 7**************3
[commit]
gpgsign = true
[tag]
gpgsign = true
$ cat ~/.gitconfig
[includeIf "gitdir/i:~/git/person/**"]
path = ~/.gitconfig.d/person
[includeIf "gitdir/i:~/git/work/**"]
path = ~/.gitconfig.d/work
add gpg key to github
get gpg public key
# person $ gpg --armor --export 6**************D | pbcopy # work $ gpg --armor --export 7**************3 | pbcopyadd in github
- go to
Settings->SSH and GPG keys->New GPG key - paste the gpg public key and save
- go to
verify
[!TIP|label:to show signature in
git logandgit show]$ git config --global log.showSignature true
# .. git commit -am '...'
$ git show --show-signature [--no-patch]
shows in
git logwith[%G?]%C[alias] pl = !git -c log.decorate=short --no-pager log --color --graph --abbrev-commit --date=relative --max-count=3 --pretty=tformat:"'%C(#678963)%h%C(reset) -%C(yellow)%d%C(reset) %s %C(green)(%cr) %C(italic blue)<%an>%C(reset) %C(italic #6971a3)[%G?]%C(reset)'"# example output: [G] -> with signature, [N] -> no signature $ git pl * 178ac121 - (HEAD -> marslo, origin/marslo) feat(conventional commits): add details for git conventional commits (8 days ago) <marslo> [G] * 8f1d4772 - fix(brew,cleanup): add the ultimate fix solution for brew environment (2 weeks ago) <marslo> [N] * f1aafe99 - feat(jf,fossa): introduce fossa CLI; add example for jf cli (2 weeks ago) <marslo> [N]
1.2.11.3.1 -- git pl with gpg sign
github gpg key management
[!NOTE|label:references:]
gpg: Can't check signature: No public key:$ git show -s HEAD --show-signature commit 7eb9b4f124894a8ee7be153d763373423e1c9bd3 (origin/stable, origin/HEAD) gpg: Signature made Fri Mar 13 12:11:32 2026 PDT gpg: using RSA key B5690EEEBB952194 gpg: Can't check signature: No public key Author: John Doe <john.doe@mail.com> Date: 2026-03-13 12:11:32 -0700 Friday- web-flow.gpg
- keyserver.ubuntu.com
- 0xB5690EEEBB952194
download
$ for k in $(gh api "users/web-flow/gpg_keys" --jq '.[]|@base64'); do
id="$(echo ${k} | jq -Rr '@base64d|fromjson|.key_id')"
raw=$(echo ${k} | jq -Rr '@base64d|fromjson|.raw_key')
echo "${raw}" > "github-${id}.gpg"
done
$ ls
github-4AEE18F83AFDEB23.gpg github-B5690EEEBB952194.gpg
import
# import `B5690EEEBB952194`
# using curl
$ curl -s https://api.github.com/users/web-flow/gpg_keys |
jq -r '.[] | select(.key_id == "B5690EEEBB952194") | .raw_key' |
gpg --import
# using keyserver, with port 11371
$ gpg --keyserver pgp.mit.edu --recv-keys B5690EEEBB952194
gpg: key B5690EEEBB952194: public key "GitHub <noreply@github.com>" imported
gpg: Total number processed: 1
gpg: imported: 1
# or with proxy + port 80
$ gpg --keyserver hkp://keyserver.ubuntu.com:80 \
--keyserver-options http-proxy=http://proxy.domain.com:8080 \
--recv-keys B5690EEEBB952194
# with port 443
$ gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys B5690EEEBB952194
gpg: key B5690EEEBB952194: "GitHub <noreply@github.com>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1
| PORT | PROTOCOL | DESCRIPTION | EXAMPLE |
|---|---|---|---|
11371 |
hkp | default port for keyserver | keyserver.ubuntu.com |
443 |
hkps | for https proxy | hkps://keyserver.ubuntu.com |
80 |
hkp | for http proxy | hkp://keyserver.ubuntu.com:80 |
trust
$ gpg --list-keys 968479A1AFF927E37D1A566BB5690EEEBB952194
pub rsa4096 2024-01-16 [SC]
968479A1AFF927E37D1A566BB5690EEEBB952194
uid [ unknown] GitHub <noreply@github.com>
$ echo "968479A1AFF927E37D1A566BB5690EEEBB952194:6:" | gpg --import-ownertrust
gpg: setting ownertrust to 6
$ gpg --list-keys 968479A1AFF927E37D1A566BB5690EEEBB952194
pub rsa4096 2024-01-16 [SC]
968479A1AFF927E37D1A566BB5690EEEBB952194
uid [ultimate] GitHub <noreply@github.com>
tips
view the exported private key structure
$ gpg --list-packets <(gpg --export-secret-keys 6C549DA3FA02DB3D)