Cryptographic library used in Devolutions products. It is made to be fast, easy to use and misuse-resistant.
The library is splitted into multiple modules, which are explained below. When
dealing with "managed" data, that includes an header and versionning, you deal
with structures like Ciphertext
, PublicKey
, etc.
These all implements TryFrom<&[u8]>
and Into<Vec<u8>>
which are the implemented way to serialize and deserialize data.
```rust use std::convert::TryFrom as ; use devolutionscrypto::utils::generatekey; use devolutionscrypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };
let key: Vec
let data = b"somesecretdata";
let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
// The ciphertext can be serialized.
let encrypteddatavec: Vec
// 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::tryfrom(encrypteddatavec.asslice()).expect("deserialization shouldn't fail");
let decrypted_data = ciphertext.decrypt(&key).expect("The decryption shouldn't fail");
asserteq!(decrypteddata, data); ```
This module contains everything related to encryption. You can use it to encrypt and decrypt data using either a shared key of a keypair.
Either way, the encryption will give you a Ciphertext
, which has a method to decrypt it.
```rust use devolutionscrypto::utils::generatekey; use devolutions_crypto::ciphertext::{ encrypt, CiphertextVersion, Ciphertext };
let key: Vec
let data = b"somesecretdata";
let encrypted_data: Ciphertext = encrypt(data, &key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
let decrypteddata = encrypteddata.decrypt(&key).expect("The decryption shouldn't fail");
asserteq!(decrypteddata, data); ```
Here, you will need a PublicKey
to encrypt data and the corresponding
PrivateKey
to decrypt it. You can generate them by using generate_keypair
or derive_keypair
in the Key module.
```rust use devolutionscrypto::key::{generatekeypair, KeyVersion, KeyPair}; use devolutionscrypto::ciphertext::{ encryptasymmetric, CiphertextVersion, Ciphertext };
let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
let data = b"somesecretdata";
let encrypteddata: Ciphertext = encryptasymmetric(data, &keypair.public_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");
let decrypteddata = encrypteddata.decryptasymmetric(&keypair.privatekey).expect("The decryption shouldn't fail");
asserteq!(decrypteddata, data); ```
For now, this module only deal with keypairs, as the symmetric keys are not wrapped yet.
You have two ways to generate a KeyPair
: Using generate_keypair
will generate a random one, using derive_keypair
will derive one from another password or key along with derivation parameters(including salt). Except in specific circumstances, you should use generate_keypair
.
Asymmetric keys have two uses. They can be used to encrypt and decrypt data and to perform a key exchange.
generate_keypair
```rust use devolutionscrypto::key::{generatekeypair, KeyVersion, KeyPair};
let keypair: KeyPair = generate_keypair(KeyVersion::Latest); ```
derive_keypair
```rust use devolutionscrypto::Argon2Parameters; use devolutionscrypto::key::{KeyVersion, KeyPair, derive_keypair};
let parameters: Argon2Parameters = Default::default(); let keypair: KeyPair = derive_keypair(b"thisisapassword", ¶meters, KeyVersion::Latest).expect("derivation should not fail"); ```
The goal of using a key exchange is to get a shared secret key between
two parties without making it possible for users listening on the conversation
to guess that shared key.
1. Alice and Bob generates a KeyPair
each.
2. Alice and Bob exchanges their PublicKey
.
3. Alice mix her PrivateKey
with Bob's PublicKey
. This gives her the shared key.
4. Bob mixes his PrivateKey
with Alice's PublicKey
. This gives him the shared key.
5. Both Bob and Alice has the same shared key, which they can use for symmetric encryption for further communications.
```rust use devolutionscrypto::key::{generatekeypair, mixkeyexchange, KeyVersion, KeyPair};
let bobkeypair: KeyPair = generatekeypair(KeyVersion::Latest); let alicekeypair: KeyPair = generatekeypair(KeyVersion::Latest);
let bobshared = mixkeyexchange(&bobkeypair.privatekey, &alicekeypair.public_key).expect("key exchange should not fail");
let aliceshared = mixkeyexchange(&alicekeypair.privatekey, &bobkeypair.public_key).expect("key exchange should not fail");
// They now have a shared secret! asserteq!(bobshared, alice_shared); ```
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. ```rust use devolutionscrypto::passwordhash::{hash_password, PasswordHashVersion};
let password = b"somesuperstrongpa$$w0rd!";
let hashedpassword = hashpassword(password, 10000, PasswordHashVersion::Latest);
assert!(hashedpassword.verifypassword(b"somesuperstrongpa$$w0rd!")); assert!(!hashedpassword.verifypassword(b"someweakpa$$w0rd!")); ```
This module is used to generate a key that is splitted in multiple Share
and that requires a specific amount of them to regenerate the key.
You can think of it as a "Break The Glass" scenario. You can
generate a key using this, lock your entire data by encrypting it
and then you will need, let's say, 3 out of the 5 administrators to decrypt
the data. That data could also be an API key or password of a super admin account.
```rust use devolutionscrypto::secretsharing::{generatesharedkey, 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
asserteq!(shares.len(), 5); let key = joinshares(&shares[2..5]).expect("joining shouldn't fail with the right shares"); ```
These are a bunch of functions that can be useful when dealing with the library.
This is a method used to generate a random key. In almost all case, the length
parameter should be 32.
```rust use devolutionscrypto::utils::generatekey;
let key = generatekey(32); asserteq!(32, key.len()); ```
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.
```rust use devolutionscrypto::utils::{generatekey, derivekey}; let key = b"this is a secret password"; let salt = generatekey(16); let iterations = 10000; let length = 32;
let newkey = derivekey(key, &salt, iterations, length);
asserteq!(32, newkey.len()); ```
As of the current version: * Symmetric cryptography uses XChaCha20Poly1305 * Asymmetric cryptography uses Curve25519. * Asymmetric encryption uses ECIES. * Key exchange uses x25519, or ECDH over Curve25519 * Password Hashing uses PBKDF2-HMAC-SHA2-256 * Secret Sharing uses Shamir Secret sharing over GF256