mcpField
C
crypto-protocol-diagram

crypto-protocol-diagram

github.com/trailofbits安全7.9k4.0k 次安装今天更新
代码仓库

关于 crypto-protocol-diagram

这是一个从源代码或规范提取加密协议流程并生成 Mermaid 与 ASCII 时序图的技能,面向协议分析和安全审查,重点呈现消息语义与加密步骤,而非代码结构。

主要功能

  1. 01读取协议代码与规范
  2. 02识别参与方和消息流程
  3. 03标注加密操作
  4. 04呈现协议阶段与中止路径
  5. 05生成 Mermaid 和 ASCII 图

适用场景

  1. 01从源代码可视化握手流程
  2. 02绘制 RFC 或形式化模型
  3. 03对照实现与协议规范

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trailofbits/skills --skill crypto-protocol-diagram

安装后在 Claude Code 中输入/crypto-protocol-diagram确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
assets/
trail-of-bits-mark.svg
examples/simple-handshake/
expected-output.md
protocol.py
examples/simple-proverif/
expected-output.md
model.pv
references/
ascii-sequence-diagram.md
mermaid-sequence-syntax.md
protocol-patterns.md
spec-parsing-patterns.md

详细介绍

加密协议图

生成 Mermaid sequenceDiagram(写入文件)和 ASCII 时序图(内联打印),输入可以是:

  • 实现加密协议的源代码,或
  • 规范——RFC、学术论文、伪代码、非正式说明、ProVerif(.pv)或 Tamarin(.spthy)模型。

使用的工具: Read、Write、Grep、Glob、Bash、WebFetch(用于 URL 规范)。

与可视化代码结构的 diagramming-code 技能不同,此技能提取的是协议语义:谁向谁发送什么、每个步骤会发生哪些加密转换,以及协议包含哪些阶段。

如需绘制调用图、类层次结构或模块依赖关系图,请改用 diagramming-code 技能。

适用场景

  • 用户要求绘制、可视化或提取加密协议
  • 输入是实现握手、密钥交换或多方协议的源代码
  • 输入是 RFC、学术论文、伪代码或形式化模型(ProVerif/Tamarin)
  • 用户指定了某个协议(TLS、Noise、Signal、X3DH、FROST)

不适用场景

  • 用户需要调用图、类层次结构或模块依赖关系图——请改用 diagramming-code
  • 用户需要对协议进行形式化验证——请使用 mermaid-to-proverif(生成图之后)
  • 输入不包含加密协议语义(没有参与方,也没有消息交换)

应避免的错误理由

理由错误原因必须采取的行动
“协议很简单,我可以凭记忆绘图”凭记忆绘制的图会遗漏步骤并反转箭头系统地阅读源代码或规范
“既然有代码,我就跳过规范流程”代码可能与规范不一致——两种流程能发现不同的错误两者都存在时,先执行规范工作流,再标注代码中的差异
“加密注释只是可有可无的装饰”没有加密注释,图就只展示消息流,对安全审查毫无用处为每项加密操作添加注释
“中止路径很明显,不需要 alt 块”隐式处理中止会掩盖缺失的错误检查使用 alt 块展示所有中止/错误路径
“我不需要先查看示例”示例定义了预期输出质量标准处理不熟悉的输入前,先研究相关示例
“ProVerif/Tamarin 模型是代码,不是规范”形式化模型就是规范——它们描述预期行为,而非实现对 .pv 和 .spthy 文件使用规范工作流(S1–S5)

工作流

Protocol Diagram Progress:
- [ ] Step 0: Determine input type (code / spec / both)
- [ ] Step 1 (code) or S1–S5 (spec): Extract protocol structure
- [ ] Step 6: Generate sequenceDiagram
- [ ] Step 7: Verify and deliver

步骤 0:确定输入类型

开始前,先对输入进行分类:

特征输入类型
源文件扩展名(.py、.rs、.go、.ts、.js、.cpp、.c)代码
函数/类定义、导入语句代码
RFC 风格的章节标题(§、Section X.Y、MUST/SHALL 等关键词)规范
Algorithm/Protocol/Figure 标签、数学符号规范
包含 process、let、in/out 的 ProVerif 文件(.pv)规范
包含 rule、--[...]-> 的 Tamarin 文件(.spthy)规范
描述协议的普通文本或编号步骤规范
同时有源文件和规范文档两者(使用 ⚠️ 标注差异)
  • 仅代码 → 跳转到下方的步骤 1
  • 仅规范 → 跳转到下方的规范工作流(S1–S5)
  • 两者都有 → 先执行规范工作流,然后使用代码阅读步骤对照规范图验证实现,并使用 ⚠️ 标注任何差异
  • 不明确 → 询问用户:“这是源代码文件、规范文档,还是两者都有?”

