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
impl StrongBox
sourcepub fn new(
enc_key: impl Into<Key<[u8; 32]>>,
dec_keys: impl IntoIterator<Item = impl Into<Key<[u8; 32]>>>,
) -> Self
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.
sourcepub fn encrypt(
&self,
plaintext: impl Into<Vec<u8>>,
ctx: impl AsRef<[u8]> + Debug,
) -> Result<Vec<u8>, Error>
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.
sourcepub fn encrypt_secret(
&self,
plaintext: impl Into<Key<Vec<u8>>>,
ctx: impl AsRef<[u8]> + Debug,
) -> Result<Vec<u8>, Error>
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.
sourcepub fn decrypt(
&self,
ciphertext: impl AsRef<[u8]>,
ctx: impl AsRef<[u8]> + Debug,
) -> Result<Vec<u8>, Error>
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§
Auto Trait Implementations§
impl Freeze for StrongBox
impl RefUnwindSafe for StrongBox
impl Send for StrongBox
impl Sync for StrongBox
impl Unpin for StrongBox
impl UnwindSafe for StrongBox
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit)