devolutions_crypto/
lib.rs

1//! [![Build Status](https://dev.azure.com/devolutions-net/Open%20Source/_apis/build/status/devolutions-crypto?branchName=master)](https://dev.azure.com/devolutions-net/Open%20Source/_build/latest?definitionId=170&branchName=master) [![](https://meritbadge.herokuapp.com/devolutions-crypto)](https://crates.io/crates/devolutions-crypto)  
2//! Cryptographic library used in Devolutions products. It is made to be fast, easy to use and misuse-resistant.
3//!
4//! # Usage
5//! * [Overview](#overview)
6//! * [Ciphertext Module](#ciphertext)
7//!     * [Symmetric Encryption](#symmetric)
8//!     * [Asymmetric Encryption](#asymmetric)
9//! * [Key Module](#key)
10//!     * [Key Generation/Derivation](#generationderivation)
11//!     * [Key Exchange](#key-exchange)
12//! * [PasswordHash Module](#passwordhash)
13//! * [SecretSharing Module](#secretsharing)
14//! * [Utils Module](#utils)
15//!     * [Key Generation](#key-generation)
16//!     * [Key Derivation](#key-derivation)
17//!
18//! ## Overview
19//!
20//! The library is splitted into multiple modules, which are explained below. When
21//! dealing with "managed" data, that includes an header and versionning, you deal
22//! with structures like `Ciphertext`, `PublicKey`, etc.  
23//!
24//! These all implements `TryFrom<&[u8]>` and `Into<Vec<u8>>` which are the implemented way to serialize and deserialize data.
25//!
26//! ```rust
27//! use std::convert::TryFrom as _;
28//! use devolutions_crypto::utils::generate_key;
29//! use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };
30//!
31//! let key: Vec<u8> = generate_key(32);
32//!
33//! let data = b"somesecretdata";
34//!
35//! let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
36//!
37//! // The ciphertext can be serialized.
38//! let encrypted_data_vec: Vec<u8> = encrypted_data.into();
39//!
40//! // This data can be saved somewhere, passed to another language or over the network
41//! // ...
42//! // When you receive the data as a byte array, you can deserialize it into a struct using TryFrom
43//!
44//! let ciphertext = Ciphertext::try_from(encrypted_data_vec.as_slice()).expect("deserialization shouldn't fail");
45//!
46//! let decrypted_data = ciphertext.decrypt(&key).expect("The decryption shouldn't fail");
47//!
48//! assert_eq!(decrypted_data, data);
49//! ```
50//!
51//! ## Ciphertext
52//!
53//! This module contains everything related to encryption. You can use it to encrypt and decrypt data using either a shared key of a keypair.  
54//! Either way, the encryption will give you a `Ciphertext`, which has a method to decrypt it.
55//!
56//! ### Symmetric
57//!
58//! ```rust
59//! use devolutions_crypto::utils::generate_key;
60//! use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };
61//!
62//! let key: Vec<u8> = generate_key(32);
63//!
64//! let data = b"somesecretdata";
65//!
66//! let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
67//!
68//! let decrypted_data = encrypted_data.decrypt(&key).expect("The decryption shouldn't fail");
69//!
70//! assert_eq!(decrypted_data, data);
71//! ```
72//!
73//! ### Asymmetric
74//! Here, you will need a `PublicKey` to encrypt data and the corresponding
75//! `PrivateKey` to decrypt it. You can generate them by using `generate_keypair`
76//! in the [Key module](#key).
77//!
78//! ```rust
79//! use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
80//! use devolutions_crypto::ciphertext::{ encrypt_asymmetric, CiphertextVersion, Ciphertext };
81//!
82//! let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
83//!
84//! let data = b"somesecretdata";
85//!
86//! let encrypted_data: Ciphertext = encrypt_asymmetric(data, &keypair.public_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
87//!
88//! let decrypted_data = encrypted_data.decrypt_asymmetric(&keypair.private_key).expect("The decryption shouldn't fail");
89//!
90//! assert_eq!(decrypted_data, data);
91//! ```
92//!
93//! ## Key
94//!
95//! For now, this module only deal with keypairs, as the symmetric keys are not wrapped yet.
96//!
97//! ### Generation/Derivation
98//!
99//! Using `generate_keypair` will generate a random keypair.
100//!
101//! Asymmetric keys have two uses. They can be used to [encrypt and decrypt data](##asymmetric) and to perform a [key exchange](#key-exchange).
102//!
103//! #### `generate_keypair`
104//! ```rust
105//! use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
106//!
107//! let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
108//! ```
109//!
110//! ### Key Exchange
111//!
112//! The goal of using a key exchange is to get a shared secret key between
113//! two parties without making it possible for users listening on the conversation
114//! to guess that shared key.
115//! 1. Alice and Bob generates a `KeyPair` each.
116//! 2. Alice and Bob exchanges their `PublicKey`.
117//! 3. Alice mix her `PrivateKey` with Bob's `PublicKey`. This gives her the shared key.
118//! 4. Bob mixes his `PrivateKey` with Alice's `PublicKey`. This gives him the shared key.
119//! 5. Both Bob and Alice has the same shared key, which they can use for symmetric encryption for further communications.
120//!
121//! ```rust
122//! use devolutions_crypto::key::{generate_keypair, mix_key_exchange, KeyVersion, KeyPair};
123//!
124//! let bob_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
125//! let alice_keypair: KeyPair = generate_keypair(KeyVersion::Latest);
126//!
127//! let bob_shared = mix_key_exchange(&bob_keypair.private_key, &alice_keypair.public_key).expect("key exchange should not fail");
128//!
129//! let alice_shared = mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).expect("key exchange should not fail");
130//!
131//! // They now have a shared secret!
132//! assert_eq!(bob_shared, alice_shared);
133//! ```
134//!
135//! ## PasswordHash
136//! 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.
137//! ```rust
138//! use devolutions_crypto::password_hash::{hash_password, PasswordHashVersion};
139//!
140//! let password = b"somesuperstrongpa$$w0rd!";
141//!
142//! let hashed_password = hash_password(password, 10000, PasswordHashVersion::Latest);
143//!
144//! assert!(hashed_password.verify_password(b"somesuperstrongpa$$w0rd!"));
145//! assert!(!hashed_password.verify_password(b"someweakpa$$w0rd!"));
146//! ```
147//!
148//! ## SecretSharing
149//! This module is used to generate a key that is splitted in multiple `Share`
150//! and that requires a specific amount of them to regenerate the key.  
151//! You can think of it as a "Break The Glass" scenario. You can
152//! generate a key using this, lock your entire data by encrypting it
153//! and then you will need, let's say, 3 out of the 5 administrators to decrypt
154//! the data. That data could also be an API key or password of a super admin account.
155//!
156//! ```rust
157//! use devolutions_crypto::secret_sharing::{generate_shared_key, join_shares, SecretSharingVersion, Share};
158//!
159//! // You want a key of 32 bytes, splitted between 5 people, and I want a
160//! // minimum of 3 of these shares to regenerate the key.
161//! let shares: Vec<Share> = generate_shared_key(5, 3, 32, SecretSharingVersion::Latest).expect("generation shouldn't fail with the right parameters");
162//!
163//! assert_eq!(shares.len(), 5);
164//! let key = join_shares(&shares[2..5]).expect("joining shouldn't fail with the right shares");
165//! ```
166//!
167//! ## Utils
168//!
169//! These are a bunch of functions that can
170//! be useful when dealing with the library.
171//!
172//! ### Key Generation
173//!
174//! This is a method used to generate a random key. In almost all case, the `length` parameter should be 32.
175//!
176//! ```rust
177//! use devolutions_crypto::utils::generate_key;
178//!
179//! let key = generate_key(32);
180//! assert_eq!(32, key.len());
181//! ```
182//!
183//! ### Key Derivation
184//!
185//! This is a method used to generate a key from a password or another key. Useful for password-dependant cryptography. Salt should be a random 16 bytes array if possible and iterations should be 10000 or configurable by the user.
186//!
187//! ```rust
188//! use devolutions_crypto::utils::{generate_key, derive_key_pbkdf2};
189//! let key = b"this is a secret password";
190//! let salt = generate_key(16);
191//! let iterations = 10000;
192//! let length = 32;
193//!
194//! let new_key = derive_key_pbkdf2(key, &salt, iterations, length);
195//!
196//! assert_eq!(32, new_key.len());
197//! ```
198//!
199//! # Underlying algorithms
200//! As of the current version:
201//!  * Symmetric cryptography uses XChaCha20Poly1305
202//!  * Asymmetric cryptography uses Curve25519.
203//!  * Asymmetric encryption uses ECIES.
204//!  * Key exchange uses x25519, or ECDH over Curve25519
205//!  * Password Hashing uses PBKDF2-HMAC-SHA2-256
206//!  * Secret Sharing uses Shamir Secret sharing over GF256
207#![allow(clippy::field_reassign_with_default)]
208
209mod argon2parameters;
210mod enums;
211mod error;
212mod header;
213
214pub mod ciphertext;
215pub mod key;
216pub mod online_ciphertext;
217pub mod password_hash;
218pub mod secret_sharing;
219pub mod signature;
220pub mod signing_key;
221pub mod utils;
222
223use enums::{CiphertextSubtype, KeySubtype, PasswordHashSubtype, ShareSubtype, SignatureSubtype};
224pub use header::{Header, HeaderType};
225
226pub use enums::{
227    CiphertextVersion, DataType, KeyVersion, OnlineCiphertextVersion, PasswordHashVersion,
228    SecretSharingVersion, SignatureVersion, SigningKeyVersion,
229};
230
231pub use argon2::Variant as Argon2Variant;
232pub use argon2::Version as Argon2Version;
233pub use argon2parameters::defaults as argon2parameters_defaults;
234pub use argon2parameters::Argon2Parameters;
235pub use argon2parameters::Argon2ParametersBuilder;
236pub use error::{Error, Result};
237
238pub const DEFAULT_KEY_SIZE: usize = 32;
239pub const DEFAULT_PBKDF2_ITERATIONS: u32 = 10000;
240
241#[cfg(feature = "wbindgen")]
242pub mod wasm;