惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
IT之家
IT之家
V
V2EX
Jina AI
Jina AI
V
Visual Studio Blog
有赞技术团队
有赞技术团队
博客园 - 司徒正美
博客园 - 叶小钗
The Cloudflare Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
Google Online Security Blog
Google Online Security Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
N
News and Events Feed by Topic
N
News and Events Feed by Topic
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
月光博客
月光博客
Security Archives - TechRepublic
Security Archives - TechRepublic
Webroot Blog
Webroot Blog
SecWiki News
SecWiki News
博客园_首页
罗磊的独立博客
量子位
Latest news
Latest news
I
Intezer
V
Vulnerabilities – Threatpost
A
Arctic Wolf
Last Week in AI
Last Week in AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
SegmentFault 最新的问题
S
Security Affairs
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Palo Alto Networks Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
N
News | PayPal Newsroom

Dejavu's Blog

甲骨文 ARM 实例部署 Gemma 4 模型 Headscale + Tailscale 组建虚拟专用网 在 Linux 上使用 Yubikey OpenPGP 应用 BuyVM VPS 块存储挂载教程 Alpine Linux 服务器配置指南 Alpine Linux 安装 Cloudflared Docker 多容器共享中心数据库 安装 Komari 服务器监控工具 Scaleway VPS 安装 Debian Linux Debian 13 下部署 AsmBB 论坛 使用 Kopia 自动化备份服务器数据 给 Docker 启用 IPv6 支持 Netcup 服务器安装自定义 ISO 镜像 烽火 HG5582A 光猫开启桥接模式 Docker 自托管 Shlink 短链服务 部署 Obsidian LiveSync 实时同步服务指南 我的 2025 年不完全回顾 Linux 下 Intel 核显驱动配置与硬件加速 Fedora Linux 安装配置记录 2025 年优雅地自托管 RSS 服务 Woodpecker CI 和 Gitea 实现 Hugo 自动部署 Gitea/Forgejo 集成 Woodpecker CI/CD 在 Blinko 中使用 Ollama 作为 AI 供应商 Docker 部署 Gitea/Forgejo Plausible CE 启用城市级地理位置识别 Blinko 开源 AI 知识库 Docker 部署指南 Netcup 免税账号注册及购买服务器全记录 Docker 自托管 Cloudreve Pro 私有网盘服务 GiffGaff SIM 卡使用体验和注意事项 简体中文互联网在变得糟糕吗? 如何低成本申请 S/MIME 证书用于个人邮件服务 迁移到 NameCrane Mail 域名邮箱套件服务 香烟与咖啡 Windows 11 IoT LTSC 养老指南 巧用浏览器生成 HAR 文件批量下载所需网页资源 聊聊静态网站的评论系统 在 Hugo 站点中优雅地展示实况照片 使用 snac 部署一个简洁优雅的 ActivityPub 实例 当 25 岁来临的时候 断网的这两年 从 Bitwarden/Vaultwarden 到 KeePassXC 也许是 Android 上最好的本地播放器 - 椒盐音乐 2023 半年小结 写一个好玩的 Hugo 货币汇率转换短代码 写一个 Hugo 短代码将不同类别的总字数统计转换为书名显示 海信 Touch Lite 墨水屏音乐阅读器的简单体验 从 Debian 11(bullseye) 无感升级到 Debian 12(bookworm) 使用 GitHub Actions 自动提交 URL 到 IndexNow 批量重写 Git 历史提交记录 使用 cgit 托管小小的也很可爱的 Git 服务器 在 Debian 上使用 stagit 和 Nginx 的简单 Git 服务器 托管简单 Git 服务器的一些尝试 使用 stagit 自托管纯静态 Git 存储库 使用 Docker 快速部署单人 Fediverse 实例 我是如何建立自己的个人博客的? 简单、隐私友好的谷歌分析替代品,Plausible 自托管部署指南 服务器使用 Cloudflare CDN 的最佳实践 甲骨文服务器分配并启用 IPv6 地址 Git 版本控制学习笔记(二) Cloudflare WAF 防护策略简易指南 Mastodon 服务器批量导入自定义表情 低成本自托管 Mastodon 实例简明指南 自托管服务指南──有了服务器可以做什么? 使用 Miniflux + RSSHub 打造个人 RSS 阅读器 构建支持多种 CPU 架构的 Docker 镜像 一个可自托管的静态短链接应用 别了,二〇二二! Duplicacy CLI 进阶使用指南 Duplicacy CLI 备份工具的基本使用 初探 Cloudflare 零信任 - 通过 Docker 部署 Bitwarden 密码管理器 Yubikey 转运日志及上手指南 初探 Cloudflare 零信任 — 通过 Cloudflare Tunnel 搭建 SSH 聊天室 初探 Cloudflare 零信任 - 通过 Cloudflare Tunnel 访问服务 某科学的 PGP 算号指南 2022 年的 MacBook Air M1 使用体验及应用推荐 使用 Vercel 和 Supabase 自托管 Cusdis 评论系统 为什么你的搜索引擎不好用? 个人在 Windows 上常用软件清单 macOS 基础开发环境设置指南 在 macOS 上使用 Canokey 的 OpenPGP 应用 提取 Windows UWP 应用商店的安装包以供离线安装 Git 版本控制学习笔记(一) 使用 Notion 管理 GitHub Star 项目 使用 Vercel 免费部署 Giscus 评论系统 将博客评论从 Utterances 无缝迁移到 Giscus Canokey 签名和认证应用指南 Canokey 的基本使用指南 Canokey Pigeon 揽件日志及简单开箱 关于 Google Play 保护机制和 DRM 安全等级的那些事 记录一次捡垃圾装机 GitHub 使用 GPG 密钥提交签名认证 使用 Scoop 管理 Windows 下的软件和开发环境 Windows Terminal+PowerShell 7 打造 Windows 下最好用的终端 一个好用的 Telegram 文件批量上传/下载工具 Clash for Windows 优雅地使用 TUN 模式接管系统流量 全平台搭建 Hexo 静态博客指南 尝试将 Manjaro 作为主力操作系统使用 Hexo 进行 SEO 优化的基本指南 使用本地代理给 Git 和 NPM 加速 使用 flowerss 部署 Telegram RSS 订阅机器人
在 Windows 中使用 Yubikey 的 OpenPGP 应用
Dejavu Moe · 2025-10-23 · via Dejavu's Blog

