gpg 密钥导入、导出 #
导入、导出 gpg 公钥/私钥 #
基本用法 #
bash
# 导出 gpg 私钥:(需要其口令,并且导出的数据未被加密,注意妥善保存)
# -a, --armor 参数表示输出文本格式而非二进制格式
# -o, --output file 用于指定输出文件路径
# name 用于指定导出哪个用户标识的私钥(包括与之相关的所有主子密钥)
# name 也可以输入 keyid(如果 keyid 后跟感叹号则表示导出唯一密钥而非与之相关的所有主子密钥)
gpg [-a] [-o file] --export-secret-keys name
# 导出 gpg 公钥:
gpg [-a] [-o file] --export name
# 导出 ssh 公钥:(后跟感叹号表示导出唯一密钥而非与之相关的所有主子密钥)
gpg [-o file] --export-ssh-key keyid!
# 导入 gpg 私钥或公钥:(若导入私钥则会要求输入口令对其进行加密)
gpg --import [file...]
最佳实践 #
Important
由于 gpg --export-secret-keys
命令导出的 gpg 私钥数据未被加密,因此推荐对其进行加密后再保存到磁盘。公钥无需加密保存。
bash
# 导出 gpg 私钥:(导出 gpg 私钥数据,并对其进行对称加密,会要求输入加密用的口令)
# (这里的 s2k 相关参数是为了覆盖默认的加密参数,是可选参数)
# (需要注意在 Windows 中 PowerShell 管道可能会有些问题,最好用 CMD 跑这些命令)
gpg --export-secret-keys name | gpg -c --s2k-cipher-algo AES256 --s2k-digest-algo SHA512 --s2k-count 65536 > ./my_sec_keys_encryped.gpg
# 导入 gpg 私钥:(解密后再进行导入操作,解密步骤会要求输入口令)
gpg -d ./my_sec_keys_encryped.gpg | gpg --import
gpg 子密钥导出为 ssh 密钥对 #
目的:将 gpg 主密钥下的一个功能为 A(认证)的子密钥导出为 ssh 密钥对。
方案A:pgp2ssh(推荐) #
Warning
这个方案本人只在 Linux/WSL 环境中测试,Windows 环境下未测试。
这个方案可导出 RSA 或 Ed25519 类型的 gpg 密钥。
项目地址:https://github.com/pinpox/pgp2ssh
bash
# Step 0: 编译得到 pgp2ssh 可执行文件(需要 go 环境)
git clone https://github.com/pinpox/pgp2ssh
cd ./pgp2ssh
go build
# Step 1: 导出 gpg 私钥到临时文件(pgp2ssh 只支持文本格式,不支持二进制格式)
gpg -a --export-secret-keys keyid! > ./tmp_sec_keys.asc
# Step 2: 执行 pgp2ssh(按照提示进行操作即可)
./pgp2ssh
# 具体操作如下:
2025/07/20 06:30:46 Enter path to private PGP key (default: ./priv.asc):
./tmp_sec_keys.asc ### 输入密钥文件地址 ###
2025/07/20 06:31:48 Keys:
2025/07/20 06:31:48 [0] 05DB0F94ACFB538A (primary)
2025/07/20 06:31:48 [1] 7DFA4A81153E9B7A (subkey)
2025/07/20 06:31:48 Choose key by index (default: 0):
1 ### 选择想要导出的1号子密钥(keyid最后8位对应上) ###
2025/07/20 06:32:10 Continuing with key [1] 7DFA4A81153E9B7A
2025/07/20 06:32:10 Please enter passphrase to decrypt PGP key:
2025/07/20 06:32:16 private key type: *eddsa.PrivateKey
2025/07/20 06:32:16 public key type: eddsa.PublicKey
2025/07/20 06:32:16 public SSH key: ### 下面是 ssh 公钥内容 ###
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBmsglrqNo5jUTtejRUQ7lFV8+g9vDftQhDKwhBRqi36
2025/07/20 06:32:16 Private SSH key: ### 下面是 ssh 私钥内容 ###
-----BEGIN OPENSSH PRIVATE KEY-----
......
-----END OPENSSH PRIVATE KEY-----
### 至此 ssh 密钥对导出结束,将以上内容分别复制到一个公钥文件和一个私钥文件当中即可,换行用 LF 换行符。 ###
# Step 3: 删除临时文件
rm -f ./tmp_sec_keys.asc
# Step 4: 设置 ssh 私钥文件的备注和密码
ssh-keygen -c -C 'remark' -f my_ssh_key
ssh-keygen -p -f ./my_ssh_key
# Step 5: 导出 ssh 公钥文件
ssh-keygen -y -f ./my_ssh_key > ./my_ssh_key.pub
方案B:monkeysphere #
Warning
这个方案只支持导出 RSA 类型的 gpg 私钥或公钥。不支持 Windows 环境。
bash
# Step 0: 安装 monkeysphere(用于转换密钥格式,包含常用命令 openpgp2ssh, pem2openpgp 等)
# CentOS
yum install monkeysphere
# Ubuntu
apt install monkeysphere
# Step 1: 导出 ssh 私钥(后跟感叹号表示导出唯一密钥而非与之相关的所有主子密钥)(openpgp2ssh 后面的 keyid 可以省略)
gpg --export-secret-keys keyid! | openpgp2ssh [keyid] > ./my_ssh_key
# Step 2: 设置 ssh 私钥文件的备注和密码
ssh-keygen -c -C 'remark' -f ./my_ssh_key
ssh-keygen -p -f ./my_ssh_key
# Step 3: 导出 ssh 公钥文件
ssh-keygen -y -f ./my_ssh_key > ./my_ssh_key.pub
ssh 私钥导入到 gpg 密钥环 #
目的:将一个 ssh 私钥文件导入到 gpg 中,成为主密钥下的一个子密钥,并拥有功能 A(认证)。
步骤一:转换为 gpg 私钥 #
方案A:ssh-add(推荐) #
利用 gpg-agent 模拟的 ssh-agent 服务来管理 ssh 私钥,利用 ssh-add 命令将 ssh 私钥导入成为 gpg 私钥(不在密钥环中,没有对应公钥,既不是一个主密钥,也不是一个子密钥,无法用 gpg -k/-K 等命令来查看)。该私钥文件存放于 {GPG_HOME}/private-keys-v1.d/
目录中,该私钥文件删除与否不会对其他密钥产生任何影响。
{GPG_HOME}
在 Linux 中位于 $HOME/.gnupg
,在 Windows 中位于 %HOME%/AppData/Roaming/gnupg
。
bash
# Step 0: 配置 gpg-agent 服务,在 {GPG_HOME}/gpg-agent.conf 配置文件中添加以下内容:
enable-ssh-support
# 对于 Windows 的 Gpg4win 版本需要额外添加以下三行:
enable-putty-support
enable-win32-openssh-support
use-standard-socket
# Step 1: 启动 gpg-agent 服务
gpg-connect-agent /bye
# Step 2: 将 ssh 私钥导入成为 gpg 私钥(不在密钥环中,没有对应公钥,既不是一个主密钥,也不是一个子密钥)
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
ssh-add ./my_ssh_key
# 执行完上面的命令后,配置文件 {GPG_HOME}/sshcontrol 会自动添加如下配置:
# Ed25519 key added on: 2025-07-19 17:58:33
# Fingerprints: MD5:af:1c:1e:5f:fb:46:9a:e5:4a:31:0f:19:40:f1:5e:a3
# SHA256:lxb98XbOQIBjjTe703FWaKLFqj25w9Cur88qvGkMILk
A6E4D0712A1A5487B902FEBF7CC7215590A6F62F 0
### 上面这个大写16进制字符串就是导入的密钥的 keygrip,后面步骤二(主密钥添加子密钥)要用到。 ###
### 配置文件 sshcontrol 配置的是 gpg-agent 用于 ssh 认证的私钥列表。 ###
方案B:monkeysphere #
Warning
这个方案只支持转换 RSA 类型的 ssh 私钥,不支持 Ed25519 等类型。
bash
# Step 0: 安装 monkeysphere(用于转换密钥格式,包含常用命令 openpgp2ssh, pem2openpgp 等)
# CentOS
yum install monkeysphere
# Ubuntu
apt install monkeysphere
# Step 1: 复制一个临时 ssh 私钥文件(因为后面可能要对 ssh 密钥文件做修改,因此不建议直接操作原密钥文件)
cp ./my_ssh_key ./tmp_ssh_key
# Step 2: 若 ssh 私钥已加密,或是 OpenSSH 格式,则需要转换为未加密的 PEM 格式。
# (OpenSSH格式:-----BEGIN OPENSSH PRIVATE KEY-----)
# (PEM格式:-----BEGIN RSA PRIVATE KEY-----)
ssh-keygen -p -m PEM -f ./tmp_ssh_key
# Step 3: 将 PEM 格式的 ssh 私钥导入为独立的 gpg 主密钥(tmp_name 为该 gpg 主密钥的用户标识)
# 可选环境变量:
# PEM2OPENPGP_TIMESTAMP 自签名和密钥创建时间。UNIX时间戳(秒),默认当前时间
# PEM2OPENPGP_KEY_TIMESTAMP 仅密钥创建时间。UNIX时间戳(秒)
# PEM2OPENPGP_USAGE_FLAGS 逗号分隔的用途。可选项有 certify,sign,encrypt,authenticate,split,shared。默认 certify
# PEM2OPENPGP_EXPIRATION 过期时长(秒)。默认不设置
# PEM2OPENPGP_NEWKEY 忽略标准输入,直接生成一个新的密钥
pem2openpgp tmp_name < ./tmp_ssh_key | gpg --import
# Step 4: 查看该独立主密钥的 keygrip(之后就不再需要该独立主密钥的公钥信息,记得删除公钥,但不要删除私钥)
gpg -k --with-keygrip
# Step 5: 删除临时 ssh 私钥文件
rm -f ./tmp_ssh_key
步骤二:主密钥添加子密钥 #
bash
# Step 0: 编辑自己的主密钥(name 是自己的用户标识)
gpg --expert --edit-key name
# Step 1: 添加子密钥,执行如下操作:
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? ### 输入13,从已有密钥中添加 ###
Enter the keygrip: ### 将步骤一中得到的 gpg 私钥作为子密钥,输入其 keygrip 值 ###
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate ### 保留 Authenticate 功能即可,其他功能不需要 ###
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection?
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) ### 选择过期时长,默认(0)回车就行 ###
Key does not expire at all
Is this correct? (y/N) ### 输入 y ###
Really create? (y/N) ### 输入 y ###
gpg> save ### 输入 save,保存退出 ###
# Step 2: 确认是否添加成功(检查子密钥中是否包含目标密钥的 keygrip)
gpg -k --with-keygrip