返回首页

AI 和 Meyer Contracts:在生产前捕获加密 Bug

文章演示了如何将 Design by Contract 与 AI 代理结合使用,从而在生产发布前检测加密系统中的关键逻辑错误。以带有硬件 TRNG 的 PKI 为例,展示了两个漏洞的检测,这些漏洞会被传统测试遗漏。

AI + Meyer Contracts:如何防止加密灾难
Advertisement 728x90

# AI 代理与契约式设计如何在生产前捕获加密漏洞

AI 代理正在彻底改变开发安全系统的格局:它们不是手动编写代码和测试,而是基于形式化契约生成实现。这消除了契约式设计失败的主要原因——双倍工作量。在一个集成了硬件 TRNG 和 PKI 的项目中,两个关键漏洞正是通过契约测试精准捕获,而普通单元测试根本会漏掉。

为什么测试会漏掉密码学中的逻辑错误

测试只能检查程序员想到的情况。如果他们没想到要验证 RSA 中的填充,或者在输入 DRBG 前检查熵质量——测试就不会自己写出来。这就是 OpenBSD 中一个 27 年的 bug 和 FFmpeg 中一个 16 年的漏洞如何逃过数百万自动化检查的原因。编译器和静态分析工具对逻辑错误无能为力:选择错误的加密模式、跳过证书吊销检查、使用过时标准——这些都悄无声息地逃过它们的侦测。

核心问题:测试是对实现的反应,而不是意图。契约在任何代码编写前就捕捉意图。它们设定边界:系统必须做什么(后置条件)、什么被禁止(不变量),以及在什么条件下可以调用(前置条件)。这不仅仅是文档——而是可执行规范。

Google AdInline article slot

契约式方法的不同之处在于:

  • 正式性:PRE/POST/INV 以机器可读形式编写,而不是注释。
  • 早期检测:契约违反立即失败,而不是在生产环境中。
  • 聚焦保证:不是“如何工作”——而是“什么被保证”。
  • 单一真相来源:开发过程中契约不变;只有需求变更时才更新。

AI 代理如何处理后半部分工作

契约式设计在主流中失败,是因为双倍工作量:先写契约,再写代码,然后写测试。在截止期限压力下,契约首当其冲被牺牲。今天,AI 代理接管实现和测试生成,只留给人类制定契约。这改变了经济学:一行契约取代数百行代码和测试。

流程如下:

Google AdInline article slot
  • 人类编写不变量:padding == RSA-PSS | RSA-OAEP; PKCS#1 v1.5 == FORBIDDEN
  • 代理生成 CryptoEngine 模块,只使用允许的填充。
  • 同时,代理创建契约测试,尝试使用 PKCS#1 v1.5 并期望抛出异常。
  • 如果测试失败——代理修复实现,而不碰契约。
  • 人类只审查 10 行契约,而不是 1000 行代码。

优势:

  • 速度:全栈嵌入式项目只需 11 天活跃工作,而不是数月。
  • 可靠性:契约是焦点;其中的错误比代码中更容易发现。
  • 可扩展性:一人管理不同角色的代理(编码者、测试者、架构师)。

真实案例:集成硬件 TRNG 和契约测试的 PKI

pki-on-box 项目包含五个模块:STM32G431(硬件 TRNG)、Python 守护进程(符合 NIST SP 800-90A 的 DRBG)、CryptoEngine(密钥生成)、KeyStorage(AES-256-GCM)、CA 服务(X.509 签名)。每个模块在接口处都有形式化契约。部署前发现了两个关键漏洞:

  • 错误填充:实现意外使用了 PKCS#1 v1.5 而非 RSA-PSS。Bleichenbacher 攻击可通过填充预言机恢复明文——契约测试立即失败。
  • 错误 AES 模式:选择了 ECB 而非 GCM。契约要求认证加密——测试再次失败。

项目指标:

Google AdInline article slot
  • 131 次提交
  • 62 个契约测试 + 15 个硬件测试
  • 3 块 MCU 板(STM32G474、G431、H750)
  • 目标平台:RK3328 ARM64
  • AI 成本:1780₽(30 次会话)
  • 公开仓库:github.com/vasilievsv/hw.pki-on-box

接口处的契约:关键错误产生之地

逻辑错误发生在模块边界。DRBG 输出字节——CryptoEngine 必须知道如何使用。没有契约——有人从 StackOverflow 示例中随便挑填充。项目中的两个关键契约如下:

contract: key_generation
  PRE:
    - DRBG.seeded == true
    - algorithm ∈ {RSA-2048, ECDSA-P384}
  POST:
    - private_key.encrypted(AES-256-GCM)
    - public_key = derive(private_key)
  INV:
    - padding == RSA-PSS | RSA-OAEP
    - PKCS#1 v1.5 == FORBIDDEN
contract: certificate_issuance
  PRE:
    - issuer_ca.valid() && !revoked()
    - csr.signature.verify() == true
  POST:
    - cert.serial.unique()
    - cert.signature.verify(issuer_ca.public_key) == true
  INV:
    - root_ca.offline == true
    - cert_chain.depth <= max_path_length

填充的契约测试:

def test_rejects_pkcs1v15_padding(self, crypto):
    priv, pub = crypto.generate_rsa_keypair(bits=2048)
    data = b"invariant check"
    sig = crypto.sign_data(priv, data)
    # PSS must rabotat
    pub.verify(sig, data, padding.PSS(...))
    # PKCS1v15 must slomatsya
    with pytest.raises(Exception):
        pub.verify(sig, data, padding.PKCS1v15(), hashes.SHA256())

该测试不检查功能——它验证不变量遵守。如果填充变更——测试失败,即使签名“技术上有效”。

关键收获

  • 契约 > 测试:测试检查实现;契约检查意图。只有通过形式化保证才能捕获逻辑错误。
  • AI 消除双倍工作:代理从契约生成代码和测试;人类专注规范。
  • 边界处的关键错误:填充、加密模式、吊销检查——全由模块接口的不变量控制。
  • 公开验证:带有硬件 TRNG 和契约测试的项目在公开仓库中供审计。
  • 时间经济学:全栈嵌入式系统只需 11 天而非数月——得益于角色分工和自动生成。

— Editorial Team

Advertisement 728x90

继续阅读