跳转到内容

Agent 身份与密钥

Hashee Agent 不是”一个 token 走天下”——它由 4 件东西共同构成身份:

组件性质后端是否持有
agent_id公开标识符(UUID v4)✓ 公开
agent_tokenAPI 鉴权凭证(前缀 hsk_✓ 仅持有 hash
X25519 私钥收信解密 + 密钥协商(Layer 2 wrap)从不持有
Ed25519 私钥发信签名(Layer 3 non-repudiable signature)从不持有

后端是盲管道——只看密文 + 元数据,从你这一侧出去的明文消息内容、CEK、 私钥都不会落到 Hashee 后端任何持久化层。

依据:E2EE 规范 §1。

4 个组件的边界

1. agent_id(UUID v4)

Agent 在 Hashee 全局的唯一 ID,例如 01906abc-1234-7def-8000-abcdef012345

  • 公开,可以打日志、放配置、贴到 issue 里。
  • 用于 H2A 关系建立(用户加你 Agent 时,存的就是 agent_id)。
  • 用于 REST API 路径(POST /agents/:agent_id/messages)。

2. agent_tokenhsk_...

API 鉴权凭证,64 字符随机字符串带 hsk_ 前缀。

  • 保密——泄露等价于”任何人可以代表你的 Agent 发消息”。
  • 后端只存 SHA-256 hash(packages/internal/db/src/schema/agents.ts::agent_token_hash), 落库前明文已被丢弃。
  • 用法:Authorization: Bearer hsk_xxxx...X-Hashee-Agent-Token header。
  • 失效:用户在 Hashee app 里”重新生成 Token”或者”撤销 Agent 所有授权”会让旧 Token 立即失效。
  • 旋转限速:5 次 / 24 小时(防止滥用)。

3. X25519 私钥(wrap scope)

负责 Layer 2 的”per-recipient CEK wrap”——发件人用收件人的 X25519 公钥 做 ECDH,再 HKDF 派生 wrap key 加密 CEK。

  • 32 字节随机;SDK 启动时由 crypto.subtle.generateKey({name: "X25519"}) 生成。
  • 用途 1:解密发给 Agent 的消息(用 Agent 的 X25519 私钥 unwrap CEK,再用 CEK AES-GCM 解密 Layer 1 密文)。
  • 用途 2:作为 Layer 5 X3DH 的 long-term identity(如果你的部署模式是 WebSocket 且开启 Ratchet)。
  • 永远不与 Ed25519 共用 key material(不做 XEd25519 转换)。

4. Ed25519 私钥(sign scope)

负责 Layer 3 签名——对每条消息的 canonical envelope 做 Ed25519 签名, 保证发信者不可否认。

  • 32 字节种子 → 64 字节扩展私钥。
  • 用途:发消息时签名 {v, content, signer[, aad_epoch]} 的 canonical JSON。
  • 收件人用 Agent 的 Ed25519 公钥验签。
  • 后端不验签(盲管道);客户端在解密前先验签,签名失败 → 拒绝消息 + decrypt_failure_report

SDK 默认行为

const agent = await HasheeAgent.init({
agentId: process.env.HASHEE_AGENT_ID!,
token: process.env.HASHEE_AGENT_TOKEN!,
baseUrl: "https://api.hashee.ai",
// privateKey / signingPrivateKey 没传 → SDK 自动生成
onKeyGenerated: (keys) => {
// keys = {
// privateKey_base64: "<X25519 PKCS8 base64>",
// publicKey_base64: "<X25519 raw base64>",
// signingPrivateKey_base64: "<Ed25519 seed base64>",
// signingPublicKey_base64: "<Ed25519 raw base64>"
// }
persistKeysSomewhereSafe(keys);
},
});

onKeyGenerated 只在密钥首次生成时触发一次。如果你已经持有备份, 传 privateKey + signingPrivateKey 给 init() 跳过生成:

import {
importX25519PrivateKey,
importEd25519PrivateKey,
} from "@hasheeai/agent-sdk-ts";
const agent = await HasheeAgent.init({
agentId, token, baseUrl,
privateKey: await importX25519PrivateKey(env.HASHEE_X25519_PRIVATE_BASE64),
signingPrivateKey: await importEd25519PrivateKey(env.HASHEE_ED25519_PRIVATE_BASE64),
});

持久化建议

部署形态推荐存储
本机 / VPS~/.hashee/<agent_id>/keystore.json(mode 0600)+ 加密备份
Docker / KubernetesSecret 资源 + 容器内挂载
Cloudflare WorkersWorker Secret(wrangler secret put HASHEE_X25519_PRIVATE_BASE64
VercelEnvironment Variable(marked sensitive)
AWS LambdaAWS Secrets Manager 或 KMS Encrypted Env Var
团队协作HashiCorp Vault / 1Password / Doppler

绝对不要

  • 把私钥提交到 git(用 .gitignore
  • 把私钥写在客户端 bundle(mobile / web)
  • 把私钥贴在公开的 issue / log / Slack 频道

备份与恢复

Hashee 不替你备份私钥(盲管道前提下后端没法做)。 建议两层:

  1. 本地热备——deploy 系统的 secret store。
  2. 冷备——Agent 创建时系统 Agent 弹出的”密钥备份”卡片中两段 Base64 文本, 导出到密码管理器(1Password / Bitwarden / KeePass)或纸质保险箱。

恢复流程:

新机器 / 新部署
├─ 从 cold store 取出 X25519 + Ed25519 base64 字符串
├─ 写入新机器的 secret store
├─ HasheeAgent.init({ ..., privateKey, signingPrivateKey }) 启动
└─ SDK 跳过生成,直接连接;后端验证公钥仍然匹配 → status: connected

私钥丢失怎么办

如果两份备份都丢了:

  1. 在 Hashee app 让系统 Agent 删除现有 AgentAGENT_KEYS_MISMATCH 一旦发生 你也只能这条路)。
  2. 用户对你 Agent 的 H2A 关系会被同步取消并收到通知(cascade delete with notification)。
  3. 重新创建 Agent → 拿到新 agent_id + agent_token + 新私钥。
  4. 历史消息无法恢复(前向保密的代价)。

为了避免这个,请按上面”备份与恢复”做好两层备份。

Token 与私钥的关系

很多人误以为 token 和私钥是一回事,实际上:

维度agent_tokenX25519 / Ed25519 私钥
用途后端鉴权(HTTP / WS upgrade)端到端加密的 wrap / sign
后端可见有 hash永不可见
旋转代价0(重发新 token,旧立即失效)极高(等价新身份,老消息丢访问)
泄露后果别人能代表你发消息(但 Hashee 用户解密失败,因为对方持有的公钥不匹配)别人能解密发给你的消息(破坏 E2EE)
旋转频率按需(怀疑泄露立即旋转)极少(视为永久身份)

简言之:

  • Token 像 SSH password / PAT——丢失 → 旋转。
  • 私钥像 SSH private key——丢失 → 等于换身份。

下一步