Skip to main content

Crate devolutions_crypto

Crate devolutions_crypto 

Source
Expand description

Cryptographic library used in Devolutions products. It is made to be fast, easy to use and misuse-resistant.

§Usage

§Overview

This 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, SecretKey, PublicKey, etc.

These structures all implement TryFrom<&[u8]> and Into<Vec<u8>> to serialize and deserialize data.

§Ciphertext

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. The encryption will give you a Ciphertext, which has a method to decrypt it.

§Symmetric

The library provides a SecretKey which can be used as a shared secret to encrypt messages.

use std::convert::TryFrom as _;
use devolutions_crypto::key::{generate_secret_key, KeyVersion, SecretKey};
use devolutions_crypto::ciphertext::{ encrypt_with_secret_key, CiphertextVersion, Ciphertext };

let secret_key = generate_secret_key(KeyVersion::Latest);
let data = b"somesecretdata";
let encrypted_data = encrypt_with_secret_key(data, &secret_key, CiphertextVersion::Latest).expect("encryption shouldn't fail");

// The ciphertext can be serialized to be saved somewhere, passed to another language or over the network.
let encrypted_data_vec: Vec<u8> = encrypted_data.into();

// 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_with_secret_key(&secret_key).expect("The decryption shouldn't fail");
assert_eq!(decrypted_data, data);

The key can also be passed as raw bytes.

use devolutions_crypto::utils::generate_key;
use devolutions_crypto::ciphertext::{encrypt_with_raw_key, CiphertextVersion, Ciphertext};

let key: Vec<u8> = generate_key(32).expect("generate key shouldn't fail");
let data = b"somesecretdata";

let encrypted_data: Ciphertext = encrypt_with_raw_key(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);

§Asymmetric

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);

§Key

This module provides secret keys and keypairs.

§Generation

Use generate_secret_key to a generate a random symmetric key and generate_keypair to generate a random keypair.

Asymmetric keys have two uses. They can be used to encrypt and decrypt data and to perform a key exchange.

use devolutions_crypto::key::{generate_keypair, KeyVersion, KeyPair};

let keypair: KeyPair = generate_keypair(KeyVersion::Latest);

§Key Derivation

The Key Derivation module provides a way to derive a SecretKey from a password or passphrase. The derive operation returns a SecretKey, and a DerivationParameters that can be serialized and reused to derive the same key at a later time.

Example with derive_key:

use devolutions_crypto::key_derivation::{derive_key, DerivationParameters};
use devolutions_crypto::KeyDerivationVersion;

let password = b"a very strong password";
let (secret_key, params) = derive_key(password, KeyDerivationVersion::Latest).expect("derivation should not fail");
// Serialize params to re-derive later:
let params_bytes: Vec<u8> = params.into();

Example with Argon2 (recommended):

use devolutions_crypto::key_derivation::Argon2;
let password = b"a very strong password";
let argon2 = Argon2::new();
let (secret_key, params) = argon2.derive(password).expect("derivation should not fail");
// Serialize params to re-derive later:
let params_bytes: Vec<u8> = params.into();

Example with PBKDF2:

use devolutions_crypto::key_derivation::Pbkdf2;
let password = b"a very strong password";
let pbkdf2 = Pbkdf2::new();
let (secret_key, params) = pbkdf2.derive(password).expect("derivation should not fail");

§Key Exchange

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 generate a KeyPair each.
  2. Alice and Bob exchange their PublicKey.
  3. Alice mixes 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 have the same shared key, which they can use for symmetric encryption for further communications.
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 shouldn't fail");

let alice_shared = mix_key_exchange(&alice_keypair.private_key, &bob_keypair.public_key).expect("key exchange shouldn't fail");

// They now have a shared secret!
assert_eq!(bob_shared, alice_shared);

§Derive and Encrypt

This module combines password-based key derivation and symmetric encryption into a single self-contained blob. The KDF parameters needed for decryption are stored alongside the ciphertext, so callers only need to supply the original password to decrypt.

use std::convert::TryFrom as _;
use devolutions_crypto::derive_encrypt::{encrypt_with_password, KdfEncryptedData};
use devolutions_crypto::key_derivation::Argon2;
use devolutions_crypto::CiphertextVersion;

let password = b"a very strong password";
let params = Argon2::new().parameters();
let blob = encrypt_with_password(
    b"secret data",
    password,
    params,
    CiphertextVersion::Latest,
).expect("encryption shouldn't fail");

// Serialize to bytes for storage or transport.
let blob_bytes: Vec<u8> = blob.into();

// Deserialize and decrypt.
let blob = KdfEncryptedData::try_from(blob_bytes.as_slice()).expect("deserialization shouldn't fail");
let plaintext = blob.decrypt_with_password(password).expect("decryption shouldn't fail");
assert_eq!(plaintext, b"secret data");

§PasswordHash

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, PasswordHashVersion::Latest).expect("hash password shouldn't fail");

assert!(hashed_password.verify_password(b"somesuperstrongpa$$w0rd!"));
assert!(!hashed_password.verify_password(b"someweakpa$$w0rd!"));

§SecretSharing

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 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.

use devolutions_crypto::secret_sharing::{generate_shared_key, join_shares, SecretSharingVersion, Share};

// You want a key of 32 bytes, split between 5 people, and I want 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");

§Utils

These are a bunch of functions that can be useful when dealing with the library.

§Key Generation

This is a method used to generate a random key. In almost all case, the length parameter should be 32.

use devolutions_crypto::utils::generate_key;

let key = generate_key(32).expect("generate key shouldn't fail");;
assert_eq!(32, key.len());

§Key Derivation

The library exposes raw methods for key derivation with argon2 and PBKDF2. We recommend using the managed Key Derivation module.

use devolutions_crypto::utils::{generate_key, derive_key_pbkdf2};
let key = b"this is a secret password";
let salt = generate_key(16).expect("generate key shouldn't fail");;
let iterations = 600000;
let length = 32;

let new_key = derive_key_pbkdf2(key, &salt, iterations, length);

assert_eq!(32, new_key.len());

§Underlying algorithms

As of the current version:

  • Symmetric cryptography uses XChaCha20Poly1305
  • Asymmetric cryptography uses Curve25519.
  • Asymmetric encryption uses ECIES.
  • Key derivation uses Argon2 or PBKDF2
  • Key exchange uses x25519, or ECDH over Curve25519
  • Password Hashing uses PBKDF2-HMAC-SHA2-256
  • Secret Sharing uses Shamir Secret sharing over GF256

Re-exports§

pub use derive_encrypt::encrypt_with_password;
pub use derive_encrypt::encrypt_with_password_and_aad;
pub use derive_encrypt::KdfEncryptedData;
pub use key_derivation::derive_key;
pub use key_derivation::Argon2;
pub use key_derivation::DerivationParameters;
pub use key_derivation::Pbkdf2;

Modules§

argon2parameters_defaults
ciphertext
Module for symmetric/asymmetric encryption/decryption.
derive_encrypt
key
Module for dealing with wrapped keys and key exchange.
key_derivation
Module for key derivation. Derives a key or password into a SecretKey and returns the DerivationParameters needed to reproduce the derivation.
online_ciphertext
Module for symmetric/asymmetric encryption/decryption.
password_hash
Module for password hashing and verification. Use this if you need to store user passwords.
secret_sharing
Module for creating keys split between multiple parties. Use this for “Break The Glass” scenarios or when you want to cryptographically enforce approval of multiple users.
signature
Module for signing and verifying data.
signing_key
Module for dealing with signature keys.
utils
Module for utils that does not use any of the Devolutions custom data types.

Structs§

Argon2Parameters
Parameters used to derive the password into an Argon2 hash.
Header

Enums§

Argon2Variant
The Argon2 variant.
Argon2Version
The Argon2 version.
CiphertextVersion
The versions of the encryption scheme to use.
DataType
The different data types.
Error
This crate’s error type.
KdfEncryptedDataVersion
The versions of the KDF-encrypt scheme to use.
KeyDerivationVersion
The versions of the key derivation scheme to use.
KeySubtype
KeyVersion
The versions of the key scheme to use.
OnlineCiphertextVersion
The versions of the online encryption scheme to use.
PasswordHashVersion
The versions of the password hashing scheme to use.
SecretSharingVersion
The versions of the secret sharing scheme to use.
SignatureVersion
The versions of the secret sharing scheme to use.
SigningKeyVersion

Constants§

DEFAULT_KEY_SIZE
DEFAULT_PBKDF2_ITERATIONS

Traits§

HeaderType

Type Aliases§

Result