前言

几年前,我开始接触硬件安全密钥,当时使用的 Canokey 它实现了 Yubikey 的绝大部分功能,在 Canokey 签名和认证应用指南 中记录了我的配置过程(该指南同样适用于 Yubikey)。

然而,时隔数年,当我尝试在 Windows 系统上重新配置此流程时,却遭遇了诸多令人困惑的地方。难以排查系统内建的 Win32-OpenSSH 与通过 Scoop 安装的 GnuPG (而非 Gpg4Win )之间,对于 ssh-agentgpg-agent,如何实现管道和代理转发的复杂机制,它们对我来说就像是个「黑盒子」。

confused.webp

经过查阅 很多 一些资料,我重新完成了这个配置过程,本文仍可能存在错误之处,但其核心价值在于记录,确保下次重装系统后我可以快速完成设置和使用。

本文着力于 Win32-OpenSSH 原生 SSH 客户端 的配置,而非 PuTTY、Cygwin、MSYS2 或 WSL2 中的实现。使用 PuTTY 进行代理转发的方案不够简洁高效,我更喜欢简单、原生的实现和处理。此外, win-gpg-agent 项目的维护者已于 2022 年 9 月宣布停止维护,安全考量可能是其中一个原因。

仔细阅读 GnuPG 清单 T3883 和 GitHub #827 上关于此问题的追踪,可以发现跨系统代理配置困难的主要原因可能在于 Windows 的命名管道 (Named Pipes) 与 *nix 系统的套接字 (Socket) 处理机制存在本质区别,最新的 Win32-OpenSSH 是否已经实现了这个原生命名管道的处理呢?我无从了解,但是现在最起码它正常工作了!

pinentry-basic.webp

本文中,我们的处理流程大致如下:

+----------------+
|    YubiKey     |
|  OpenPGP Keys  |
+-------+--------+
        |
        | (GPG Keys)
        v
