| Crates.io | devolutions-crypto |
| lib.rs | devolutions-crypto |
| version | 0.9.2 |
| created_at | 2019-11-22 14:22:55.293577+00 |
| updated_at | 2025-01-28 19:14:00.663029+00 |
| description | An abstraction layer for the cryptography used by Devolutions |
| homepage | https://github.com/devolutions/devolutions-crypto |
| repository | https://github.com/devolutions/devolutions-crypto |
| max_upload_size | |
| id | 183493 |
| size | 892,542 |
Cryptographic library used in Devolutions products. It is made to be fast, easy to use and misuse-resistant.
Documentation
The library is split into multiple modules, which are explained below. When
dealing with "managed" data, that includes an header and versioning, you deal
with structures like Ciphertext, PublicKey, etc.
These structures all implement TryFrom<&[u8]> and Into<Vec<u8>> which are the implemented way to serialize and deserialize data.
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);
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.
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);
Here, you will need a PublicKey to encrypt data and the corresponding
PrivateKey to decrypt it. You can generate them by using generate_keypair
in the Key module.
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);
For now, this module only deal with keypairs, as the symmetric keys are not wrapped yet.
Using generate_keypair will generate a random keypair.
Asymmetric keys have two uses. They can be used to encrypt and decrypt data and to perform a key exchange.
generate_keypairuse devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};
let keypair: KeyPair = generate_keypair(KeyVersion::Latest);
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.
KeyPair.PublicKey.PrivateKey with Bob's PublicKey. This gives her the shared key.PrivateKey with Alice's PublicKey. This gives him the shared key.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);
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.
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!"));
This module is used to generate a key that is split 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 for example
generate a key, encrypt your data and then require 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.
use devolutions_crypto::secret_sharing::{generate_shared_key, join_shares, SecretSharingVersion, Share};
// You want a key of 32 bytes, split between 5 people, and 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");
This module is used to sign data using a keypair to certify its authenticity.
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));
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 cases, the length parameter should be 32.
use devolutions_crypto::utils::generate_key;
let key = generate_key(32);
assert_eq!(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.
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());
As of the current version: