WorkBuddy v5.6+ accessToken、refreshToken解密指南:AES-256-GCM 实战
1. 背景:为什么 v5.6 要加密 token?
在 v5.6 之前,WorkBuddy 桌面客户端的登录态文件 workbuddy-desktop.info 里,accessToken / refreshToken 是明文存放的。虽然文件本身应受系统权限保护,但明文落盘一旦被拷贝或误传,就等于把登录凭证拱手让人。
从 v5.6 开始,客户端对这两个字段做了静态加密:先把明文 token 用 AES-256-GCM 加密,再 Base64 编码封进一个「信封(envelope)」对象写入文件。文件里再也看不到裸 token,而是变成这样:
{
"auth": {
"accessToken": { "$wbEncrypted": 1, "envelope": "eyJzdWl0ZSI6MS..." },
"refreshToken": { "$wbEncrypted": 1, "envelope": "eyJzdWl0ZSI6MS..." }
}
}只要看到 "$wbEncrypted": 1 这个标记,就说明这是一个 v5.6+ 的加密 token,需要用对应的解密流程还原出明文。
2. 加密数据格式(信封结构)
密文本身并不直接放在字段里,而是被封装进 envelope 这个字符串。envelope 的值是 一段 Base64 编码的 JSON,解码后大致长这样(字段名以实际工具源码为准,结构与工具行为一致):
{
"suite": 1,
"iv": "MTIzNDU2Nzg5MGFiY2RlZg==",
"tag": "YWJjZGVmMTIzNDU2Nzg5MA==",
"data": "QW5lNzZlTm1lN3l0Z...(长串密文)"
}字段 | 含义 |
suite | 加密套件版本号(目前为 1,表示 AES-256-GCM) |
iv | 初始化向量 / Nonce,AES-GCM 标准用 12 字节(96 bit),Base64 编码 |
tag | GCM 认证标签(Authentication Tag),一般 16 字节(128 bit),Base64 编码 |
data | 真正的密文(Ciphertext),Base64 编码 |
为什么用 GCM? GCM 是 AEAD(带认证加密)模式,不仅保证机密性,还用 tag 校验数据完整性。任何对密文或 IV 的篡改,都会在解密阶段因为 tag 校验失败而直接报错,而不是吐出乱码。这也是它比「AES-CBC + 手写 MAC」安全的地方。
解码示例(页面里那串 eyJzdWl0ZSI6MS... 正是 {"suite":1... 的 Base64)。
3. 解密的核心难点:主密钥从哪来?
AES-256-GCM 解密只要三样东西:key(主密钥)+ iv + tag + 密文。
其中 iv / tag / data 都明文写在 envelope 里,随手就能取。难点只有一个——主密钥(256-bit 的 key)不在文件里。
WorkBuddy 客户端的主密钥在运行时由 Electron 进程持有,且不会落盘。要拿到它,唯一公开可行的路径是:
启动本地的 WorkBuddy.exe 作为 Electron Runtime 子进程,从进程内存里提取主密钥。
这就是为什么:
✅ 本地 Windows / macOS 机器(装了 WorkBuddy 客户端)可以解密——它能拉起 Electron Runtime 把密钥从内存里取出来。
❌ 宝塔 / Linux 服务器(没装客户端、跑不动 Electron)不能直接解密。签到脚本一旦检测到 $wbEncrypted 格式会直接报错并提示「请先到本地解密」,而不是盲目尝试。
换句话说:解密动作必须在装有 WorkBuddy 客户端的本地机器上完成,解密出明文后,再把 info 文件上传到服务器使用。服务器侧只消费明文。
4. 解密方法(逐步拆解)
完整的本地解密流程分三步:
┌─────────────────────────────────────────────────────────┐
│ Step 1 读取 workbuddy-desktop.info,定位 $wbEncrypted │
│ Step 2 启动 Electron Runtime,从内存提取主密钥 (key) │
│ Step 3 解析 envelope → AES-256-GCM 解密 → 明文 token │
└─────────────────────────────────────────────────────────┘
Step 1 — 定位加密字段
读取 JSON,遍历 auth 节点,凡是有 "$wbEncrypted": 1 的字段(通常是 accessToken、refreshToken),取其 envelope 字符串进入下一步。accessTokenEncode / refreshTokenEncode 这类字段是解密工具「备份原密文」用的,不是解密入口。
Step 2 — 取得主密钥
这一步由 Electron Runtime 完成。把 WorkBuddy.exe 作为子进程拉起后,利用客户端内部的 safeStorage / 密钥派生逻辑,把保存在进程内存中的主密钥读出来。具体的内存定位逻辑封装在工具里,对外只暴露一个 get_master_key() 之类的接口。
关键点:主密钥与当前登录用户/设备绑定,且只在运行时存在。换台机器、或客户端未登录,都拿不到同一把密钥。
Step 3 — GCM 解密(核心算法)
拿到 key 后,剩下的就是标准 AES-256-GCM 运算:
envelope 字符串 → Base64 解码 → JSON
取出 iv、tag、data,分别 Base64 解码 成 bytes
用 key + iv + tag 对 data 做 AES-256-GCM 解密
解密结果(bytes)按 UTF-8 解码,即为明文 token
5. 推荐解密工具(,免写代码)
仓库随附两个现成解密工具,覆盖手动与自动化两种场景:
方式一:GUI 工具(手动首选)
双击 https://gitee.com/web/workbuddy_checkin/releases/download/latest/wb_token_gui.exe :

WorkBuddy.exe 路径 → 点「自动探测」(或手动选本地 WorkBuddy.exe)
info 文件路径 → 点「自动定位」(或手动选 workbuddy-desktop.info)
点 读取并解密 → 明文 token 出现,各自带「复制」按钮
点 写回 info 文件 → 原加密对象挪到 accessTokenEncode / refreshTokenEncode 备份,明文覆盖 accessToken / refreshToken
原加密凭据不会丢,下次客户端刷新 token 会重新加密,互不影响。
方式二:命令行工具(适合自动化)
python wb_token_resolver.py "path/to/workbuddy-desktop.info" --write
就地把加密 accessToken 替换成明文。注意:命令行版默认只处理 accessToken;refreshToken 若也加密,建议直接用 GUI 一键搞定两者。
解密后
把更新后的 workbuddy-desktop.info 重新上传到服务器(覆盖旧文件),服务器侧的签到/调用脚本即可正常识别使用。建议 chmod 600 保护该文件。
6. 常见坑
现象 | 原因 | 解决 |
报 $wbEncrypted 不支持 | 服务器 info 是加密格式,但服务器没客户端 | 回本地 Windows 用 GUI/CLI 解密后再上传 |
tag 校验失败 / InvalidTag | iv/tag/data 解码错乱,或 key 不对 | 确认主密钥来自同一台机器同一登录态 |
解密出乱码 | envelope 被当整体解密而非先 JSON 解析 | 必须先 Base64 解码 envelope → 解析 JSON → 分别取字段 |
refreshToken 没解密 | 用了 CLI 版(默认只解 accessToken) | 改用 GUI 工具一次性处理两者 |
解密后客户端无法续期 | 没备份原密文 | GUI 已自动备份到 *Encode;CLI 版注意保留 |
8. 安全约定(务必遵守)
解密只在本地做:主密钥只在装了客户端的机器内存里,异地/服务器无法也不应还原。
原密文留底:解密写回时保留 accessTokenEncode / refreshTokenEncode,方便客户端下次刷新。
明文文件权限收紧:服务器上 chmod 600 workbuddy-desktop.info,避免明文 token 被其他进程读取。
绝不外泄明文:终端/日志/推送里 token 一律脱敏(只显示 eyJhbG...xxxx)。
临时写入原子化:刷新 token 时先写 .tmp 再 os.replace,防止中途崩溃损坏 info 文件。
小结
WorkBuddy v5.6+ 用 AES-256-GCM 把 accessToken / refreshToken 封进 envelope 写盘,iv/tag/data 明文可见,唯独 256-bit 主密钥留在 Electron 进程内存。解密方法可归纳为:
定位 $wbEncrypted 字段,取出 envelope;
本地启动 Electron Runtime 提取主密钥;
Base64 解码 envelope → 拆分 iv/tag/data → AES-256-GCM 解密 → 得到明文 token。
日常使用直接拿 wb_token_gui.exe / wb_token_resolver.py 最省事;需要嵌到自己脚本里时可以查看开源仓库核心代码。