+------------------------+
|      gpg-agent         |
| (GPG Agent & SSH Proxy)|
+---+--------+--------+--+
    ^        |        ^
    |        |        | (SSH Auth Request)
    |        |        +---------------------+
    |        |                              |
    | (GPG Sign Request)                    v
+---+-----------------------+        +------+-------------------------+
|   GnuPG / Git (Commit -S) |        | Win32-OpenSSH / Git (Push/SSH) |
+---------------------------+        +--------------------------------+

             (PIN/Touch Authentication)
             <------------------------>

环境

先决条件

我们假定 YubiKey 上的 OpenPGP 应用中已生成并写入了 GPG 密钥。同时默认你此前在其他计算机上的相关配置能够正常工作。在新安装的 Windows 系统上,你已通过 Scoop 完成了 gnupggitsudo 的安装。

scoop install git gnupg
scoop install sudo -g

系统信息

systeminfo | findstr /B /C:"OS 名称" /C:"OS 版本"
OS 名称:            Microsoft Windows 11 IoT 企业版 LTSC
OS 版本:            10.0.26100 N/A Build 26100

GnuPG 信息

GnuPG 的版本信息

gpg --version
gpg (GnuPG) 2.5.16
libgcrypt 1.11.2
Copyright (C) 2025 g10 Code GmbH
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: C:\Scoop\apps\gnupg\current\home
Supported algorithms:
Pubkey: RSA, Kyber, 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

配置文件路径,我的在 C 盘的 Scoop 目录下

gpgconf --list-dirs
sysconfdir:C%3a\Scoop\apps\gnupg\current\etc\gnupg
bindir:C%3a\Scoop\apps\gnupg\current\bin
libexecdir:C%3a\Scoop\apps\gnupg\current\bin
libdir:C%3a\Scoop\apps\gnupg\current\lib\gnupg
datadir:C%3a\Scoop\apps\gnupg\current\share\gnupg
localedir:C%3a\Scoop\apps\gnupg\current\share\locale
socketdir:C%3a\Scoop\apps\gnupg\current\gnupg
dirmngr-socket:C%3a\Scoop\apps\gnupg\current\gnupg\S.dirmngr
keyboxd-socket:C%3a\Scoop\apps\gnupg\current\gnupg\S.keyboxd
agent-ssh-socket:C%3a\Scoop\apps\gnupg\current\gnupg\S.gpg-agent.ssh
agent-extra-socket:C%3a\Scoop\apps\gnupg\current\gnupg\S.gpg-agent.extra
agent-browser-socket:C%3a\Scoop\apps\gnupg\current\gnupg\S.gpg-agent.browser
agent-socket:C%3a\Scoop\apps\gnupg\current\gnupg\S.gpg-agent
homedir:C%3a\Scoop\apps\gnupg\current\home

OpenSSH 信息

使用的是 Windows 默认的 Win32-OpenSSH 客户端

ssh -V
OpenSSH_for_Windows_9.5p2, LibreSSL 3.8.2

配置流程

禁用 SSH Agent 服务

现在的 Win32-OpenSSH 已经有 ssh-agent 服务了,但是它会干扰 gpg-agent 的处理进程,确保它已停止运行

sudo Get-Service ssh-agent

Status   Name               DisplayName
------   ----               -----------
Stopped  ssh-agent          OpenSSH Authentication Agent

否则请停止其服务并禁止自动运行

sudo Stop-Service ssh-agent
sudo Set-Service -StartupType Disabled ssh-agent

识别智能卡

这一步并非强制要求,但根据 YubiKey-Guide 中的 说明 ,现在 Windows 中可能存在一些虚拟智能卡(例如 Windows Hello 相关的读卡器)。有可能干扰 到 scdaemon 的工作,导致它无法正确读取 YubiKey 智能卡设备。

查看设备信息:

Get-PnpDevice -Class SoftwareDevice | Where-Object {$_.FriendlyName -like "*YubiKey*"} | Select-Object -ExpandProperty FriendlyName

会输出 Yubikey 完整的设备名称,比如:

Yubico YubiKey OTP+FIDO+CCID 0

C:\Scoop\apps\gnupg\current\home 下新建一个 scdaemon.conf 写入以下内容:

reader-port Yubico YubiKey OTP+FIDO+CCID 0