步骤 1:定位协议入口

使用 Grep 搜索能够揭示协议的函数名、类型名和注释:

# Find handshake, session, round, phase entry points
rg -l "handshake|session_init|round[_0-9]|setup|keygen|send_msg|recv_msg" {targetDir}

# Find crypto primitives in use
rg "sign|verify|encrypt|decrypt|dh|ecdh|kdf|hkdf|hmac|hash|commit|reveal|share" \
    {targetDir} --type-add 'src:*.{py,rs,go,ts,js,cpp,c}' -t src -l

从最高层级的编排函数开始阅读——也就是调用握手阶段或主协议循环的函数。

步骤 2:识别参与方和角色

从以下内容中提取参与方名称:

  • 结构体/类名称:Client、Server、Initiator、Responder、Prover、 Verifier、Dealer、Party、Coordinator
  • 承载角色状态的函数参数名称
  • 声明协议角色的注释
  • 用于设置双方或 N 方场景的测试夹具

将这些名称映射为 Mermaid participant 声明。使用简短易读的别名:

participant I as Initiator
participant R as Responder
步骤 3:追踪消息流

跟踪状态转换以及网络发送/接收操作。查找以下模式:

模式含义
send(msg) / recv()直接消息交换
serialize + transmit发送结构化消息
将返回值传递给另一方的函数逻辑消息(进程内)
round1_output → round2_input基于轮次的 MPC 步骤
名为 ephemeral_key、ciphertext、mac、tag 的结构体字段消息内容

对于进程内的协议实现(双方在同一进程中运行),如果函数调用边界在部署时对应网络边界,则将其视为逻辑消息发送。

步骤 4:标注密码学操作

在每个协议步骤中识别并标注:

操作图表标注
密钥生成Note over A: keygen(params) → pk, sk
DH / ECDHNote over A,B: DH(sk_A, pk_B)
KDF / HKDFNote over A: HKDF(ikm, salt, info)
签名Note over A: Sign(sk, msg) → σ
验证Note over B: Verify(pk, msg, σ)
加密Note over A: Enc(key, plaintext) → ct
解密Note over B: Dec(key, ct) → plaintext
承诺Note over A: Commit(value, rand) → C
哈希Note over A: H(data) → digest
秘密分享Note over D: Share(secret, t, n) → {s_i}
门限合并Note over C: Combine({s_i}) → secret

标注应简洁,使用数学简写,而非代码。

步骤 5:识别协议阶段

使用 rect 或 Note 块将消息步骤归入命名阶段:

常见阶段包括:

  • 设置/密钥生成:参与方密钥创建、可信设置、参数生成
  • 握手/初始化:临时密钥交换、随机数交换、版本协商
  • 身份验证:身份证明、证书交换、签名验证
  • 密钥派生:从共享秘密派生会话密钥
  • 数据传输/主协议:加密的应用数据交换
  • 结束/拆除:关闭会话、MAC 验证、中止处理

识别中止/错误路径,并使用 alt 块展示。


规范工作流(S1–S5)

当输入是规范文档而非源代码时,使用此路径。 完成 S1–S5 后,继续执行上述代码工作流中的步骤 6(生成 sequenceDiagram)和步骤 7(验证并交付)。

步骤 S1:读取规范

获取完整的规范文本:

  • 提供了文件路径 → 使用 Read 工具读取
  • 提供了 URL → 使用 WebFetch 获取
  • 直接粘贴了内容 → 根据对话上下文直接处理

然后识别规范格式,并阅读 references/spec-parsing-patterns.md 以获取针对该格式的提取指导:

格式特征
RFCRFC XXXX、MUST/SHALL/SHOULD、ABNF 语法、带章节编号的正文
学术论文/伪代码Algorithm X、Protocol X、Figure X、编号步骤、数学模式中的 ←/→
非正式文本编号列表、“A sends B ...”、自然语言描述
ProVerif (.pv)process、let、in(ch, x)、out(ch, msg)、!(复制)
Tamarin (.spthy)rule、--[ ]->、Fr(~x)、!Pk(A, pk)、In(m)、Out(m)

如果规范引用了已知的命名协议(TLS、Noise、Signal、X3DH、Double Ratchet、FROST),也请阅读 references/protocol-patterns.md,将其规范流程用作骨架,并补充规范中的具体细节。

步骤 S2:提取参与方和角色

识别所有协议参与者。查找:

  • 正文或伪代码中命名的角色:Alice、Bob、Client、Server、 Initiator、Responder、Prover、Verifier、Dealer、Party_i、 Coordinator、Signer
  • 章节标题:"Parties"、"Roles"、"Participants"、"Setup"、"Notation"
  • ProVerif:顶层的进程名称(let ClientProc(...)、let ServerProc(...))
  • Tamarin:规则名称和事实参数(例如 !Pk($A, pk)——$A 是一个参与方)

将每个角色映射为 Mermaid participant 声明。使用简短 ID 和描述性别名(参见命名约定: references/mermaid-sequence-syntax.md)。

步骤 S3:提取消息流

追踪每个参与方按什么顺序向谁发送消息。不同格式的提取模式:

RFC / 非正式说明:

  • 箭头表示法:A → B: msg、A -> B
  • 句式模式:"A sends B ..."、"B responds with ..."、"A transmits ..."、 "upon receiving X, B sends Y"
  • 编号步骤:按顺序提取,并根据上下文推断发送方和接收方

伪代码:

  • 带有显式 sender/receiver 参数的函数签名
  • send(party, msg) / receive(party) 调用
  • 在下一步中,作为另一方函数输入传递的返回值

ProVerif(.pv):

  • out(ch, msg)——在通道 ch 上发送
  • in(ch, x)——在通道 ch 上接收,并将消息绑定到 x
  • 匹配同一通道上的 out/in 对,以确定消息流
  • !(重复)表示能够处理多个会话的角色

Tamarin(.spthy):

  • In(m) 前提——接收消息 m
  • Out(m) 结论——发送消息 m
  • 规则名称和顺序揭示协议轮次
  • Fr(~x)——参与方生成的新鲜随机值
  • --[ Label ]-> 事实——安全注解,而非消息

保留顺序和轮次结构。在最终图示中,使用 par 块将并发发送(广播)归为一组。

步骤 S4:提取加密操作

针对每个协议步骤,识别执行的加密操作及执行该操作的参与方:

规范记法操作图示注解
keygen()、Gen(1^λ)密钥生成Note over A: keygen() → pk, sk
DH(a, B)、g^abDH / ECDHNote over A,B: DH(sk_A, pk_B)
KDF(ikm)、HKDF(...)密钥派生Note over A: HKDF(ikm, salt, info) → k
Sign(sk, m)、σ ← Sign签名Note over A: Sign(sk, msg) → σ
Verify(pk, m, σ)验证Note over B: Verify(pk, msg, σ)
Enc(k, m)、{m}_k加密Note over A: Enc(k, plaintext) → ct
Dec(k, c)解密Note over B: Dec(k, ct) → plaintext
H(m)、hash(m)哈希Note over A: H(data) → digest
Commit(v, r)、com承诺Note over A: Commit(value, rand) → C
ProVerif senc(m, k)对称加密Note over A: Enc(k, m) → ct
ProVerif pk(sk)公钥派生Note over A: pk = pk(sk)
ProVerif sign(m, sk)签名Note over A: Sign(sk, m) → σ

识别安全条件和中止路径:

  • 正文:"if verification fails, abort"、"only if ..."、"reject if ..."
  • 伪代码:assert、require、if ... abort
  • ProVerif:if m = expected then ... else 0
  • Tamarin:相互矛盾的事实或限制引理

这些内容应在最终图示中用 alt 块表示。

步骤 S5:标记规范中的歧义

进入步骤 6 之前,检查是否存在遗漏:

  • 消息顺序不明确:根据轮次结构或章节顺序推断; 添加注释 ⚠️ ordering inferred from spec structure
  • 隐含参与方:如果某一方的角色虽有暗示但未命名,请为其指定一个 描述性名称,并注明这是推断
  • 缺少步骤:如果规范省略了该协议的规范模式所要求的某个步骤,请添加注释: ⚠️ spec omits [step] — canonical protocol requires it
  • 加密方案未充分说明:如果规范仅写了“加密”,却未指定方案,请添加注释:⚠️ encryption scheme not specified
  • ProVerif/Tamarin:私有信道(用 new c 声明的 c,或作为私有自由名称的 c)表示带外信道 — 请注明

步骤 6:生成 sequenceDiagram

按照 references/mermaid-sequence-syntax.md 中的规则生成 Mermaid 语法。

完整性优先于简洁性。 展示每种不同的消息类型。省略重复的 循环迭代(改用 loop 块),但绝不要省略不同的协议步骤。

正确性优先于美观。 图表必须与代码的实际行为一致。如果代码与已知规范不符,请注明这种差异:

Note over A,B: ⚠️ spec requires MAC here — implementation omits it
步骤 7:验证并交付

交付之前:

  • 每个已声明的参与方都实际发送或接收了至少一条消息
  • 箭头方向正确(发送方 → 接收方)
  • 加密操作位于正确的一方(执行计算的一方)
  • 如果使用了协议阶段,阶段块之外不得出现箭头
  • alt 块涵盖已知的中止/错误路径
  • 图表渲染时没有语法错误(检查 references/mermaid-sequence-syntax.md 以了解常见问题)
  • 如果发现与规范不符之处,已添加 ⚠️ 注释

将图表写入文件。 选择一个根据协议名称生成的文件名,例如 noise-xx-handshake.md 或 x3dh-key-agreement.md。编写 Markdown 文件,结构如下:

# <Protocol Name> Sequence Diagram

\`\`\`mermaid
sequenceDiagram
    ...
\`\`\`

## Protocol Summary

- **Parties:** ...
- **Round complexity:** ...
- **Key primitives:** ...
- **Authentication:** ...
- **Forward secrecy:** ...
- **Notable:** [spec deviations or security observations, or "none"]

写入文件后,在回复中内联打印一份 ASCII 时序图,然后附上协议摘要。注明输出文件名,让用户知道在哪里可以找到 Mermaid 源文件。

遵循 references/ascii-sequence-diagram.md 中的所有绘图约定,包括内联输出格式。


决策树

── Input is a spec document (not code)?
│  └─ Step S1: identify format, read references/spec-parsing-patterns.md
│
── Input is source code (not a spec)?
│  └─ Step 1: grep for handshake/round/send/recv entry points
│
── Both spec and code provided?
│  └─ Run Spec Workflow (S1–S5) first to build canonical diagram,
│     then read code and annotate divergences with ⚠️
│
── Spec is a known protocol (TLS, Noise, Signal, X3DH, FROST)?
│  └─ Read references/protocol-patterns.md and use canonical flow as skeleton
│
── Spec is ProVerif (.pv) or Tamarin (.spthy)?
│  └─ Read references/spec-parsing-patterns.md → Formal Models section
│
── Spec message ordering is ambiguous?
│  └─ Infer from round/section structure, annotate with ⚠️
│
── Can't identify parties from spec?
│  └─ Check "Parties"/"Notation" sections; for ProVerif read process names;
│     for Tamarin read rule names and fact arguments
│
── Don't know which code files implement the protocol?
│  └─ Step 1: grep for handshake/round/send/recv entry points
│
── Can't identify parties from struct names?
│  └─ Read test files — test setup reveals roles
│
── Protocol runs in-process (no network calls)?
│  └─ Treat function argument passing at role boundaries as messages
│
── MPC / threshold protocol with N parties?
│  └─ Read references/protocol-patterns.md → MPC section
│
── Mermaid syntax error?
│  └─ Read references/mermaid-sequence-syntax.md → Common Pitfalls
│
└─ ASCII drawing conventions?
   └─ Read references/ascii-sequence-diagram.md

示例

代码路径 — examples/simple-handshake/:

  • protocol.py — 双方认证密钥交换(X25519 DH + Ed25519 签名 + HKDF + ChaCha20-Poly1305)
  • expected-output.md — 该协议对应的完整 ASCII 图和 Mermaid 文件, 也是该技能应生成的内容

规范路径(ProVerif) — examples/simple-proverif/:

  • model.pv — 在 ProVerif 中建模的 HMAC 挑战-响应认证
  • expected-output.md — 逐步提取说明(参与方、 消息流、加密操作),以及该技能应生成的准确 ASCII 图和 Mermaid 文件

处理不熟悉的输入之前,请先研究相关示例。


配套文档

评论

支持 Markdown