7个版本 (重大变更)
0.5.0 | 2024年2月4日 |
---|---|
0.4.0 | 2022年10月27日 |
0.3.0 | 2022年5月2日 |
0.2.1 | 2021年12月27日 |
0.0.0 | 2020年2月9日 |
#941 在 加密学
每月1,256次下载
在 6 个crate中使用 5 直接
91KB
1.5K SLoC
age-plugin Rust库
此crate提供了一个构建age插件的API。
简介
age文件加密格式遵循“一个精炼的联合”设计理念。在特定格式版本内的扩展机制是age头部中的接收者段落:文件密钥可以用任何方式包装,并且age客户端需要忽略他们不理解的部分。
执行此机制的核心API包括
- 一个包装文件密钥并返回段落的接收者。
- 一个解包段落并返回文件密钥的身份。
age插件系统提供了一个机制,用于在进程边界上公开这些核心API。它有两个主要组件
- 将接收者和身份映射到插件二进制文件的映射。
- 包装和解包文件密钥的状态机。
使用这种可组合的设计,您可以实现可以直接与age
库crate一起使用的接收者或身份,并将其作为插件二进制文件部署以供rage
等客户端使用。
将接收者和身份映射到插件二进制文件
age插件通过任意不区分大小写的字符串NAME
进行标识。此字符串在三个地方使用
- 兼容插件的接收者使用带有HRP
age1name
(小写)的Bech32进行编码。 - 兼容插件的身份使用带有HRP
AGE-PLUGIN-NAME-
(大写)的Bech32进行编码。 - 插件二进制文件(由age客户端启动)的名称为
age-plugin-name
。
用户通过提供文件加密的接收者或文件解密的身份与age客户端交互。当提供插件接收者或身份时,age客户端将搜索对应插件名称的二进制文件所在的PATH
。
接收者段落类型不需要与特定插件名称相关联。在解密时,age客户端将传递所有接收者段落到每个连接的插件。插件必须忽略他们不知道的段落。
插件二进制可以通过在多个名称下出现在PATH
中来处理多个收件人或身份类型。这可以通过到规范二进制的符号链接或别名来实现。
多个插件二进制可以支持相同的收件人和身份类型;age客户端将使用在PATH
中找到的第一个二进制文件。一些Unix操作系统支持"alternatives",插件二进制如果提供对常见收件人或身份类型的支持,应利用这一功能。
请注意,用户指定的身份不需要指向特定的解密密钥,或者实际上不包含任何密钥材料。它只需要包含足够的信息,以便插件能够定位必要的密钥材料。
标准age密钥
插件可以支持解密加密为本地age收件人的文件,通过包括对x25519
收件人段落的支持。此类插件将选择自己的名称,用户将使用包含指定该插件名称的身份文件。
示例插件二进制
以下示例使用clap
来解析命令行参数,但任何可以检测到--age-plugin=STATE_MACHINE
标志的参数解析逻辑都将有效。
use age_core::format::{FileKey, Stanza};
use age_plugin::{
identity::{self, IdentityPluginV1},
print_new_identity,
recipient::{self, RecipientPluginV1},
Callbacks, run_state_machine,
};
use clap::Parser;
use std::collections::HashMap;
use std::io;
struct RecipientPlugin;
impl RecipientPluginV1 for RecipientPlugin {
fn add_recipient(
&mut self,
index: usize,
plugin_name: &str,
bytes: &[u8],
) -> Result<(), recipient::Error> {
todo!()
}
fn add_identity(
&mut self,
index: usize,
plugin_name: &str,
bytes: &[u8]
) -> Result<(), recipient::Error> {
todo!()
}
fn wrap_file_keys(
&mut self,
file_keys: Vec<FileKey>,
mut callbacks: impl Callbacks<recipient::Error>,
) -> io::Result<Result<Vec<Vec<Stanza>>, Vec<recipient::Error>>> {
todo!()
}
}
struct IdentityPlugin;
impl IdentityPluginV1 for IdentityPlugin {
fn add_identity(
&mut self,
index: usize,
plugin_name: &str,
bytes: &[u8]
) -> Result<(), identity::Error> {
todo!()
}
fn unwrap_file_keys(
&mut self,
files: Vec<Vec<Stanza>>,
mut callbacks: impl Callbacks<identity::Error>,
) -> io::Result<HashMap<usize, Result<FileKey, Vec<identity::Error>>>> {
todo!()
}
}
#[derive(Debug, Parser)]
struct PluginOptions {
#[arg(help = "run the given age plugin state machine", long)]
age_plugin: Option<String>,
}
fn main() -> io::Result<()> {
let opts = PluginOptions::parse();
if let Some(state_machine) = opts.age_plugin {
// The plugin was started by an age client; run the state machine.
run_state_machine(
&state_machine,
Some(|| RecipientPlugin),
Some(|| IdentityPlugin),
)?;
return Ok(());
}
// Here you can assume the binary is being run directly by a user,
// and perform administrative tasks like generating keys.
Ok(())
}
许可证
根据您的选择,许可协议为:
- Apache License,版本2.0,(LICENSE-APACHE或http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT或http://opensource.org/licenses/MIT)
任选其一。
贡献
除非您明确声明,否则根据Apache-2.0许可证定义,您提交的任何有意包含在工作中的贡献都将按照上述方式双许可,无需任何附加条款或条件。
依赖关系
~5–14MB
~164K SLoC