插入 Yubikey,查看智能卡状态:

# reload gpg config
gpgconf --launch gpg-agent

# check gpg card
gpg --card-status

导入公钥

从服务器或者本地文件导入我们的 PGP 公钥,我在公钥服务器导入:

curl -fsSL https://pgp.dejavu.moe/ | gpg --import -

信任自己的公钥:

gpg --expert --edit-key [your email/keyid/fingerprint]

gpg> trust

Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)

  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

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

配置 Git 签名

查看用于签名子密钥的 [KeyID of signature subkey]

gpg --list-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
\Scoop\apps\gnupg\current\home\pubring.kbx
--------------------------------------------
pub   ed25519/[Master KeyID] 2021-05-31 [C]
      [Master Key Fingerprint]
uid                 [ultimate] Dejavu Moe <admin@dejavu.moe>
sub   ed25519/[KeyID of signature subkey]      2022-09-26 [S] [expires: 2035-09-23]
sub   cv25519/[KeyID of encryption subkey]     2021-07-18 [E] [expires: 2035-07-15]
sub   ed25519/[KeyID of authentication subkey] 2022-01-09 [A] [expires: 2035-01-06]

添加 Git 设置:

git config --global user.name "YourName"
git config --global user.email "[email protected]"
git config --global user.signingkey "[KeyID of signature subkey]"
git config --global commit.gpgsign true
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"

配置 GPG 程序路径:

# find gpg.exe
which gpg.exe
C:\Scoop\apps\gnupg\current\bin\gpg.exe

# then
git config --global gpg.program "C:/Scoop/apps/gnupg/current/bin/gpg.exe"

验证 GPG 签名

新建一个测试文本文件

echo "This is a test message to be signed." > test_sign.txt

尝试签名

gpg --local-user [KeyID/Email] --detach-sign test_sign.txt

验证签名

gpg --verify test_sign.txt.sig test_sign.txt
gpg: Signature made 10/23/25 12:31:54
gpg:                using EDDSA key 2E21425AC287228857E027D5223E2D2495F24232
gpg:                issuer "[email protected]"
gpg: Good signature from "Dejavu Moe <[email protected]>" [ultimate]

配置 SSH 代理

查看用于身份认证子密钥的 keygrip,进入 C:\Scoop\apps\gnupg\current\home 目录,将 [keygrip for authentication subkey] 的内容写入 sshcontrol 文件:

# list all keygrip
gpg -K --with-keygrip
ssb>  ed25519 2022-01-09 [A] [expires: 2035-01-06]
      Keygrip = [keygrip for authentication subkey]

同样在这个目录下写入 gpg-agent.conf 文件:

# enable SSH agent
enable-ssh-support
# enable optimized support for Win32-OpenSSH client
enable-win32-openssh-support
# set the default cache time for PIN codes (10 minutes)
default-cache-ttl 600
# set the maximum cache time for PIN codes (2 hours)
max-cache-ttl 7200
# pinentry dir
pinentry-program C:/Scoop/apps/gnupg/current/bin/pinentry-basic.exe

重新启动相关进程:

gpg-connect-agent killagent /bye
gpg-connect-agent /bye
gpgconf --launch gpg-agent

尝试导出 SSH 公钥:

应该会得到正确的 SSH 公钥格式,将其添加到 GitHub 或 VPS 上的信任 SSH 公钥列表里,比如:

ssh-ed25519 AAAA.../... cardno:12_345_987

验证 GPG SSH

测试下 GitHub SSH 访问

应该没问题了

Hi DejavuMoe! debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
You've successfully authenticated, but GitHub does not provide shell access.

最后

还是想吐槽下这个 pinentry-basic.exe,每次输入 PIN 解锁 Yubikey 时,都要用鼠标去输入框点一下,它无法自动获取输入焦点,暂时只能做到在 GPG 签名时可以直接在终端里输入 PIN。

pinentry-tty-sign.webp

嗯,现在一切就已经完成了。然而,目前对于 SSH 认证的 PIN 输入问题仍未找到满意的解决方案,类似 pinentry-tty 的思路在当前环境下(指 Windows 原生环境)尚未成功实现,算是一个小痛点吧。

参考资料: