Struct strong_box::StrongBox

source ·
pub struct StrongBox { /* 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

fn main() -> Result<(), Error> {

// 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 = StrongBox::new(old_key.clone(), [old_key]);
let new_strongbox = StrongBox::new(new_key.clone(), [new_key]);
// This StrongBox encrypts with `new_key`, but can decrypt ciphertexts
// encrypted with *either* `new_key` *or* `old_key`
let fallback_strongbox = StrongBox::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 StrongBox 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 StrongBox 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 StrongBox 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 StrongBox should be able to decrypt
assert_eq!(
    b"Hello, new world!".to_vec(),
    new_strongbox.decrypt(&ciphertext, b"new context")?
);

// Unsurprisingly, the fallback StrongBox 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 StrongBox 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 StrongBox 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 StrongBox

source

pub fn new( enc_key: impl Into<Key<[u8; 32]>>, dec_keys: impl IntoIterator<Item = impl Into<Key<[u8; 32]>>>, ) -> Self

Create a new StrongBox.

source

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

Just like StrongBox::encrypt_secret, but for data that isn’t already protected by secrecy::Secret.

source

pub fn encrypt_secret( &self, plaintext: impl Into<Key<Vec<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.

§Errors

Will return Error::Encryption or Error::Encoding in the (extremely unlikely) event something goes horribly wrong.

source

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

Decrypt a ciphertext, using any key the StrongBox knows, and validate that ciphertext was encrypted with the specified context.

§Errors

Will return Error::Decryption if the ciphertext was encrypted with a different key, or a different context. A malformed ciphertext will return Error::Decoding.

Trait Implementations§

source§

impl Clone for StrongBox

source§

fn clone(&self) -> StrongBox

Returns a copy 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 StrongBox

source§

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

Formats the value using the given formatter. 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§

default unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. 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

§

type Output = T

Should always be Self
source§

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

§

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

§

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

§

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