WhatsApp 配对码提取五段(Web 全参)
用配对码把一台新设备挂到已登录的手机上,成功后在本地得到一份会话 JSON。习惯上把其中最核心的五块密钥材料叫做「五段」:noiseKey、signedIdentityKey、signedPreKey、registrationId、advSecretKey。其余字段(账号签名、本机 JID、路由信息等)随同一份 JSON 一并写出,供后续登录复用。
配对走 WebSocket 文本通道(UTF-8 JSON),不走浏览器表单。独立操作页用于发起配对;后台看板只读状态,不要拿来发配对。服务启动时会做出口授权校验,未通过则进程直接退出。可用健康检查接口确认服务是否就绪(应返回 {"ok":true})。
演示视频
以下为本方案的使用演示(若无法播放,可 在 YouTube 打开):
⚠️ 声明:本文仅作技术流程与概念整理;请遵守所在地法律法规与 WhatsApp 服务条款。仅限本人有权操作的账号;切勿用于未授权访问、骚扰或任何违法用途。风险与责任由使用者自行承担。
🔒 安全提示:五段与会话 JSON 等价于高敏感凭据,不要在公开场合泄露完整内容。下文密钥样例均为结构占位,不可用于登录。
一、配对通道怎么用
连上后服务端立刻推一条:
{"type":"hello","message":"connected","ts":1710000000000}之后同一连接可连续发起多个会话,用 reqId / guid 区分。客户端请求至少带 action;reqId 可省略(服务端会补 UUID)。
开始配对
{"action":"start_session","reqId":"r-001","phone":"8613800138000"}phone 只保留数字、国际格式、不要以 0 开头、长度须大于 6。成功先回 ack 并分配 guid;号码不合法则直接 error(如 phone number too short、phone must be international format without leading 0)。
停会话 / 心跳
{"action":"stop_session","reqId":"r-002","guid":"<ack 里的 guid>"}
{"action":"ping","reqId":"r-003"}停会话成功为 session_stopped;缺少 guid 或会话不存在为 error。ping 回 pong。空 action 会被忽略,不回复。
广播规则:发起配对的连接一定收到本会话事件;link_code / paired / pair_err / session_timeout / login_event / session_started 还会推给同一台上其它已连接的配对客户端(不含 owner)。session_stopped 广播给其它客户端,不含发起 stop 的那条连接。
二、从配对码到本地 JSON
一次成功提取的顺序大致如下(网络和用户操作会造成先后差异)。
ack:会话已接受,记下guid。link_code:拿到linkCode(形如ABCD-1234)。手机端:WhatsApp → 关联设备 → 使用手机号码关联 → 输入该码。login_event(可选,0 到多次):event为登录通道事件名,例如success。paired:配对成功,本地已写出 JSON,path即为文件路径。失败为pair_err。若该号码此前已有登录态,可能先出现session_started,而不走配对码。- 超时:约 160 秒仍未配对成功,推
session_timeout。子进程崩溃则推type=error。
paired 示例:
{
"type": "paired",
"reqId": "r-001",
"guid": "05346bf4-e4f4-4e41-b9fc-6466f78069a6",
"phone": "8613800138000",
"path": "/path/to/payload/8613800138000_<sha1>.json",
"message": "pair success",
"ts": 1710000005000
}文件落在程序目录下的 payload/,命名为 <手机号>_<内容 sha1>.json。看板通道只同步写出成功或失败,不参与配对。
最短联调路径:连上配对 WebSocket 后发送一条 start_session(带国际格式 phone),再按手机端提示输入返回的 linkCode。
三、五段本体(JSON 里必须能对上的五块)
下面以一份已提取成功的会话结构为例(companion 设备号以 :N 表示)。密钥在 JSON 里都是 { "type": "Buffer", "data": "<标准 Base64>" };公私钥成对出现。
1. noiseKey — 传输层握手
Noise 握手用的静态密钥对。缺公钥或私钥,后续无法再连上同一条加密通道。
"noiseKey": {
"public": { "type": "Buffer", "data": "<Base64_public>" },
"private": { "type": "Buffer", "data": "<Base64_private>" }
}2. signedIdentityKey — 本机身份
本 companion 设备的长期身份密钥。signalIdentities.identifierKey 与这里的 公钥相同,不要改成账号侧的 accountSignatureKey。
"signedIdentityKey": {
"public": { "type": "Buffer", "data": "<Base64_public>" },
"private": { "type": "Buffer", "data": "<Base64_private>" }
}3. signedPreKey — 签名预密钥
含 keyId、signature 以及一对 keyPair。当前样例 keyId 为 1。
"signedPreKey": {
"keyId": 1,
"signature": "<Base64_signature>",
"keyPair": {
"public": { "type": "Buffer", "data": "<Base64_public>" },
"private": { "type": "Buffer", "data": "<Base64_private>" }
}
}4. registrationId — 注册号
无符号 32 位整数。和身份密钥、预密钥一起参与加密会话建立。
5. advSecretKey — 多设备 ADV 密钥
单段 Base64 字符串。用于校验主设备下发的设备身份容器。没有这一段,账号签名对不上,五段即使另外四段齐全也无法作为已配对设备使用。
四、同一份 JSON 里还要一起带上的字段
五段是骨架,下面这些决定「这是哪台设备、有没有配对完成」。
本机身份
| 字段 | 说明 |
|---|---|
Phone | 国际号码,与 me.id 的 user 段一致 |
me.id | 本设备 JID,冒号后是 companion 设备号(如 8613800138000:5@s.whatsapp.net) |
me.lid | LID,设备号应与 me.id 相同 |
me.name | 推送名,可空 |
platform | 主设备平台(如 android) |
registered | 已完成配对时应为 true |
账号签名(account)
主设备签发的设备身份:details、accountSignatureKey、accountSignature、deviceSignature,均为 Base64。这是「被主设备承认」的证明,和五段里的 advSecretKey 配套。
signalIdentities(按真实设备号,不要写成 0)
"signalIdentities": {
"identifier": {
"name": "<phone>:<deviceId>@s.whatsapp.net",
"deviceId": 5
},
"identifierKey": {
"type": "Buffer",
"data": "<须等于 signedIdentityKey.public.data>"
}
}deviceId 必须等于 me.id 里的设备号(不是 0)。identifierKey.data 必须等于 signedIdentityKey.public.data。
配对与同步附属字段
| 字段 | 含义 |
|---|---|
pairingCode | 8 位配对码(无横线)。仅配对过程中有值 |
pairingEphemeralKeyPair | 生成配对码时的临时密钥对 |
routingInfo | 边缘路由 blob,type=Buffer |
lastPropHash | 服务端 props 哈希 |
firstUnuploadedPreKeyId / nextPreKeyId | 预密钥计数;尚未生成时可能为 0,有库存后为下一枚 ID |
lastAccountSyncTimestamp | 账号同步时间戳 |
accountSettings.unarchiveChats | 常见为 false |
accountSyncCounter | 常见为 0 |
myAppStateKeyId | 可空 |
processedHistoryMessages | 可为空数组 |
JSON 对象的 key 顺序不重要(实现里常常按字母序输出)。Buffer 内部是 type + data,缺一不可。
五、验收与注意点
对照 paired 给出的文件,至少确认:
- 五段都在:
noiseKey、signedIdentityKey、signedPreKey、registrationId、advSecretKey,公私钥data都不是空字符串。 Phone、me.id、me.lid的号码与设备号一致;signalIdentities.identifier.deviceId与me.id的:N相同。identifierKey与signedIdentityKey.public相同;account四段签名齐全。registered为true。pairingCode/routingInfo/lastPropHash/ 预密钥计数允许在刚写出时仍为空或为0,它们不是五段本体,有则一并保留。
常见失败不在 JSON 结构,而在通道:号码格式不对、未在约 160 秒内在手机端输入配对码、未通过启动授权校验、对已消失的 guid 发 stop_session。提取成功以 type=paired 且 path 指向可读 JSON 为准;不要用看板页上的路径猜测代替这条事件。
若你有合法、合规的软件定制或技术咨询需求,可通过本站页脚所列方式联系(请简要说明场景与合规性)。