Struct StaticStrongBox

Source
pub struct StaticStrongBox { /* private fields */ }
Expand description

A secure symmetric encryption container, supporting key rotation and AAD contexts.

This is your basic, Mark 1 mod 0 StrongBox. Given an encryption key, it will encrypt data all day long with a modern, fast cipher (ChaCha20) with integrity protection and authenticated additional data (using Poly1305). If provided with one or more decryption keys, it will decrypt data that was encrypted with any of those keys, giving you the ability to “rotate” your key over time, by creating a new key, making it the new encryption key, and keeping the old key in the set of “decryption” keys until such time as all data has been re-encrypted with the new key.

The “authenticated additional data” is a mouthful, but what it means is that when you encrypt data, you provide the encryption with a “context”, such as the ID of the user that the encrypted data belongs to. When you decrypt the data again, you provide the ID of the user the data belongs to, and if they don’t match, decryption fails. Why is that useful? Because if an attacker gets write access to the database, and moves encrypted data from one user to another, Bad Things can happen. This Security StackExchange answer is an excellent explanation of why an encryption context is useful.

§Example

use strong_box::{Error, StaticStrongBox, StrongBox};

// A couple of keys are always useful to have
let old_key = strong_box::generate_key();
let new_key = strong_box::generate_key();

let old_strongbox = StaticStrongBox::new(old_key.clone(), [old_key.clone()]);
let new_strongbox = StaticStrongBox::new(new_key.clone(), [new_key.clone()]);
// This StaticStrongBox encrypts with `new_key`, but can decrypt ciphertexts
// encrypted with *either* `new_key` *or* `old_key`
let fallback_strongbox = StaticStrongBox::new(new_key.clone(), vec![new_key, old_key]);

/////////////////////////////////////////////////////////
// A ciphertext encrypted using the old key

let ciphertext = old_strongbox.encrypt(b"Hello, old world!", b"some context")?;

// We'd *hope* that we can decrypt what we encrypted
assert_eq!(
    b"Hello, old world!".to_vec(),
    old_strongbox.decrypt(&ciphertext, b"some context")?
);

// A StaticStrongBox that uses a different key won't be able to decrypt
let result = new_strongbox.decrypt(&ciphertext, b"some context");
assert!(matches!(result, Err(Error::Decryption)));

// Also, a StaticStrongBox that uses the right key won't decrypt if the context isn't the
// same as was used to encrypt
let result = old_strongbox.decrypt(&ciphertext, b"a different context");
assert!(matches!(result, Err(Error::Decryption)));

// However, magic of magicks, the fallback StaticStrongBox can do the job!
assert_eq!(
    b"Hello, old world!".to_vec(),
    fallback_strongbox.decrypt(&ciphertext, b"some context")?
);

//////////////////////////////////////////////////////////////
// Now, let's try a ciphertext encrypted using the new key

let ciphertext = new_strongbox.encrypt(b"Hello, new world!", b"new context")?;

// Again, the same StaticStrongBox should be able to decrypt
assert_eq!(
    b"Hello, new world!".to_vec(),
    new_strongbox.decrypt(&ciphertext, b"new context")?
);

// Unsurprisingly, the fallback StaticStrongBox can decrypt it too, as it uses the same key
assert_eq!(
    b"Hello, new world!".to_vec(),
    fallback_strongbox.decrypt(&ciphertext, b"new context")?
);

// A StaticStrongBox using just the old key won't be able to decrypt, though
let result = old_strongbox.decrypt(&ciphertext, b"new context");
assert!(matches!(result, Err(Error::Decryption)));

// And again, the right StaticStrongBox but the wrong context won't decrypt
let result = new_strongbox.decrypt(&ciphertext, b"some other context");
assert!(matches!(result, Err(Error::Decryption)));

Implementations§

Source§

impl StaticStrongBox

Source

pub fn new( enc_key: impl Into<Key>, dec_keys: impl IntoIterator<Item = impl Into<Key>>, ) -> Self

Create a new StaticStrongBox.

Trait Implementations§

Source§

impl Clone for StaticStrongBox

Source§

fn clone(&self) -> StaticStrongBox

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 Debug for StaticStrongBox

Source§

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

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

impl StrongBox for StaticStrongBox

Source§

fn encrypt( &self, plaintext: impl AsRef<[u8]>, ctx: impl AsRef<[u8]> + Debug, ) -> Result<Vec<u8>, Error>

Encrypt secret data using the StrongBox’s encryption key, within the StrongBox’s specified context. Read more
Source§

fn decrypt( &self, ciphertext: impl AsRef<[u8]>, ctx: impl AsRef<[u8]> + Debug, ) -> Result<Vec<u8>, Error>

Decrypt a ciphertext, using any valid key for the StrongBox, and validate that the ciphertext was encrypted with the specified context. Read more

Auto Trait Implementations§

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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> Same for T

Source§

type Output = T

Should always be Self
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

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more