Ed25519 设备认证

OpenClaw 在 Gateway、Control UI 和原生应用中使用 Ed25519 公钥加密进行设备认证。

关键文件

  • src/infra/device-identity.ts (183 行): 核心身份管理
  • src/shared/device-auth.ts (31 行): 认证数据结构
  • src/pairing/pairing-store.ts (621 行): 配对流程实现

认证流程

密钥生成和派生

设备身份

// 来自 src/infra/device-identity.ts
const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
const publicKeyPem = publicKey.export({ type: "spki", format: "pem" });
const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" });
const deviceId = crypto.createHash("sha256")
  .update(derivePublicKeyRaw(publicKeyPem))
  .digest("hex");

密钥格式常量

// 用于密钥格式检测的 ED25519 SPKI 前缀
const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");

此前缀用于从 SPKI 格式中提取原始的 32 字节 Ed25519 公钥。

配对流程

配对码生成

  • 码长度: 8 字符
  • 字母表: ABCDEFGHJKLMNPQRSTUVWXYZ23456789(排除 0、O、1、I 以避免混淆)
  • TTL: 60 分钟 (3600000 毫秒)
  • 最大待处理数: 每个频道/账户 3 个码

来自 src/pairing/pairing-store.ts:

const PAIRING_CODE_LENGTH = 8;
const PAIRING_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
const PAIRING_PENDING_TTL_MS = 60 * 60 * 1000;
const PAIRING_PENDING_MAX = 3;

配对过程

  1. 请求配对:

    • 设备调用 upsertChannelPairingRequest({ channel, id, accountId, meta })
    • 系统生成唯一的 8 字符码
    • 码存储并在 60 分钟后过期
  2. 用户批准:

    • 用户通过控制 UI 输入码
    • 系统调用 approveChannelPairingCode({ channel, code, accountId })
    • 匹配时:将设备添加到允许列表,从待处理中删除码
  3. 令牌签发:

    • Gateway 签发带有角色和作用域的令牌
    • 令牌存储在设备认证存储中

质询-响应签名

签名

// 设备签名质询载荷
function signDevicePayload(privateKeyPem: string, payload: string): string {
  const key = crypto.createPrivateKey(privateKeyPem);
  const sig = crypto.sign(null, Buffer.from(payload, "utf8"), key);
  return base64UrlEncode(sig);
}

验证

// Gateway 验证签名
function verifyDeviceSignature(
  publicKey: string,
  payload: string,
  signatureBase64Url: string
): boolean {
  const key = crypto.createPublicKey(publicKey);
  const sig = base64UrlDecode(signatureBase64Url);
  return crypto.verify(null, Buffer.from(payload, "utf8"), key, sig);
}

安全属性

  • 设备身份是确定性的: deviceId = SHA256(publicKey) 确保同一设备始终具有相同的 ID
  • 私钥永不离开设备: 仅传输签名
  • 质询-响应防止重放: 每次认证使用新的质询
  • 限时配对: 码在 60 分钟后过期
  • 有限的待处理码: 每个频道/账户最多 3 个待处理码,防止滥用

交叉引用