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>
impl<'a> RingCryptor<'a>
Sourcepub fn with_aad(self, aad: &'a [u8]) -> Self
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.
Sourcepub fn get_key_size(enc_algo: &EncryptionAlgorithm) -> usize
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);Sourcepub fn verify_key_size(
enc_algo: &EncryptionAlgorithm,
key: &[u8],
) -> Result<(), Error>
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(()));Sourcepub fn derive_key_no_alloc(
meta: &Metadata,
secret: &[u8],
key: &mut [u8],
) -> Result<(), Error>
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(()));Sourcepub fn derive_key(
meta: &Metadata,
secret: &[u8],
) -> Result<Zeroizing<Vec<u8>>, Error>
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
zeroizecrate.
§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)?;
Sourcepub fn seal_in_place(
&self,
meta: &Metadata,
key: &[u8],
buf: &mut [u8],
) -> Result<usize, Error>
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.
Sourcepub fn seal_with_meta(
&self,
meta: &Metadata,
key: &[u8],
plaintext: &[u8],
) -> Result<Vec<u8>, Error>
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.
Sourcepub fn seal_with_key(
&self,
key: &[u8],
plaintext: &[u8],
) -> Result<Vec<u8>, Error>
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.
Sourcepub fn seal_with_passphrase(
&self,
pass: &[u8],
plaintext: &[u8],
) -> Result<Vec<u8>, Error>
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.
Sourcepub fn open_in_place(
&self,
meta: &Metadata,
key: &[u8],
buf: &mut [u8],
) -> Result<usize, Error>
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.
Sourcepub fn open_with_meta(
&self,
meta: &Metadata,
key: &[u8],
ciphertext: &[u8],
) -> Result<Vec<u8>, Error>
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.
Sourcepub fn open(&self, secret: &[u8], buf: &[u8]) -> Result<Vec<u8>, Error>
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>
impl<'a> Clone for RingCryptor<'a>
Source§fn clone(&self) -> RingCryptor<'a>
fn clone(&self) -> RingCryptor<'a>
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more