跳到主要内容
ecdsa.com
Rust

aws-lc-rs

AWS 的 aws-lc-rs,构建在 AWS-LC C 库之上、与 ring 兼容的 Rust API:FIXED/ASN1 编码常量与 ring 相同,稳定 API 中还提供 P-521、secp256k1、ML-KEM 和 ML-DSA,并可选用 FIPS 140-3 构建。
许可证
ISC AND (Apache-2.0 OR ISC)
检查的版本
1.18.2 ·
源代码
github.com/aws/aws-lc-rs
文档
docs.rs/aws-lc-rs/1.18.2/aws_lc_rs/

兼容性概览

ECDSAEdDSA后量子

ECDSA 曲线
P-256P-384P-521secp256k1
EdDSA
Ed25519
后量子算法
ML-KEMML-DSA
公钥格式
spki-dersec1-uncompressedsec1-compressed
私钥格式
pkcs8-dersec1-derraw-scalar

aws-lc-rs 通过一套仿照 ring 设计的 API 提供 AWS-LC(Amazon 维护的 BoringSSL 分支)的功能,因此大多数 ring 代码只需改掉 crate 名称即可编译。它是 rustls 的默认密码学提供程序;Rust 服务需要 FIPS 140-3 认证(fips 特性)或后量子算法时,通常会选用它。C 库在构建过程中编译;本次检查在普通的 rust 镜像中以默认特性构建了 1.18.2。

签名编码与 ring 完全一致:*_FIXED 常量生成并接受 64 字节的原始 r‖s,*_ASN1 常量对应 DER;在 ASN1 验证常量下,原始签名验证失败。nonce 是随机的,s 不做规范化,验证时 high-S 和 low-S 都接受。除了 ring 已有的 P-256 和 P-384,它还能在 P-521 和 secp256k1 上签名和验证,并提供 SHA-2 和 SHA-3 变体。

在 1.18.2 中,后量子算法属于稳定 API——本次检查没有启用 unstable 特性:aws_lc_rs::kem 中有 ML-KEM-512、ML-KEM-768 和 ML-KEM-1024,aws_lc_rs::signature 中有 ML-DSA-44、ML-DSA-65 和 ML-DSA-87,示例用到了这两个模块。示例输出的大小——ML-DSA-65 的公钥为 1952 字节、签名为 3309 字节,ML-KEM-768 的密文为 1088 字节——正是证书、令牌和握手必须承载的数据量;后量子签名工具和 KEM 工具会把它们与经典算法对比。

密钥加载支持的格式比 ring 更多:ECDSA 密钥可以从 PKCS#8、SEC1(RFC 5915)DER 以及原始标量加其公钥加载;公钥可以从 SPKI DER 和 SEC1 点加载,压缩与否均可。与 ring 不同,Ed25519KeyPair::from_pkcs8 接受了 OpenSSL 写出的 48 字节 PKCS#8 v1 格式。

怀疑 FIXED/ASN1 不匹配时,可使用 DER ⇄ 原始格式转换器;混合后量子密钥交换的设置可以用 TLS 配置生成器生成。

事实及其依据的检查

以下内容均非抄自文档。检查脚本 content/libraries/verify/aws-lc-rs/run.sh 于2026年10月20日在容器镜像 rust:1.99.1-trixie 中运行了 aws-lc-rs 1.18.2;本页内容必须与它的输出一致,每条事实都列出了对应的输出行。

  • ECDSA 签名编码

    der-or-raw

    *_FIXED 常量生成 64 字节的原始 r‖s 签名,*_ASN1 常量生成 DER 签名;原始签名在 ASN1 常量下没有验证通过。

    检查记录
    fact ecdsa-signature-encoding = der-or-raw
    evidence ecdsa-signature-encoding: FIXED signs 64 bytes; the same bytes verify under the ASN1 constant: false
  • ECDSA 的 nonce

    random

    随机 nonce:同一条消息的两个签名不同。

    检查记录
    fact ecdsa-nonce = random
  • 签名时的 low-S

    either

    s 没有经过规范化:64 个签名中出现了 high-S 值。

    检查记录
    fact ecdsa-low-s-sign = either
  • 验证时的 high-S

    accepts-high-s

    FIXED 验证器接受了把 s 替换为 n − s 的签名。

    检查记录
    fact ecdsa-low-s-verify = accepts-high-s
  • 签名调用对哪些内容做哈希

    hashes-message

    消息按常量所指定的算法计算哈希(SHA-2 或 SHA-3 变体)。

    检查记录
    fact ecdsa-prehash = hashes-message
  • 格式错误的 ECDSA 签名

    returns-error

    对于格式错误或不正确的签名,验证返回错误值。

    检查记录
    fact ecdsa-malformed-signature = returns-error
  • ECDSA 曲线

    P-256P-384P-521secp256k1

    P-256、P-384、P-521 和 secp256k1 的签名与验证均成功。

    检查记录
    fact ecdsa-curves = P-256, P-384, P-521, secp256k1
  • EdDSA

    Ed25519

    Ed25519。

    检查记录
    fact eddsa = Ed25519
  • Ed25519 PKCS #8 v1 密钥

    accepted

    Ed25519KeyPair::from_pkcs8 接受了 48 字节的 PKCS#8 v1 Ed25519 密钥,而 ring 会拒绝这种密钥。

    检查记录
    fact ed25519-pkcs8-v1 = accepted
    evidence ed25519-pkcs8-v1: 48-byte PKCS#8 v1 Ed25519 key with from_pkcs8: Ok("ok")
  • 后量子算法

    ML-KEMML-DSA

    在未启用 unstable 特性的构建中,ML-KEM-512/768/1024 的封装与解封装、ML-DSA-44/65/87 的签名与验证均成功。

    检查记录
    fact pqc = ML-KEM, ML-DSA
    evidence pqc: ML-KEM-512/768/1024 via aws_lc_rs::kem; ML-DSA-44/65/87 via aws_lc_rs::signature
  • 公钥格式

    spki-dersec1-uncompressedsec1-compressed

    通过 ParsedPublicKey 加载 SPKI DER,也支持压缩或未压缩的 SEC1 点。

    检查记录
    fact public-key-formats = spki-der, sec1-uncompressed, sec1-compressed
  • 私钥格式

    pkcs8-dersec1-derraw-scalar

    PKCS#8 DER、SEC1(RFC 5915)DER,以及原始标量连同其公钥。

    检查记录
    fact private-key-formats = pkcs8-der, sec1-der, raw-scalar

用法

用 ML-DSA-65 签名并验证,执行一次 ML-KEM-768 封装,并输出密钥、签名和密文的大小。
use aws_lc_rs::kem::{DecapsulationKey, ML_KEM_768};
use aws_lc_rs::signature::{self, KeyPair, PqdsaKeyPair, UnparsedPublicKey};

fn main() {
    // ML-DSA-65 (FIPS 204) through the stable signature API.
    let key = PqdsaKeyPair::generate(&signature::ML_DSA_65_SIGNING).unwrap();
    let message = b"release v2.0 manifest";
    let mut sig = vec![0u8; signature::ML_DSA_65_SIGNING.signature_len()];
    let len = key.sign(message, &mut sig).unwrap();
    let ok = UnparsedPublicKey::new(&signature::ML_DSA_65, key.public_key().as_ref()).verify(message, &sig[..len]);
    println!("ML-DSA-65: public key {} bytes, signature {len} bytes, verified {}", key.public_key().as_ref().len(), ok.is_ok());

    // ML-KEM-768 (FIPS 203): the receiver publishes the encapsulation key.
    let receiver = DecapsulationKey::generate(&ML_KEM_768).unwrap();
    let (ciphertext, sender_secret) = receiver.encapsulation_key().unwrap().encapsulate().unwrap();
    let receiver_secret = receiver.decapsulate(ciphertext.as_ref().into()).unwrap();
    println!("ML-KEM-768: ciphertext {} bytes, shared secrets match {}", ciphertext.as_ref().len(), sender_secret.as_ref() == receiver_secret.as_ref());
}

代码片段测试工具会在容器镜像 rust:1.99.1-trixie 中原样运行每个示例,只要输出不匹配,运行就会失败。

命令
cargo run --quiet --release
输出必须匹配(正则表达式)
ML-DSA-65: public key 1952 bytes, signature 3309 bytes, verified true\nML-KEM-768: ciphertext 1088 bytes, shared secrets match true

库