RingCryptor

Struct RingCryptor 

Source
pub struct RingCryptor<'a> { /* private fields */ }
Expand description

A cryptor that uses cryptographic primitives from the ring crate.

If a user wants to encrypt a plaintext, they can use one of the .seal_* methods of the cryptor. In a nutshell, the encryption logic is the following:

  • Choose a key derivation and encryption algorithm.
  • Generate the metadata for these algorithms.
  • Serialize the metadata into a buffer large enough to hold the ciphertext and its tag.
  • Copy the plaintext in a specific position within the buffer.
  • Derive a symmetric key from a passphrase, if the PBKDF2 key derivation algorithm is used.
  • Encrypt the data in place. The original plaintext is not affected since it’s a copy.
  • Return the buffer with the serialized metadata, ciphertext and tag.

If a user wants to decrypt a plaintext, they can use one of the .open_* methods of the cryptor. In a nutshell, the decryption logic is the following:

  • Deserialize the metadata from the buffer header. Return an error if they are corrupted or don’t exist.
  • Copy the ciphertext into a new buffer.
  • Derive a symmetric key from a passphrase, if the PBKDF2 key derivation algorithm is used.
  • Decrypt the data in place, or return a decryption error. The original ciphertext is not affected, since it’s a copy.
  • Return the plaintext.

The user can skip some of the copies and allocations, depending on which cryptor methods they choose to use.

§Examples

The simplest way to encrypt a plaintext with a passprhase is the following:

use tindercrypt::cryptors::RingCryptor;

let plaintext = "The cake is a lie".as_bytes();
let pass = "My secret passphrase".as_bytes();
let cryptor = RingCryptor::new();

let ciphertext = cryptor.seal_with_passphrase(pass, plaintext)?;
let plaintext2 = cryptor.open(pass, &ciphertext)?;
assert_eq!(plaintext2, plaintext);

If the user can create their own buffers beforehand, the no-allocation path is the following:

use tindercrypt::metadata::Metadata;
use tindercrypt::cryptors::RingCryptor;

let plaintext = "The cake is a lie".as_bytes();
let pass = "My secret passphrase".as_bytes();
let cryptor = RingCryptor::new();

// The user can create this buffer beforehand.
let meta = Metadata::generate_for_passphrase(plaintext.len());
let (mut _buf, meta_size) = meta.to_buf();
let mut buf = &mut _buf[meta_size..];
buf[..plaintext.len()].copy_from_slice(plaintext);

// The user should derive the key from the passphrase.
let key = RingCryptor::derive_key(&meta, pass)?;

// These methods will not perform any allocation, and will encrypt/decrypt
// the data in place.
cryptor.seal_in_place(&meta, &key, buf)?;
cryptor.open_in_place(&meta, &key, buf)?;
assert_eq!(&buf[..plaintext.len()], plaintext);

The user is also free to specify their own metadata for the encryption process, or use additional associated data (AAD). In the following example, the user instructs the cryptor to derive a symmetric key with 10 million PBKDF2 iterations, use the ChaCha20-Poly1305 encryption algorithm and bind the ciphertext with some AAD:

use tindercrypt::metadata;
use tindercrypt::cryptors::RingCryptor;

let plaintext = "The cake is a lie".as_bytes();
let pass = "My secret passphrase".as_bytes();
let aad = "My encryption context".as_bytes();
let cryptor = RingCryptor::new().with_aad(aad); // Set the AAD.

// Create the Metadata struct.
let mut key_deriv_meta = metadata::KeyDerivationMetadata::generate();
key_deriv_meta.iterations = 10000000; // 10 million PBKDF2 iterations
let mut key_deriv_algo = metadata::KeyDerivationAlgorithm::PBKDF2(key_deriv_meta);
let enc_meta = metadata::EncryptionMetadata::generate();
let enc_algo = metadata::EncryptionAlgorithm::ChaCha20Poly1305(enc_meta);
let meta = metadata::Metadata::new(key_deriv_algo, enc_algo, plaintext.len());

// Serialize the Metadata struct into a buffer and copy the plaintext in it.
let (mut buf, meta_size) = meta.to_buf();
buf[meta_size..meta_size + plaintext.len()].copy_from_slice(&plaintext);

// Derive the key from the passphrase.
let key = RingCryptor::derive_key(&meta, pass)?;

