14个版本 (7个重大更改)

0.9.1 2024年6月21日
0.9.0 2023年10月23日
0.8.1 2023年7月17日
0.8.0 2021年11月26日
0.2.0 2019年11月22日

#251加密

Download history 5/week @ 2024-04-17 4/week @ 2024-04-24 130/week @ 2024-06-19 11/week @ 2024-06-26 136/week @ 2024-07-03 160/week @ 2024-07-24 35/week @ 2024-07-31

每月195次下载

MIT/Apache

1MB
15K SLoC

C# 10K SLoC // 0.3% comments Rust 2.5K SLoC // 0.0% comments Python 1K SLoC // 0.1% comments Visual Studio Solution 446 SLoC TypeScript 383 SLoC Shell 40 SLoC // 0.1% comments Batch 4 SLoC

devolutions-crypto

Build Status
Devolutions产品中使用的加密库。它设计得既快速又易于使用,并且具有抗误用性。 crates.io 文档

使用方法

概述

该库分为多个模块,下面将进行解释。处理“管理”数据时,包括头和版本控制,您将处理类似于 CiphertextPublicKey 等结构。

这些模块都实现了 TryFrom<&[u8]>Into<Vec<u8>>,这是实现序列化和反序列化数据的方式。

use std::convert::TryFrom as _;
use devolutions_crypto::utils::generate_key;
use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };

let key: Vec<u8> = generate_key(32);

let data = b"somesecretdata";

let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");

// The ciphertext can be serialized.
let encrypted_data_vec: Vec<u8> = encrypted_data.into();

// This data can be saved somewhere, passed to another language or over the network
// ...
// When you receive the data as a byte array, you can deserialize it into a struct using TryFrom

let ciphertext = Ciphertext::try_from(encrypted_data_vec.as_slice()).expect("deserialization shouldn't fail");

let decrypted_data = ciphertext.decrypt(&key).expect("The decryption shouldn't fail");

assert_eq!(decrypted_data, data);

密文

此模块包含与加密相关的所有内容。您可以使用它使用共享密钥或密钥对来加密和解密数据。
无论哪种方式,加密都会生成一个 Ciphertext,它有一个解密方法。

对称

use devolutions_crypto::utils::generate_key;
use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };

let key: Vec<u8> = generate_key(32);

let data = b"somesecretdata";

let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");

let decrypted_data = encrypted_data.decrypt(&key).expect("The decryption shouldn't fail");

assert_eq!(decrypted_data, data);

非对称

在这里,您需要一个 PublicKey 来加密数据,以及相应的 PrivateKey 来解密它。您可以通过使用 密钥模块 中的 generate_keypair 来生成它们。

use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
use devolutions_crypto::ciphertext::{ encrypt_asymmetric, CiphertextVersion, Ciphertext };

let keypair: KeyPair = generate_keypair(KeyVersion::Latest);

let data = b"somesecretdata";

let encrypted_data: Ciphertext = encrypt_asymmetric(data, &keypair.public_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");

let decrypted_data = encrypted_data.decrypt_asymmetric(&keypair.private_key).expect("The decryption shouldn't fail");

assert_eq!(decrypted_data, data);

密钥

目前,此模块仅处理密钥对,因为对称密钥尚未封装。

生成/推导

使用 generate_keypair 将生成一个随机密钥对。

非对称密钥有两个用途。它们可以用来 加密和解密数据,以及执行 密钥交换

generate_keypair

use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};

let keypair: KeyPair = generate_keypair(KeyVersion::Latest);

密钥交换

使用密钥交换的目的是在两个当事人之间获得一个共享密钥,同时不让在对话中监听的用户猜测该共享密钥。

  1. Alice 和 Bob 各生成一个 KeyPair
  2. Alice 和 Bob 交换他们的 PublicKey
  3. Alice 将她的 PrivateKey 与 Bob 的 PublicKey 混合。这给了她共享密钥。
  4. Bob 将他的 PrivateKey 与 Alice 的 PublicKey 混合。这给了他共享密钥。
  5. Bob 和 Alice 都拥有相同的共享密钥,他们可以使用它进行对称加密,以便进行进一步的通信。
