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