ANSSI-FR/MLA

GitHub: ANSSI-FR/MLA

MLA 是一个纯 Rust 实现的多层存档格式,提供加密、压缩、数字签名和后量子支持,以解决安全数据存储和传输的需求。

Stars: 369 | Forks: 22

[![构建与测试](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/b167bf29c0134733.svg)](https://github.com/ANSSI-FR/MLA/actions) [![Cargo MLA](https://img.shields.io/badge/crates.io-mla-red)](https://crates.io/crates/mla) [![MLA 文档](https://img.shields.io/badge/docs.rs-mla-blue)](https://docs.rs/mla) [![Cargo MLAR](https://img.shields.io/badge/crates.io-mlar-red)](https://crates.io/crates/mlar) [![PyPI - 版本](https://img.shields.io/pypi/v/mla-archive?label=PyPI%20%7C%20mla-archive)](https://pypi.org/project/mla-archive/) # 多层存档 (MLA) ANSSI logo ### 法国国家网络安全局 (ANSSI) ![badge_repo](https://img.shields.io/badge/ANSSI--FR-MLA-white) [![category_badge_internal](https://img.shields.io/badge/category-internal-%23d08fce)](https://github.com/ANSSI-FR#types-de-projets) [![openess_badge_B](https://img.shields.io/badge/code.gouv.fr-open-green)](https://documentation.ouvert.numerique.gouv.fr/les-parcours-de-documentation/ouvrir-un-projet-num%C3%A9rique/#niveau-ouverture) *此项目由 [ANSSI](https://cyber.gouv.fr/) 管理。要了解更多信息,您可以访问 ANSSI 开源策略的专用[页面](https://cyber.gouv.fr/enjeux-technologiques/open-source/)(法语)。您也可以点击上面的徽章了解其含义。* # 简介 MLA 是一种存档文件格式,具有以下特点: * 支持使用非对称密钥进行传统加密与后量子加密的混合(基于 X25519 和后量子 ML-KEM 1024 混合的 KEM,采用 AES256-GCM 的 HPKE) * 支持传统签名与后量子签名的混合 * 支持压缩(基于 [`rust-brotli`](https://github.com/dropbox/rust-brotli/)) * 可流式创建存档: * 即使在单向数据二极管上也能构建存档 * 可以通过数据块添加条目,无需预先知道最终大小 * 条目数据块可以交错添加(可以添加一个条目的开头,开始第二个条目,然后继续添加第一个条目的后续部分) * 架构无关且在一定程度上可移植(完全用 Rust 编写) * 存档读取是可定位的,即使已压缩或加密。可以直接访问存档中间的条目,无需从头开始读取 * 如果存档被截断,在一定程度上可以恢复。提供两种模式: * 经认证的恢复(默认):只检索经认证(如 AEAD,无签名验证)的加密数据块 * 未认证的恢复:检索经认证和未经认证的加密数据块。使用风险自负。 * 可以说更不容易出现 bug,尤其是在解析不受信任的存档时(Rust 的安全性) # 仓库 此仓库包含: * `mla`:实现 MLA 读写器的 Rust 库 * `mlar`:一个封装 `mla` 以执行常见操作(创建、列表、提取等)的 Rust 命令行工具 * `doc`:与 MLA 相关的文档(例如格式规范、密码学) * [MLA 手册](https://anssi-fr.github.io/MLA) * `bindings`:其他语言的绑定 * `samples`:测试资源 * `mla-fuzz-afl`:用于对 `mla` 进行模糊测试的 Rust 工具 * `.github`:持续集成需求 # 快速命令行使用 以下是一些使用 ``mlar`` 来处理 MLA 格式存档的命令。 ``` # 生成 MLA 密钥对。 mlar keygen sender mlar keygen receiver # 创建包含某些文件的归档。 mlar create -k sender.mlapriv -p receiver.mlapub -o my_archive.mla /boot/./grub/locale/en@quot.mo /etc/security/../issue ../file.txt # 列出归档的内容。 # 注意顺序可能不同,根目录被去除, # 路径已规范化,且列表内容按照 # `doc/src/ENTRY_NAME.md` 中的描述进行编码(因此输出中有百分号)。 # 输出结果为: # `` # etc/issue # boot/grub/locale/en%40quot.mo # file.txt # `` mlar list -k receiver.mlapriv -p sender.mlapub -i my_archive.mla # 将归档内容提取到一个新目录中。 # 在此示例中,这将创建两个文件: # extracted_content/etc/issue 和 extracted_content/etc/os-release mlar extract -k receiver.mlapriv -p sender.mlapub -i my_archive.mla -o extracted_content # 显示归档中一个文件的内容。 mlar cat -k receiver.mlapriv -p sender.mlapub -i my_archive.mla etc/os-release # 将归档转换为长期格式,主要用于存档目的。 # 以下操作还会移除加密并应用 # the highest (but slowest) compression level. mlar convert -k receiver.mlapriv -p sender.mlapub -i my_archive.mla -o longterm.mla --unencrypted --unsigned -q 11 # 创建包含多个接收者且不带签名也不压缩的归档。 mlar create --unsigned --uncompressed -p archive.mlapub -p client1.mlapub -o my_archive.mla ... # 列出一个包含无法解释为路径的条目名称的归档。 # 输出结果为: # `c%3a%2f%00%3b%e2%80%ae%0ac%0dd%1b%5b1%3b31ma%3cscript%3eevil%5c..%2f%d8%01%c2%85%e2%88%95` # 对应于一个包含以下内容的条目名称:ASCII 字符、c:、/、..、\、 # NUL、RTLO、换行符、终端转义序列、回车符、 # HTML、代理代码单元、U+0085 奇怪换行符、伪造的 Unicode 斜杠。 # 请注意,其中一些字符可能出现在有效的路径中。 mlar list -k samples/test_mlakey_archive_v2_receiver.mlapriv -p samples/test_mlakey_archive_v2_sender.mlapub -i samples/archive_weird.mla --raw-escaped-names # 获取其内容。 # 显示内容为: # `' OR 1=1` mlar cat -k samples/test_mlakey_archive_v2_receiver.mlapriv -p samples/test_mlakey_archive_v2_sender.mlapub -i samples/archive_weird.mla --raw-escaped-names c%3a%2f%00%3b%e2%80%ae%0ac%0dd%1b%5b1%3b31ma%3cscript%3eevil%5c..%2f%d8%01%c2%85%e2%88%95 # 创建一个网页文件的归档,不加密且不带签名 curl https://raw.githubusercontent.com/ANSSI-FR/MLA/refs/heads/main/LICENSE.md | mlar create --unencrypted --unsigned -o my_archive.mla --stdin-data # 创建一个网页文件和任意字节串的归档,不加密且不带签名(选择的分隔符不应出现在两个条目中) (curl https://raw.githubusercontent.com/ANSSI-FR/MLA/refs/heads/main/LICENSE.md; echo "SEPARATOR"; echo -n "All Hail MLA") | mlar create --unencrypted --unsigned -o my_archive.mla --stdin-data --stdin-data-separator "SEPARATOR" --stdin-data-entry-names great_license.md,hello.txt # 创建一个通过标准输入传递文件列表(而非数据)的归档 echo -n -e "/etc/issue\n/etc/os-release" | mlar create -unencrypted --unsigned -o my_archive.mla --stdin-file-list ``` `mlar` 可以通过以下方式获取: * 通过 Cargo:`cargo install mlar` * 使用支持的操作系统的[最新版本](https://github.com/ANSSI-FR/MLA/releases) * 发布的二进制文件使用 `opt-level = 3` 构建,性能出色 为了获得更高性能,您可以构建一个针对本机优化的二进制文件(不可移植),例如在 Linux 机器上: ``` RUSTFLAGS="-Ctarget-cpu=native" cargo build --release --target x86_64-unknown-linux-musl ``` 注意:本机构建针对您机器的 CPU 进行了优化,**并且不可移植**。仅当在构建它的同一台机器上运行时才使用它们。 # API 使用 参见 [https://docs.rs/mla](https://docs.rs/mla/2.0.0-beta/mla/index.html) # 在其他语言中使用 MLA 以下语言的绑定可用: * [C/C++](bindings/C/README.md) * [Python](bindings/python/README.md) ## 安全 您应该在使用前阅读 [API 文档](https://github.com/ANSSI-FR/MLA#api-usage) 和 `mlar --help`。它们有时会提供重要的安全警告。[`doc/src/ENTRY_NAME.md`](doc/src/ENTRY_NAME.md) 对于理解条目命名约定和安全影响也至关重要。 **潜在问题** * 将存档提取到至少一个上级目录可被其他用户写入的目录(例如 `/tmp` 或其他共享目录)通常是不安全的,因为存在符号链接攻击。 * 除了符号链接攻击外,`mlar` 不会提取到指定输出目录之外。 * 即使使用经过认证的密码加密,未签名的存档也无法认证其作者。任何拥有您公钥的人都可以创建这样的存档,因此它可能包含任意(可能恶意的)数据。 * `mlar` 在输出时会转义条目名称以避免安全问题。 **保证与限制** * MLA 不提供任何防止侧信道攻击的保证。但是,如果您发现这方面的问题,请联系我们,我们将评估是否修复。 * MLA Python 绑定的安全性和维护级别明确不保证。 * 在 MLA 2.0.0-beta 上进行了安全评估,记录了此后应已修复的低严重性问题(参见 [issue #465](https://github.com/ANSSI-FR/MLA/issues/465))。报告位于 `doc/20260130-mla-security-assessment.pdf`。 ## 常见问题 **`MLAArchiveWriter` 是 `Send` 的吗?** 默认情况下,`MLAArchiveWriter` 不是 `Send` 的。如果内部的可写类型也是 `Send`,可以在 `Cargo.toml` 中为 `mla` 启用 `send` 特性,例如: ``` [dependencies] mla = { version = "...", default-features = false, features = ["send"]} ``` **真的需要一种新格式吗?** 由于现有的存档格式众多,可能不需要。 但据作者所知,没有一种格式支持上述特性(当然,它们更适合其他用途)。 例如(基于作者的理解): * `tar` 格式在添加文件前需要知道其大小,并且不可定位 * `zip` 格式在删除页脚后可能会丢失文件信息 * `7zip` 格式在向存档添加文件时需要重建整个存档(不可流式)。它也相当复杂,因此在解包未知存档时更难审计/信任 * `journald` 格式不可流式。这里也不需要单写/多读,从而释放了 `journald` 格式的一些约束 * 任何存档 + `age`:[age](https://age-encryption.org/) 截至 MLA 2.0 发布时,不支持后量子加密或签名。 * 备份格式通常被设计来避免重复等问题,因此它们需要在内存中保留更大的结构,或者不可流式 调整这些格式可能会产生类似的特性。做出的选择是为了更好地控制格式的能力,并(尝试)保持简单。 ## 性能 您可以通过基于 [Criterion](https://github.com/bheisler/criterion.rs) 的嵌入式基准测试来评估性能。 已经嵌入了几个场景,例如: * 文件添加,具有不同的大小和层配置 * 文件添加,改变压缩质量 * 文件读取,具有不同的大小和层配置 * 随机文件读取,具有不同的大小和层配置 * 线性存档提取,具有不同的大小和层配置 在 "Intel(R) Core(TM) i7-1255U CPU @ 2.60GHz" 上: ``` $ cargo bench ... multiple_layers_multiple_block_size/compression: true, encryption: true, signature: true/1048576 time: [7.0850 ms 7.1179 ms 7.1586 ms] thrpt: [139.69 MiB/s 140.49 MiB/s 141.14 MiB/s] ... chunk_size_decompress_multifiles_random/compression: true, encryption: true, signature: true/1048576 time: [11.285 ms 11.494 ms 11.663 ms] thrpt: [85.745 MiB/s 87.005 MiB/s 88.616 MiB/s] ... reader_multiple_layers_multiple_block_size_multifiles_linear/compression: true, encryption: true, signature: true/1048576 time: [4.6197 ms 4.6383 ms 4.6604 ms] thrpt: [214.58 MiB/s 215.60 MiB/s 216.47 MiB/s] ... ``` Criterion.rs 文档解释了如何获取 HTML 报告、比较结果等。 ### AES-NI 支持 如 [aes crate 文档](https://docs.rs/aes/0.8.4/aes/index.html#x86x86_64-intrinsics-aes-ni) 所述,此 crate 在 `i686` 和 `x86_64` 目标上使用**运行时检测**来检查 AES-NI 是否可用。如果未检测到 AES-NI,它会自动回退到一个常数时间的软件实现。 # 贡献 感谢您的帮助!要贡献,请阅读我们的[贡献说明](.github/CONTRIBUTING.md)。
标签:ANSSI, CVE, DNS解析, Rust语言, 加密, 压缩, 可视化界面, 后量子密码学, 存档格式, 安全存储, 密码学算法, 开源项目, 操作系统检测, 数字签名, 数据二极管, 文件格式, 流式处理, 混合加密, 漏洞扫描器, 网络安全, 蓝队防御, 逆向工具, 通知系统, 隐私保护