// Encrypt and decrypt the data.
let ciphertext = cryptor.seal_with_meta(&meta, &key, &mut buf[meta_size..])?;
assert_eq!(cryptor.open(pass, &ciphertext)?, plaintext);

Implementations§

Source§

impl<'a> RingCryptor<'a>

Source

pub fn new() -> Self

Create a new cryptor instance.

Source

pub fn with_aad(self, aad: &'a [u8]) -> Self

Specify the additional associated data (AAD) to be used.

Normally, when encrypting/decrypting a data buffer, the user needs to provide just a key. In some cases though, especially when the same key is used multiple times, we may want to ensure that the data we’re decrypting are the expected ones.

By specifying associated data during the encryption, we bind them to the ciphertext. The associated data are not stored with the ciphertext, but are necessary to decrypt the data. This way, attempts to “cut-and-paste” a valid ciphertext into a different context are detected and rejected.

Source

pub fn get_key_size(enc_algo: &EncryptionAlgorithm) -> usize

Get the proper key size for the encryption algorithm.

§Examples
use tindercrypt::metadata;
use tindercrypt::cryptors::RingCryptor;

let enc_meta = metadata::EncryptionMetadata::generate();
let enc_algo = metadata::EncryptionAlgorithm::ChaCha20Poly1305(enc_meta);

// The ChaCha20 cipher requires a 256-bit key.
assert_eq!(RingCryptor::get_key_size(&enc_algo), 32);
Source

pub fn verify_key_size( enc_algo: &EncryptionAlgorithm, key: &[u8], ) -> Result<(), Error>

Verify that the key size matches the encryption algorithm.

Keys of different size will fail verification with errors::Error::KeySizeMismatch.

§Examples
use tindercrypt::metadata;
use tindercrypt::errors::Error;
use tindercrypt::cryptors::RingCryptor;

let enc_meta = metadata::EncryptionMetadata::generate();
let enc_algo = metadata::EncryptionAlgorithm::ChaCha20Poly1305(enc_meta);

// The ChaCha20 cipher requires a 256-bit key.
let key = vec![9u8; 32];
assert_eq!(RingCryptor::verify_key_size(&enc_algo, &[]), Err(Error::KeySizeMismatch));
assert_eq!(RingCryptor::verify_key_size(&enc_algo, &key), Ok(()));
Source

pub fn derive_key_no_alloc( meta: &Metadata, secret: &[u8], key: &mut [u8], ) -> Result<(), Error>

Derive a key from the provided secret and metadata, with no allocation.

This function is useful for those that want to manage the key buffer themselves, either for performance or security reasons.

Depending on the key derivation algorithm in the metadata, this function will derive a key from secret and store it into key. If the key derivation algorithm is metadata::KeyDerivationAlgorithm::None, then the secret will just be copied to key.

If the key buffer does not match the required key size, this function will return an error (see RingCryptor::verify_key_size).

§Examples
use tindercrypt::metadata;
use tindercrypt::errors::Error;
use tindercrypt::cryptors::RingCryptor;

let meta = metadata::Metadata::generate_for_passphrase(0);

let pass = "My secret passphrase".as_bytes();
let mut key = [0u8; 32];

assert_eq!(RingCryptor::derive_key_no_alloc(&meta, &pass, &mut key), Ok(()));
Source

pub fn derive_key( meta: &Metadata, secret: &[u8], ) -> Result<Zeroizing<Vec<u8>>, Error>

Derive a key from the provided secret and metadata.

This function is useful for those that want an easy and safe way to derive a key. Compared to RingCryptor::derive_key_no_alloc, it:

  • Allocates and returns a key buffer with the proper size.
  • Ensures that the key will be safely erased from memory after use, with the help of the zeroize crate.
§Examples
use tindercrypt::metadata;
use tindercrypt::errors::Error;
use tindercrypt::cryptors::RingCryptor;

let meta = metadata::Metadata::generate_for_passphrase(0);

let pass = "My secret passphrase".as_bytes();
let key = RingCryptor::derive_key(&meta, &pass)?;
Source

pub fn seal_in_place( &self, meta: &Metadata, key: &[u8], buf: &mut [u8], ) -> Result<usize, Error>

Encrypt (seal) the data buffer in place.

This method accepts a metadata instance, a key and a data buffer, that contains the plaintext and enough space for the tag. Key derivation, if required, must be performed by the user beforehand (see RingCryptor::derive_key).

This method seals the data in place, using the encryption algorithm specified in the metadata. It is much faster than the seal_with_* methods that this cryptor provides, since it doesn’t perform any allocations. The drawback is that the plaintext is not preserved and that the user must create the proper buffer layout beforehand.

Source

pub fn seal_with_meta( &self, meta: &Metadata, key: &[u8], plaintext: &[u8], ) -> Result<Vec<u8>, Error>

Encrypt (seal) the data buffer using the provided metadata.

This method accepts a metadata instance, a key and the plaintext. Key derivation, if required, must be performed by the user beforehand (see RingCryptor::derive_key).

This method serializes the metadata instance to a buffer, copies the plaintext in it and then seals it in place. This way, the plaintext is preserved, at the cost of an extra copy.

Source

pub fn seal_with_key( &self, key: &[u8], plaintext: &[u8], ) -> Result<Vec<u8>, Error>

Encrypt (seal) the data buffer using a symmetric key.

This method accepts a metadata instance, a symmetric key and the plaintext.

It generates a metadata instance and then uses the .seal_with_meta() method to seal the data. The plaintext will be preserved, at the cost of an extra copy.

Source

pub fn seal_with_passphrase( &self, pass: &[u8], plaintext: &[u8], ) -> Result<Vec<u8>, Error>

Encrypt (seal) the data buffer using a passphrase.

This method accepts a metadata instance, a passphrase and the plaintext.

It generates a metadata instance with the proper key derivation algorithm, derives the key from the passphrase, and then uses the .seal_with_meta() method to seal the data. The plaintext will be preserved, at the cost of an extra copy.

Source

pub fn open_in_place( &self, meta: &Metadata, key: &[u8], buf: &mut [u8], ) -> Result<usize, Error>

Decrypt (open) the data buffer in place.

This method accepts a metadata instance, a key and a data buffer, that contains the plaintext and enough space for the tag. Key derivation, if required, must be performed by the user beforehand (see RingCryptor::derive_key).

This method opens the data in place, using the encryption algorithm specified in the metadata. It is much faster than the other open* methods that this cryptor provides, since it doesn’t perform any allocations. The drawback is that the ciphertext is not preserved.

Source

pub fn open_with_meta( &self, meta: &Metadata, key: &[u8], ciphertext: &[u8], ) -> Result<Vec<u8>, Error>

Decrypt (open) the data buffer using the provided metadata.

This method accepts a metadata instance, a key and the ciphertext. Key derivation, if required, must be performed by the user beforehand (see RingCryptor::derive_key).

This method copies the ciphertext to a new buffer and decrypts (opens) it in place. Then, it returns the buffer with the plaintext. This way, the ciphertext is preserved, at the cost of an extra copy.

Note: By “ciphertext” we don’t refer to the whole buffer that the seal_* methods produce. We refer to the part with the encrypted payload, which does not include the metadata. For more info on how to extract this part, see the examples in the RingCryptor documentation.

Source

pub fn open(&self, secret: &[u8], buf: &[u8]) -> Result<Vec<u8>, Error>

Decrypt (open) the data buffer.

This method accepts a secret value (either a key or a passphrase) and a data buffer that contains the serialized metadata and the ciphertext.

It deserializes the metadata and extracts the ciphertext from the buffer. Depending on the key derivation algorithm, this method may derive a key from the provided passpphrase using the values in the deserialized metadata. Then, it uses .open_with_meta() to decrypt the ciphertext. The buffer will be preserved, at the cost of an extra copy.

Trait Implementations§

Source§

impl<'a> Clone for RingCryptor<'a>

Source§

fn clone(&self) -> RingCryptor<'a>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a> Debug for RingCryptor<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a> PartialEq for RingCryptor<'a>

Source§

fn eq(&self, other: &RingCryptor<'a>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<'a> Copy for RingCryptor<'a>

Source§

impl<'a> StructuralPartialEq for RingCryptor<'a>

Auto Trait Implementations§

§

impl<'a> Freeze for RingCryptor<'a>

§

impl<'a> RefUnwindSafe for RingCryptor<'a>

§

impl<'a> Send for RingCryptor<'a>

§

impl<'a> Sync for RingCryptor<'a>

§

impl<'a> Unpin for RingCryptor<'a>

§

impl<'a> UnwindSafe for RingCryptor<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V