Skip to main content

ferritls_backend_x86_64/
lib.rs

1//! # ferritls-backend-x86_64
2//!
3//! [`ferritls-core`] 的 x86_64 硬件执行核心(AES-NI + CLMUL GHASH +
4//! SHA-NI)。**FIPS 边界外** crate(docs/FIPS.md §1),仅 x86_64——
5//! 其余目标编译为空 crate。
6//!
7//! ## 用法
8//!
9//! ```no_run
10//! # fn main() -> Result<(), ferritls_core::Error> {
11//! #[cfg(target_arch = "x86_64")]
12//! {
13//!     // 进程初始化阶段(构造任何密钥之前)一次性安装。本 crate 仅
14//!     // x86_64 有内容,其他目标上此块被裁掉、示例仍然可编译。
15//!     ferritls_backend_x86_64::install()?;
16//! }
17//! // 此后 ferritls_core::gcm::{Aes128Gcm, Aes256Gcm} 的新实例走
18//! // AES-NI/CLMUL 路径;已构造的实例与未安装的环境不受影响。
19//! # Ok(())
20//! # }
21//! ```
22//!
23//! 安装语义(详见 [`ferritls_core::ops`] 模块文档):
24//!
25//! - 探测 `aes` + `pclmulqdq`,任一缺失返回
26//!   [`Unsupported`](ferritls_core::Error::Unsupported)(不降级、不安装);
27//! - 安装前在本 crate 的执行核心上跑 McGrew–Viega TC5/TC16 已知答案
28//!   自检,失败返回 [`SelfTestFailed`](ferritls_core::Error::SelfTestFailed)
29//!   并拒绝安装;
30//! - 批准模式(`ferritls-core` 以 `fips` feature 构建)下 core 拒绝一切
31//!   安装,软件路径固定;
32//! - 进程级一次,重复安装由 core 拒绝。
33//!
34//! ## unsafe 纪律(借鉴 fearless_simd 的模式,零依赖自建)
35//!
36//! crate 根 `#![deny(unsafe_code)]`;unsafe 只存在于唯一叶子模块
37//! [`raw`](self)(仅内存读写包装)与各 kernel 的进入点 trampoline
38//! (`new`/`seal`/`open` 与 SHA 的压缩函数注册点)。kernel 本体标注
39//! `#[target_feature(enable = ...)]` 并在上下文内直调 intrinsic(安全、
40//! 编译为裸指令)——从无 feature 上下文包装调用会因 feature 不匹配
41//! 被禁止内联,每个调用退化为真实函数调用(见 ARCHITECTURE.md §4)。
42//! CPU 能力以 [`AesNi`] token 进入类型系统:token 只能经运行时探测
43//! 构造(其 clone 同样源自一次成功探测),是进入 trampoline 的安全
44//! 论证。除 trampoline 外的全部代码均为安全代码。
45//!
46//! 常数时间:AES/GCM 指令为固定延迟、数据无关;kernel 内无以秘密为
47//! 条件的分支或访存(轮密钥按公开轮号索引);标签比较统一由 core 的
48//! 公开类型完成(本 crate 只计算、不比较)。
49//!
50//! [`ferritls-core`]: https://docs.rs/ferritls-core
51
52#![cfg(target_arch = "x86_64")]
53#![deny(unsafe_code)]
54
55mod gcm;
56mod raw;
57mod sha;
58mod token;
59
60use std::sync::OnceLock;
61
62use ferritls_core::ops;
63
64pub use token::{AesNi, ShaNi};
65
66/// 后端单例(唯一向 core 注册的对象)。
67struct Backend {
68    /// 探测成功后由 [`install`] 写入;注册引用只会在写入之后交给 core,
69    /// 工厂方法读取时的 [`None`] 属内部不变式破坏。
70    tok: OnceLock<AesNi>,
71}
72
73static BACKEND: Backend = Backend {
74    tok: OnceLock::new(),
75};
76
77impl ops::AeadOps for Backend {
78    fn name(&self) -> &'static str {
79        "aesni-clmul"
80    }
81
82    fn aes128_gcm(&self, key: &[u8; 16]) -> Box<dyn ops::AeadGcm> {
83        let tok = self
84            .tok
85            .get()
86            .expect("backend token set before registration");
87        Box::new(gcm::NiGcm::<11>::new(tok, key))
88    }
89
90    fn aes256_gcm(&self, key: &[u8; 32]) -> Box<dyn ops::AeadGcm> {
91        let tok = self
92            .tok
93            .get()
94            .expect("backend token set before registration");
95        Box::new(gcm::NiGcm::<15>::new(tok, key))
96    }
97}
98
99/// 探测 AES-NI + CLMUL(不安装)。
100///
101/// 供需要自定义装配/诊断的调用方使用;常规路径直接 [`install`]。
102pub fn detect() -> Option<AesNi> {
103    AesNi::detect()
104}
105
106/// SHA-256 后端单例(函数分发形态:唯一状态是能力证明)。
107struct ShaBackend {
108    tok: OnceLock<ShaNi>,
109}
110
111static SHA_BACKEND: ShaBackend = ShaBackend {
112    tok: OnceLock::new(),
113};
114
115impl ferritls_core::ops::HashOps for ShaBackend {
116    fn name(&self) -> &'static str {
117        "sha-ni"
118    }
119
120    fn sha256_compress(&self) -> ferritls_core::ops::Sha256Compress {
121        let tok = self
122            .tok
123            .get()
124            .expect("sha-ni token set before registration");
125        tok.sha256_compress()
126    }
127}
128
129/// 探测 SHA 扩展 → KAT 自检 → 安装 SHA-256 压缩后端(进程级一次)。
130///
131/// 语义同 [`install`]:CPU 不支持 / KAT 失败 / 批准模式 / 重复安装
132/// 分别以对应错误拒绝。与 [`install`] 相互独立(CPU 可能只具备其一)。
133pub fn install_hash() -> Result<(), ferritls_core::Error> {
134    let tok = ShaNi::detect().ok_or(ferritls_core::Error::Unsupported)?;
135    sha::power_up_kat(&tok)?;
136    let _ = SHA_BACKEND.tok.set(tok);
137    ferritls_core::ops::install_hash(&SHA_BACKEND)
138}
139
140/// 探测 → 上电 KAT 自检 → 安装到 ferritls-core(进程级一次)。
141///
142/// CPU 不支持返回 [`Unsupported`](ferritls_core::Error::Unsupported);
143/// KAT 失败返回 [`SelfTestFailed`](ferritls_core::Error::SelfTestFailed);
144/// 批准模式或重复安装由 core 拒绝(同样表现为
145/// [`Unsupported`](ferritls_core::Error::Unsupported))。
146pub fn install() -> Result<(), ferritls_core::Error> {
147    let tok = AesNi::detect().ok_or(ferritls_core::Error::Unsupported)?;
148    gcm::power_up_kat(&tok)?;
149    let _ = BACKEND.tok.set(tok);
150    ops::install(&BACKEND)
151}