use devolutions_crypto::key::{generate_keypair, mix_key_exchange, KeyVersion, KeyPair};

let bob_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
let alice_keypair: KeyPair = generate_keypair(KeyVersion::Latest);

let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_keypair.public_key).expect("key exchange should not fail");

let alice_shared = mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).expect("key exchange should not fail");

// They now have a shared secret!
assert_eq!(bob_shared, alice_shared);

PasswordHash

您可以使用此模块来哈希密码并在之后验证它。这是在登录时验证用户密码的推荐方法。

use devolutions_crypto::password_hash::{hash_password, PasswordHashVersion};

let password = b"somesuperstrongpa$$w0rd!";

let hashed_password = hash_password(password, 10000, PasswordHashVersion::Latest);

assert!(hashed_password.verify_password(b"somesuperstrongpa$$w0rd!"));
assert!(!hashed_password.verify_password(b"someweakpa$$w0rd!"));

SecretSharing

此模块用于生成一个密钥,该密钥分成多个 Share,并且需要特定的数量来恢复密钥。
您可以将其视为一个“破碎玻璃”场景。您可以使用它生成一个密钥,通过加密整个数据来锁定数据,然后您将需要,比如说,3 个管理员中的 5 个来解密数据。这些数据也可以是一个 API 密钥或超级管理员账户的密码。

use devolutions_crypto::secret_sharing::{generate_shared_key, join_shares, SecretSharingVersion, Share};

// You want a key of 32 bytes, splitted between 5 people, and I want a 
// minimum of 3 of these shares to regenerate the key.
let shares: Vec<Share> = generate_shared_key(5, 3, 32, SecretSharingVersion::Latest).expect("generation shouldn't fail with the right parameters");

assert_eq!(shares.len(), 5);
let key = join_shares(&shares[2..5]).expect("joining shouldn't fail with the right shares");

Signature

此模块用于使用密钥对签名数据以证明其真实性。

生成密钥对

use devolutions_crypto::signing_key::{generate_signing_keypair, SigningKeyVersion, SigningKeyPair, SigningPublicKey};

let keypair: SigningKeyPair = generate_signing_keypair(SigningKeyVersion::Latest);

签名数据

use devolutions_crypto::signature::{sign, Signature, SignatureVersion};

let signature: Signature = sign(b"this is some test data", &keypair, SignatureVersion::Latest);

验证签名

use devolutions_crypto::signature::{sign, Signature, SignatureVersion};

assert!(signature.verify(b"this is some test data", &public_key));

Utils

这些是一组在处理库时可能有用的函数。

密钥生成

这是一个用于生成随机密钥的方法。在几乎所有情况下,length 参数应该是 32。

use devolutions_crypto::utils::generate_key;

let key = generate_key(32);
assert_eq!(32, key.len());

密钥派生

这是一个用于从密码或另一个密钥生成密钥的方法。对于依赖于密码的加密非常有用。如果可能,盐应该是随机的 16 字节数组,迭代次数应该是 10000 或由用户配置。

use devolutions_crypto::utils::{generate_key, derive_key};
let key = b"this is a secret password";
let salt = generate_key(16);
let iterations = 10000;
let length = 32;

let new_key = derive_key(key, &salt, iterations, length);

assert_eq!(32, new_key.len());

底层算法

截至当前版本

  • 对称加密使用 XChaCha20Poly1305
  • 非对称加密使用 Curve25519。
  • 非对称加密使用 ECIES。
  • 密钥交换使用 x25519 或 Curve25519 上的 ECDH
  • 密码哈希使用 PBKDF2-HMAC-SHA2-256
  • 密钥共享使用 GF256 上的 Shamir 密钥共享

依赖关系

~4.5–6MB
~114K SLoC