aegis-aead/libaegis
GitHub: aegis-aead/libaegis
AEGIS 系列高性能认证加密算法的便携式 C 语言实现,提供 AEAD 加密、MAC、加密随机访问文件等完整功能。
Stars: 129 | Forks: 29
# libaegis
[AEGIS](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aegis-aead/) 系列高性能认证加密算法(AEGIS-128L、AEGIS-128X2、AEGIS-128X4、AEGIS-256、AEGIS-256X2、AEGIS-256X4)的便携式 C 语言实现,支持运行时 CPU 检测。
## 功能特性
- AEGIS-128L,支持 16 和 32 字节标签(软件、AES-NI、ARM Crypto、Altivec)
- AEGIS-128X2,支持 16 和 32 字节标签(软件、VAES + AVX2、AES-NI、ARM Crypto、Altivec)
- AEGIS-128X4,支持 16 和 32 字节标签(软件、AVX512、VAES + AVX2、AES-NI、ARM Crypto、Altivec)
- AEGIS-256,支持 16 和 32 字节标签(软件、AES-NI、ARM Crypto、Altivec)
- AEGIS-256X2,支持 16 和 32 字节标签(软件、VAES + AVX2、AES-NI、ARM Crypto、Altivec)
- AEGIS-256X4,支持 16 和 32 字节标签(软件、AVX512、VAES + AVX2、AES-NI、ARM Crypto、Altivec)
- AEGIS-MAC 的所有变体,支持增量更新。
- 带有附加标签和分离标签的加密与解密。
- 增量加密与解密。
- 用于构建加密文件系统和数据库的随机访问加密文件 API (RAF)。
- 无认证的加密与解密(不推荐 - 仅针对特定协议实现)。
- 确定性伪随机流生成。
## 安装
请注意编译器的选择会有所不同。与 `gcc` 相比,Zig(或带有 `-march=native` 等特定目标选项的最新版 `clang`)能生成更高效的代码。
### 使用 `zig` 编译
```
zig build -Drelease
```
要使用 `-Dlinkage` 选项将库构建为共享对象:
```
zig build -Dlinkage=dynamic -Drelease
```
库和头文件将安装在 `zig-out` 文件夹中。
为了在没有硬件加速的设备上优先考虑性能而非侧信道缓解措施,请添加 `-Dfavor-performance`:
```
zig build -Drelease -Dfavor-performance
```
还可以使用 `-Dwith-benchmark` 选项构建基准测试:
```
zig build -Drelease -Dfavor-performance -Dwith-benchmark
```
`libaegis` 不需要 WASI 或任何扩展即可在 WebAssembly 上运行。完全支持 `wasm32-freestanding` 目标。
可以通过在命令行中添加 `-Dcpu=baseline+bulk_memory+simd128` 来启用诸如 `bulk_memory` 和 `simd128` 等 WebAssembly 扩展。
### 使用 `cmake` 编译
```
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/install/prefix ..
make install
```
要将库构建为共享库,请添加 `-DBUILD_SHARED_LIBS=On`。
为了在没有硬件加速的设备上优先考虑性能而非侧信道缓解措施,请添加 `-DFAVOR_PERFORMANCE`。
### 直接包含
将 `src` 目录中的所有内容直接复制到您的项目中,并像编译常规 C 代码一样编译它们。不需要特殊配置。
## 用法
包含 `` 并在使用该库执行任何其他操作之前调用 `aegis_init()`。
`aegis_init()` 会检查 CPU 功能,以便后续使用最快的实现。
### 加密和解密消息
```
#include
#include
int main(void) {
aegis_init();
/* Use a secure random number generator for key and nonce. */
uint8_t key[aegis256_KEYBYTES]; /* 32 bytes */
uint8_t nonce[aegis256_NPUBBYTES]; /* 32 bytes */
memset(key, 0x42, sizeof key);
memset(nonce, 0x00, sizeof nonce);
const char *message = "hello, world";
size_t message_len = strlen(message);
/* Encrypt (detached mode: ciphertext and tag are separate) */
uint8_t ciphertext[128]; /* must be at least message_len bytes */
uint8_t tag[32]; /* 256-bit authentication tag */
aegis256_encrypt_detached(ciphertext, tag, sizeof tag,
(const uint8_t *) message, message_len,
NULL, 0, /* no additional data */
nonce, key);
/* Decrypt and verify */
uint8_t decrypted[128]; /* must be at least message_len bytes */
if (aegis256_decrypt_detached(decrypted, ciphertext, message_len,
tag, sizeof tag,
NULL, 0,
nonce, key) != 0) {
/* Authentication failed: the data was tampered with */
return 1;
}
/* decrypted now contains the original message */
return 0;
}
```
一次性调用的 `aegis256_encrypt()` / `aegis256_decrypt()` 函数的工作方式相同,但会将标签附加到密文之后,因此输出缓冲区的大小必须是 `message_len + maclen` 字节。
所有六个变体都遵循相同的 API 模式——只需交换前缀(`aegis128l_`、`aegis256_`、`aegis128x2_` 等)并调整密钥/nonce 大小即可。
### 计算 MAC
AEGIS 也可用作独立的消息认证码。MAC API 支持增量更新,因此您可以分块输入数据。
```
#include
#include
int main(void) {
aegis_init();
uint8_t key[aegis256_KEYBYTES];
memset(key, 0x42, sizeof key);
/* Initialize the MAC state (NULL nonce = all zeros) */
aegis256_mac_state st;
aegis256_mac_init(&st, key, NULL);
/* Feed data in one or more chunks */
aegis256_mac_update(&st, (const uint8_t *) "hello, ", 7);
aegis256_mac_update(&st, (const uint8_t *) "world", 5);
/* Finalize and get the 256-bit tag */
uint8_t tag[32];
aegis256_mac_final(&st, tag, sizeof tag);
return 0;
}
```
加密和 MAC 不能使用相同的密钥。如果您需要使用相同的密钥认证多个消息,请使用 `aegis256_mac_state_clone()` 克隆已初始化的状态,或者使用 `aegis256_mac_reset()` 重置状态,而不是重新初始化。
### 随机访问文件 API
RAF(随机访问文件)API 允许您像操作常规文件一样自然地操作加密文件。读取任何字节范围、在任意位置写入、随意扩展或截断,所有这些都带有完整的加密和认证。文件可以任意大,而无需将其完全加载到内存中。这使得构建加密文件系统、数据库或任何需要就地修改加密数据而无需重新加密整个文件的应用程序变得非常简单。
```
#include
// Allocate scratch buffer (can be stack, heap, or static)
CRYPTO_ALIGN(64) uint8_t scratch_buf[AEGIS128L_RAF_SCRATCH_SIZE(4096)];
aegis_raf_scratch scratch = { .buf = scratch_buf, .len = sizeof scratch_buf };
aegis128l_raf_ctx ctx;
aegis_raf_config cfg = { .scratch = &scratch, .chunk_size = 4096, .flags = AEGIS_RAF_CREATE };
aegis_raf_io io = { /* your I/O callbacks */ };
aegis_raf_rng rng = { /* your RNG callback */ };
aegis128l_raf_create(&ctx, &io, &rng, &cfg, master_key);
aegis128l_raf_write(&ctx, &written, data, len, offset);
aegis128l_raf_read(&ctx, buf, &bytes_read, len, offset);
aegis128l_raf_close(&ctx); // automatically calls sync
```
该 API 需要可插拔的 I/O(`read_at`、`write_at`、`get_size`、`set_size`、`sync`)和 RNG 回调,使其适用于任何存储后端。调用者提供一个供内部使用的临时缓冲区,从而实现零分配操作。
要打开现有文件,请使用 `aegis_raf_probe()` 读取文件的算法和块大小,然后分配正确的临时缓冲区并调用匹配的 `*_raf_open()`:
```
aegis_raf_info info;
aegis_raf_probe(&io, &info); // reads alg_id, chunk_size, file_size
// Use info.alg_id to select the variant and info.chunk_size to size the scratch buffer.
// This example assumes AEGIS-128L with a known max chunk size of 4096:
CRYPTO_ALIGN(64) uint8_t scratch_buf[AEGIS128L_RAF_SCRATCH_SIZE(4096)];
aegis_raf_scratch scratch = { .buf = scratch_buf, .len = sizeof scratch_buf };
aegis_raf_config cfg = { .scratch = &scratch };
aegis128l_raf_ctx ctx;
aegis128l_raf_open(&ctx, &io, &rng, &cfg, master_key);
```
#### 上下文绑定的密钥派生(可选)
跨多个 RAF 文件或文件族使用相同主密钥的应用程序,可以通过 `aegis_raf_derive_master_key()` 派生上下文绑定的子密钥。不同的上下文会产生不同的 RAF 密钥,从而隔离文件而无需单独的主密钥。
```
uint8_t raf_key[16];
aegis_raf_derive_master_key(raf_key, sizeof raf_key,
app_master_key, sizeof app_master_key,
(const uint8_t *) "my-context", 10);
aegis128l_raf_create(&ctx, &io, &rng, &cfg, raf_key);
// caller is responsible for zeroizing raf_key after use
```
对于 128 位密钥变体,上下文最多可达 120 字节;对于 256 位密钥变体,最多可达 72 字节。线缆格式保持不变——上下文绑定纯粹是一项密钥管理功能。打开文件需要与创建文件时相同的上下文;错误或缺失的上下文将导致头部认证失败,就像密钥错误一样。
#### Merkle 树(可选)
每个数据块已通过其 AEAD 标签进行独立认证,因此基本的完整性始终得到保证。可选的 Merkle 树是一个独立的特性,它维护对整个文件明文内容的实时哈希承诺,并在写入数据块或截断文件时进行增量更新。当您需要一个代表整个文件当前状态的单个摘要时(例如,向远程方证明文件内容、检测带外修改(通过与先前存储的承诺进行比较)或将文件锚定在外部数据结构中),这非常有用。
大多数应用程序不需要此功能,可以在没有它的情况下使用 RAF API。
叶节点值来自于您对明文块数据的 `hash_leaf` 回调。它们不是 RAF 每个块的 AEAD 认证标签。
通过依赖 `chunk`、`chunk_len` 和 `chunk_idx` 来保持叶节点哈希的稳定性。
`aegis128l_raf_merkle_commitment()` 返回一个上下文绑定的承诺,其中包含文件的内容、版本、算法、块大小和标识,以及结构树根和文件大小。
```
// Provide hash callbacks and a caller-allocated buffer
aegis_raf_merkle_config merkle = {
.hash_leaf = my_hash_leaf, // hash plaintext chunk data (not the RAF auth tag)
.hash_parent = my_hash_parent, // combine two child digests
.hash_empty = my_hash_empty, // digest for missing/empty nodes
.hash_commitment = my_hash_commitment, // hash(root, ctx, file_size)
.hash_len = 32, // digest size (8..64 bytes)
.max_chunks = 1024,
.buf = merkle_buf,
.len = sizeof merkle_buf,
};
// Pass merkle config when creating the RAF context
aegis_raf_config cfg = {
.scratch = &scratch, .chunk_size = 4096,
.flags = AEGIS_RAF_CREATE, .merkle = &merkle,
};
// After writes, verify Merkle state against current file contents or read the root commitment
aegis128l_raf_merkle_verify(&ctx, &corrupted_chunk);
uint8_t root[32];
aegis128l_raf_merkle_commitment(&ctx, root, sizeof root);
```
该树使用带有可配置哈希回调的扁平缓冲区布局,因此它适用于任何哈希函数。`aegis_raf_merkle_buffer_size()` 用于计算给定 `max_chunks` 和 `hash_len` 所需的缓冲区大小。
## 绑定
- [`aegis`](https://crates.io/crates/aegis) 包含 Rust 绑定。
- [`pyaegis`](https://github.com/jedisct1/pyaegis)(`pip install pyaegis`)是一组 Python 绑定。
- [`go-libaegis`](https://github.com/aegis-aead/go-libaegis) 是一组 Go 绑定。
## Libaegis TLS 用户
- [`fizz`](https://github.com/facebookincubator/fizz) 是 Facebook 的 TLS 1.3 实现。
- [`picotls`](https://github.com/h2o/picotls) 是一个 C 语言的 TLS 1.3 实现,支持 AEGIS 密码套件。
- [`h2o`](https://h2o.examp1e.net) 是一个支持 AEGIS 密码套件的 HTTP/{1,2,3} 服务器。
## 其他实现
[许多其他 AEGIS 实现](https://github.com/cfrg/draft-irtf-cfrg-aegis-aead?tab=readme-ov-file#known-implementations) 也可用于大多数编程语言。
专为在没有 AES 指令的环境中运行的应用程序推荐:[aegis-bitsliced](https://github.com/aegis-aead/aegis-bitsliced)。
专为针对特定 x86_64 CPU 的应用程序推荐:[aegis-jasmin](https://github.com/aegis-aead/aegis-jasmin)。
[aegis-aead GitHub 组织](https://github.com/orgs/aegis-aead/repositories) 还托管了 [OpenSSL](https://github.com/aegis-aead/openssl) 和 [BoringSSL](https://github.com/aegis-aead/boringssl) 的 AEGIS 补丁。
## AEGIS 变体之间的主要区别
| **特性** | **AEGIS-128L** | **AEGIS-256** | **AEGIS-128X2** | **AEGIS-128X4** | **AEGIS-256X2** | **AEGIS-256X4** |
| ------------------ | ------------------------------------------------ | ------------------------------------------------ | -------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------- |
| **密钥长度** | 128 位 | 256 位 | 128 位 | 128 位 | 256 位 | 256 位 |
| **Nonce 长度** | 128 位 | 256 位 | 128 位 | 128 位 | 256 位 | 256 位 |
| **状态大小** | 1024 位 (8 x 128 位块) | 768 位 (6 x 128 位块) | 2048 位 (2 x 1024 位状态) | 4096 位 (4 x 1024 位状态) | 1536 位 (2 x 768 位状态) | 3072 位 (4 x 768 位状态) |
| **输入速率** | 每次更新 256 位 | 每次更新 128 位 | 每次更新 512 位 | 每次更新 1024 位 | 每次更新 256 位 | 每次更新 512 位 |
| **性能** | 在标准 CPU 上速度高,针对小内存使用进行了优化 | 在标准 CPU 上速度高,针对小内存使用进行了优化 | 即使没有 AVX2 通常也比 AEGIS-128L 快,有 AVX2 时更快 | 通常比 AEGIS-128L 快,AVX-512 下最佳 | 即使没有 AVX2 通常也比 AEGIS-256 快,有 AVX2 时更快 | 通常比 AEGIS-256 快,AVX-512 下最佳 |
| **安全级别** | 128 位安全 | 256 位安全 | 128 位安全 | 128 位安全 | 256 位安全 | 256 位安全 |
## 基准测试结果
在具有并行执行流水线和 AES 支持的 CPU 上,AEGIS 的速度非常快。
以下结果来自 libaegis,该库主要针对可移植性和可读性进行了优化。其他实现(如 `aegis-jasmin` 或 Zig 实现)可能会表现出更好的性能。
### 加密 (16 KB)

### 认证 (64 KB)

### 移动端基准测试

标签:AEAD, AEGIS, AES-NI, AI工具, Altivec, ARM Crypto, AVX512, Bash脚本, Kali工具, libaegis, ProjectDiscovery, SIMD, VAES, WebAssembly, Zig, 侧信道防护, 加密库, 加密文件系统, 加密解密, 可视化界面, 客户端加密, 密码学, 开源库, 手动系统调用, 搜索引擎爬虫, 数据保护, 数据库加密, 日志审计, 硬件加速, 认证加密, 逆向工具, 随机数生成, 高性能加密