#encryption #container #key-store #encryption-key #storage #parser #file-format

无需std cocoon

一个具有强大加密和格式验证的简单保护容器

24个版本

0.4.2 2024年5月27日
0.4.1 2023年10月25日
0.3.3 2023年10月7日
0.3.2 2022年8月3日
0.1.11 2020年7月12日

#118 in 加密学

Download history 323/week @ 2024-05-03 333/week @ 2024-05-10 489/week @ 2024-05-17 531/week @ 2024-05-24 367/week @ 2024-05-31 457/week @ 2024-06-07 350/week @ 2024-06-14 387/week @ 2024-06-21 238/week @ 2024-06-28 296/week @ 2024-07-05 425/week @ 2024-07-12 623/week @ 2024-07-19 722/week @ 2024-07-26 840/week @ 2024-08-02 596/week @ 2024-08-09 429/week @ 2024-08-16

2,684 每月下载量
用于 5 个crate(4个直接使用)

MIT 许可证

110KB
1.5K SLoC

Cocoon crates.io docs.rs license coverage

蜗牛

Cocoon format

MiniCocoonCocoon 是用于将敏感数据用强大加密和格式验证进行包装的保护容器。针对以下实际场景开发了 MiniCocoonCocoon 的格式:

  1. 作为 加密文件格式,用于组织简单的安全存储
    1. 密钥存储。
    2. 密码存储。
    3. 敏感数据存储。
  2. 用于 加密数据传输
    • 作为安全的内存容器。

Cocoon 的开发以安全性为首要考虑。它旨在只做一件事,并且完美地完成。它具有最小化依赖和简约设计,以简化对安全方面的控制。它是一个纯Rust实现,所有依赖项都是禁用了默认功能的纯Rust包。

用例

无论何时需要安全地传输和存储数据,你都需要重新发明轮子:你必须注意如何正确加密数据,如何处理随机生成的缓冲区,然后如何获取数据,解析和解密。相反,你可以使用 MiniCocoonCocoon

基本用法

📌 包装/解包

一方使用 MiniCocoon::wrap 将私有数据包装到容器中。另一方(或同一方,或任何知道密钥的人)使用 MiniCocoon::unwrap 将数据从容器中解包。

在简单的数据加密情况下,MiniCocoon 优于 Cocoon,因为它生成了一个没有版本控制的较小头部容器的容器,并且它还允许顺序地包装数据(包装,包装,包装!),而不会因为KDF计算而降低性能。

let mut cocoon = MiniCocoon::from_key(b"0123456789abcdef0123456789abcdef", &[0; 32]);

let wrapped = cocoon.wrap(b"my secret data")?;
assert_ne!(&wrapped, b"my secret data");

let unwrapped = cocoon.unwrap(&wrapped)?;
assert_eq!(unwrapped, b"my secret data");

📌 导出/解析

你可以将数据存储到文件中。将数据放入 Vec 容器中,数据将使用 "cocoon" 格式 在原地加密并存储在文件中。

作为长期数据存储,Cocoon 优于,它具有具有魔数、选项和版本控制的扩展头部。

let mut data = b"my secret data".to_vec();
let mut cocoon = Cocoon::new(b"password");

cocoon.dump(data, &mut file)?;

let data = cocoon.parse(&mut file)?;
assert_eq!(&data, b"my secret data");

📌 加密/解密

您可以在原地加密数据并避免重新分配。该方法在堆栈上的数组中使用分离的元数据(容器格式前缀)。它适用于 "no_std" 构建,以及在您想要避免大量数据重新分配的情况下。不过,您需要注意如何存储和传输数据长度和容器前缀。

MiniCocoonCocoon 都具有相同的 API,但前缀大小不同。MiniCocoon 没有在每次加密调用时生成 KDF 的开销,因此推荐用于简单的顺序加密/解密操作。

let mut data = "my secret data".to_owned().into_bytes();
let mut cocoon = MiniCocoon::from_key(b"0123456789abcdef0123456789abcdef", &[0; 32]);

let detached_prefix = cocoon.encrypt(&mut data)?;
assert_ne!(data, b"my secret data");

cocoon.decrypt(&mut data, &detached_prefix)?;
assert_eq!(data, b"my secret data");

案例研究

您实现了一个必须使用用户密码加密存储在加密文件中的机密数据库。您的数据库在内存中的表示和序列化的方式有很多种。您自己处理这些方面,例如,您可以使用 HashMap 来管理数据,并使用 borshbincode 来序列化数据。您甚至可以在加密之前压缩序列化缓冲区。

最后,您使用 Cocoon 将最终图像放入加密容器中。

use borsh::{BorshDeserialize, BorshSerialize};
use cocoon::{Cocoon, Error};

use std::collections::HashMap;
use std::fs::File;

// Your data can be represented in any way.
#[derive(BorshDeserialize, BorshSerialize)]
struct Database {
    inner: HashMap<String, String>,
}

fn main() -> Result<(), Error> {
    let mut file = File::create("target/test.db")?;
    let mut db = Database { inner: HashMap::new() };

    // Over time you collect some kind of data.
    db.inner.insert("[email protected]".to_string(), "eKPV$PM8TV5A2".to_string());

    // You can choose how to serialize data. Also, you can compress it.
    let encoded = db.try_to_vec().unwrap();

    // Finally, you want to store your data secretly.
    // Supply some password to Cocoon: it can be any byte array, basically.
    // Don't use a hard-coded password in real life!
    // It could be a user-supplied password.
    let mut cocoon = Cocoon::new(b"secret password");

    // Dump the serialized database into a file as an encrypted container.
    let container = cocoon.dump(encoded, &mut file)?;

    // Let's look at how to decrypt the container and parse it back.
    let mut file = File::open("target/test.db").unwrap();
    let encoded = cocoon.parse(&mut file).unwrap();
    let decoded = Database::try_from_slice(&encoded).unwrap();

    Ok(())
}

密码学

256 位密码学被选为 Cocoon 的基线。

加密器(AEAD) 密钥派生函数(KDF)
Chacha20-Poly1305 PBKDF2-SHA256:100000 次迭代
AES256-GCM
  • 密钥:256 位。
  • KDF 的盐:随机 128 位 + 预定义部分。
  • 加密的nonce:随机 96 位。

密钥派生参数符合 NIST SP 800-132 建议的(盐,迭代次数),而加密参数(密钥,nonce,长度)符合特定加密的要求。选择 AEAD 是为了验证加密数据以及未加密的头信息。

零化

加密密钥被封装到零化容器(由 zeroize 提供的)中,这意味着密钥一旦被丢弃就会自动擦除。

工作原理

有关更多实现细节,请参阅 docs.rs,例如:

  1. 容器创建 的过程,
  2. 可定制的 crate 功能
  3. 当然还有 API

依赖关系

~2.6–3.5MB
~63K SLoC