devolutions_crypto/lib.rs
1//! Cryptographic library used in Devolutions products. It is made to be fast, easy to use and misuse-resistant.
2//!
3//! # Usage
4//! * [Overview](#overview)
5//! * [Ciphertext Module](#ciphertext)
6//! * [Symmetric Encryption](#symmetric)
7//! * [Asymmetric Encryption](#asymmetric)
8//! * [Key Module](#key)
9//! * [Key Generation](#generation)
10//! * [Key Exchange](#key-exchange)
11//! * [Key Derivation](#key-derivation)
12//! * [Derive and Encrypt](#derive-and-encrypt)
13//! * [PasswordHash Module](#passwordhash)
14//! * [SecretSharing Module](#secretsharing)
15//! * [Utils Module](#utils)
16//! * [Key Generation](#key-generation)
17//! * [Key Derivation](#key-derivation-1)
18//!
19//! ## Overview
20//!
21//! This library is split into multiple modules, which are explained below. When
22//! dealing with "managed" data, that includes an header and versioning, you deal
23//! with structures like `Ciphertext`, `SecretKey`, `PublicKey`, etc.
24//!
25//! These structures all implement `TryFrom<&[u8]>` and `Into<Vec<u8>>` to serialize and deserialize data.
26//!
27//!
28//! ## Ciphertext
29//!
30//! This module contains everything related to encryption. You can use it to encrypt and decrypt data using either a shared secret key or a keypair.
31//! The encryption will give you a `Ciphertext`, which has a method to decrypt it.
32//!
33//! ### Symmetric
34//! The library provides a `SecretKey` which can be used as a shared secret to encrypt messages.
35//!
36//! ```rust
37//! use std::convert::TryFrom as _;
38//! use devolutions_crypto::key::{generate_secret_key, KeyVersion, SecretKey};
39//! use devolutions_crypto::ciphertext::{ encrypt_with_secret_key, CiphertextVersion, Ciphertext };
40//!
41//! let secret_key = generate_secret_key(KeyVersion::Latest);
42//! let data = b"somesecretdata";
43//! let encrypted_data = encrypt_with_secret_key(data, &secret_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
44//!
45//! // The ciphertext can be serialized to be saved somewhere, passed to another language or over the network.
46//! let encrypted_data_vec: Vec<u8> = encrypted_data.into();
47//!
48//! // When you receive the data as a byte array, you can deserialize it into a struct using TryFrom
49//! let ciphertext = Ciphertext::try_from(encrypted_data_vec.as_slice()).expect("deserialization shouldn't fail");
50//! let decrypted_data = ciphertext.decrypt_with_secret_key(&secret_key).expect("The decryption shouldn't fail");
51//! assert_eq!(decrypted_data, data);
52//! ```
53//!
54//! The key can also be passed as raw bytes.
55//!
56//! ```rust
57//! use devolutions_crypto::utils::generate_key;
58//! use devolutions_crypto::ciphertext::{encrypt_with_raw_key, CiphertextVersion, Ciphertext};
59//!
60//! let key: Vec<u8> = generate_key(32).expect("generate key shouldn't fail");
61//! let data = b"somesecretdata";
62//!
63//! let encrypted_data: Ciphertext = encrypt_with_raw_key(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
64//! let decrypted_data = encrypted_data.decrypt(&key).expect("The decryption shouldn't fail");
65//! assert_eq!(decrypted_data, data);
66//! ```
67//!
68//! ### Asymmetric
69//! Here, you will need a `PublicKey` to encrypt data and the corresponding
70//! `PrivateKey` to decrypt it. You can generate them by using `generate_keypair`
71//! in the [Key module](#key).
72//!
73//! ```rust
74//! use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
75//! use devolutions_crypto::ciphertext::{ encrypt_asymmetric, CiphertextVersion, Ciphertext };
76//!
77//! let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
78//! let data = b"somesecretdata";
79//!
80//! let encrypted_data: Ciphertext = encrypt_asymmetric(data, &keypair.public_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
81//! let decrypted_data = encrypted_data.decrypt_asymmetric(&keypair.private_key).expect("The decryption shouldn't fail");
82//! assert_eq!(decrypted_data, data);
83//! ```
84//!
85//! ## Key
86//!
87//! This module provides secret keys and keypairs.
88//!
89//! ### Generation
90//!
91//! Use `generate_secret_key` to a generate a random symmetric key and `generate_keypair` to generate a random keypair.
92//!
93//! Asymmetric keys have two uses. They can be used to [encrypt and decrypt data](##asymmetric) and to perform a [key exchange](#key-exchange).
94//!
95//! ```rust
96//! use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
97//!
98//! let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
99//! ```
100//!
101//! ## Key Derivation
102//!
103//! The Key Derivation module provides a way to derive a `SecretKey` from a password or passphrase. The derive operation
104//! returns a `SecretKey`, and a `DerivationParameters` that can be serialized and reused to derive the same key at a
105//! later time.
106//!
107//! Example with `derive_key`:
108//! ```rust
109//! use devolutions_crypto::key_derivation::{derive_key, DerivationParameters};
110//! use devolutions_crypto::KeyDerivationVersion;
111//!
112//! let password = b"a very strong password";
113//! let (secret_key, params) = derive_key(password, KeyDerivationVersion::Latest).expect("derivation should not fail");
114//! // Serialize params to re-derive later:
115//! let params_bytes: Vec<u8> = params.into();
116//! ```
117//!
118//! Example with Argon2 (recommended):
119//! ```rust
120//! use devolutions_crypto::key_derivation::Argon2;
121//! let password = b"a very strong password";
122//! let argon2 = Argon2::new();
123//! let (secret_key, params) = argon2.derive(password).expect("derivation should not fail");
124//! // Serialize params to re-derive later:
125//! let params_bytes: Vec<u8> = params.into();
126//! ```
127//!
128//! Example with PBKDF2:
129//! ```rust
130//! use devolutions_crypto::key_derivation::Pbkdf2;
131//! let password = b"a very strong password";
132//! let pbkdf2 = Pbkdf2::new();
133//! let (secret_key, params) = pbkdf2.derive(password).expect("derivation should not fail");
134//! ```
135//!
136//! ### Key Exchange
137//!
138//! The goal of using a key exchange is to get a shared secret key between
139//! two parties without making it possible for users listening on the conversation
140//! to guess that shared key.
141//! 1. Alice and Bob generate a `KeyPair` each.
142//! 2. Alice and Bob exchange their `PublicKey`.
143//! 3. Alice mixes her `PrivateKey` with Bob's `PublicKey`. This gives her the shared key.
144//! 4. Bob mixes his `PrivateKey` with Alice's `PublicKey`. This gives him the shared key.
145//! 5. Both Bob and Alice have the same shared key, which they can use for symmetric encryption for further communications.
146//!
147//! ```rust
148//! use devolutions_crypto::key::{generate_keypair, mix_key_exchange, KeyVersion, KeyPair};
149//!
150//! let bob_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
151//! let alice_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
152//!
153//! let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_keypair.public_key).expect("key exchange shouldn't fail");
154//!
155//! let alice_shared = mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).expect("key exchange shouldn't fail");
156//!
157//! // They now have a shared secret!
158//! assert_eq!(bob_shared, alice_shared);
159//! ```
160//!
161//! ## Derive and Encrypt
162//!
163//! This module combines password-based key derivation and symmetric encryption into a single
164//! self-contained blob. The KDF parameters needed for decryption are stored alongside the
165//! ciphertext, so callers only need to supply the original password to decrypt.
166//!
167//! ```rust
168//! use std::convert::TryFrom as _;
169//! use devolutions_crypto::derive_encrypt::{encrypt_with_password, KdfEncryptedData};
170//! use devolutions_crypto::key_derivation::Argon2;
171//! use devolutions_crypto::CiphertextVersion;
172//!
173//! let password = b"a very strong password";
174//! let params = Argon2::new().parameters();
175//! let blob = encrypt_with_password(
176//! b"secret data",
177//! password,
178//! params,
179//! CiphertextVersion::Latest,
180//! ).expect("encryption shouldn't fail");
181//!
182//! // Serialize to bytes for storage or transport.
183//! let blob_bytes: Vec<u8> = blob.into();
184//!
185//! // Deserialize and decrypt.
186//! let blob = KdfEncryptedData::try_from(blob_bytes.as_slice()).expect("deserialization shouldn't fail");
187//! let plaintext = blob.decrypt_with_password(password).expect("decryption shouldn't fail");
188//! assert_eq!(plaintext, b"secret data");
189//! ```
190//!
191//! ## PasswordHash
192//! You can use this module to hash a password and validate it afterward. This is the recommended way to verify a user password on login.
193//! ```rust
194//! use devolutions_crypto::password_hash::{hash_password, PasswordHashVersion};
195//!
196//! let password = b"somesuperstrongpa$$w0rd!";
197//!
198//! let hashed_password = hash_password(password, PasswordHashVersion::Latest).expect("hash password shouldn't fail");
199//!
200//! assert!(hashed_password.verify_password(b"somesuperstrongpa$$w0rd!"));
201//! assert!(!hashed_password.verify_password(b"someweakpa$$w0rd!"));
202//! ```
203//!
204//! ## SecretSharing
205//! This module is used to generate a key that is split in multiple `Share`
206//! and that requires a specific amount of them to regenerate the key.
207//! You can think of it as a "Break The Glass" scenario. You can
208//! generate a key using this, lock your entire data by encrypting it
209//! and then you will need, let's say, 3 out of the 5 administrators to decrypt
210//! the data. That data could also be an API key or password of a super admin account.
211//!
212//! ```rust
213//! use devolutions_crypto::secret_sharing::{generate_shared_key, join_shares, SecretSharingVersion, Share};
214//!
215//! // You want a key of 32 bytes, split between 5 people, and I want a
216//! // minimum of 3 of these shares to regenerate the key.
217//! let shares: Vec<Share> = generate_shared_key(5, 3, 32, SecretSharingVersion::Latest).expect("generation shouldn't fail with the right parameters");
218//!
219//! assert_eq!(shares.len(), 5);
220//! let key = join_shares(&shares[2..5]).expect("joining shouldn't fail with the right shares");
221//! ```
222//!
223//! ## Utils
224//!
225//! These are a bunch of functions that can
226//! be useful when dealing with the library.
227//!
228//! ### Key Generation
229//!
230//! This is a method used to generate a random key. In almost all case, the `length` parameter should be 32.
231//!
232//! ```rust
233//! use devolutions_crypto::utils::generate_key;
234//!
235//! let key = generate_key(32).expect("generate key shouldn't fail");;
236//! assert_eq!(32, key.len());
237//! ```
238//!
239//!
240//! ### Key Derivation
241//!
242//! The library exposes raw methods for key derivation with argon2 and PBKDF2. We recommend using the managed [Key Derivation](#key-derivation) module.
243//!
244//! ```rust
245//! use devolutions_crypto::utils::{generate_key, derive_key_pbkdf2};
246//! let key = b"this is a secret password";
247//! let salt = generate_key(16).expect("generate key shouldn't fail");;
248//! let iterations = 600000;
249//! let length = 32;
250//!
251//! let new_key = derive_key_pbkdf2(key, &salt, iterations, length);
252//!
253//! assert_eq!(32, new_key.len());
254//! ```
255//!
256//!
257//! # Underlying algorithms
258//! As of the current version:
259//! * Symmetric cryptography uses XChaCha20Poly1305
260//! * Asymmetric cryptography uses Curve25519.
261//! * Asymmetric encryption uses ECIES.
262//! * Key derivation uses Argon2 or PBKDF2
263//! * Key exchange uses x25519, or ECDH over Curve25519
264//! * Password Hashing uses PBKDF2-HMAC-SHA2-256
265//! * Secret Sharing uses Shamir Secret sharing over GF256
266#![allow(clippy::field_reassign_with_default)]
267
268mod argon2parameters;
269mod enums;
270mod error;
271mod header;
272
273pub mod ciphertext;
274pub mod derive_encrypt;
275pub mod key;
276pub mod key_derivation;
277pub mod online_ciphertext;
278pub mod password_hash;
279pub mod secret_sharing;
280pub mod signature;
281pub mod signing_key;
282pub mod utils;
283
284use enums::{CiphertextSubtype, PasswordHashSubtype, ShareSubtype, SignatureSubtype};
285pub use header::{Header, HeaderType};
286
287pub use enums::{
288 CiphertextVersion, DataType, KdfEncryptedDataVersion, KeyDerivationVersion, KeySubtype,
289 KeyVersion, OnlineCiphertextVersion, PasswordHashVersion, SecretSharingVersion,
290 SignatureVersion, SigningKeyVersion,
291};
292
293pub use argon2::Variant as Argon2Variant;
294pub use argon2::Version as Argon2Version;
295pub use argon2parameters::defaults as argon2parameters_defaults;
296pub use argon2parameters::Argon2Parameters;
297pub use argon2parameters::Argon2ParametersBuilder;
298pub use derive_encrypt::{encrypt_with_password, encrypt_with_password_and_aad, KdfEncryptedData};
299pub use error::{Error, Result};
300pub use key_derivation::{derive_key, Argon2, DerivationParameters, Pbkdf2};
301
302pub const DEFAULT_KEY_SIZE: usize = 32;
303pub const DEFAULT_PBKDF2_ITERATIONS: u32 = 600000;
304
305#[cfg(feature = "wbindgen")]
306pub mod wasm;