Skip to content

Commit

Permalink
Streaming API for CBC and CTR cipher modes (#410)
Browse files Browse the repository at this point in the history
* Stream cipher API

* Return a BufferUpdate struct

* Cleanup docs

* Add more tests

* Satisfy clippy

* Cleanup + PR feedback + rebase

* Add FIPS tests

* Add debug asserts on output lengths
  • Loading branch information
justsmth authored Jun 21, 2024
1 parent 05b24c0 commit 6f3885f
Show file tree
Hide file tree
Showing 7 changed files with 1,136 additions and 16 deletions.
65 changes: 61 additions & 4 deletions aws-lc-rs/src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,58 @@
//! # }
//! ```
//!
//! ### AES-128 CBC Streaming Cipher
//!
//! ```rust
//! # use std::error::Error;
//! #
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use aws_lc_rs::cipher::{
//! StreamingDecryptingKey, StreamingEncryptingKey, UnboundCipherKey, AES_128,
//! };
//! let original_message = "This is a secret message!".as_bytes();
//! let key_bytes: &[u8] = &[
//! 0xff, 0x0b, 0xe5, 0x84, 0x64, 0x0b, 0x00, 0xc8, 0x90, 0x7a, 0x4b, 0xbf, 0x82, 0x7c,
//! 0xb6, 0xd1,
//! ];
//! // Prepare ciphertext buffer
//! let mut ciphertext_buffer = vec![0u8; original_message.len() + AES_128.block_len()];
//! let ciphertext_slice = ciphertext_buffer.as_mut_slice();
//!
//! // Create StreamingEncryptingKey
//! let key = UnboundCipherKey::new(&AES_128, key_bytes).unwrap();
//! let mut encrypting_key = StreamingEncryptingKey::cbc_pkcs7(key).unwrap();
//!
//! // Encrypt
//! let mut first_update = encrypting_key
//! .update(original_message, ciphertext_slice)
//! .unwrap();
//! let first_update_len = first_update.written().len();
//! let (context, final_update) = encrypting_key.finish(first_update.remainder_mut()).unwrap();
//! let ciphertext_len = first_update_len + final_update.written().len();
//! let ciphertext = &ciphertext_slice[0..ciphertext_len];
//!
//! // Prepare plaintext buffer
//! let mut plaintext_buffer = vec![0u8; ciphertext_len + AES_128.block_len()];
//! let plaintext_slice = plaintext_buffer.as_mut_slice();
//!
//! // Create StreamingDecryptingKey
//! let key = UnboundCipherKey::new(&AES_128, key_bytes).unwrap();
//! let mut decrypting_key = StreamingDecryptingKey::cbc_pkcs7(key, context).unwrap();
//!
//! // Decrypt
//! let mut first_update = decrypting_key.update(ciphertext, plaintext_slice).unwrap();
//! let first_update_len = first_update.written().len();
//! let final_update = decrypting_key.finish(first_update.remainder_mut()).unwrap();
//! let plaintext_len = first_update_len + final_update.written().len();
//! let plaintext = &plaintext_slice[0..plaintext_len];
//!
//! assert_eq!(original_message, plaintext);
//! #
//! # Ok(())
//! # }
//! ```
//!
//! ## Constructing a `DecryptionContext` for decryption.
//!
//! ```rust
Expand Down Expand Up @@ -142,8 +194,10 @@ pub(crate) mod block;
pub(crate) mod chacha;
pub(crate) mod key;
mod padded;
mod streaming;

pub use padded::{PaddedBlockDecryptingKey, PaddedBlockEncryptingKey};
pub use streaming::{BufferUpdate, StreamingDecryptingKey, StreamingEncryptingKey};

use crate::buffer::Buffer;
use crate::error::Unspecified;
Expand Down Expand Up @@ -280,7 +334,9 @@ impl Algorithm {
&self.id
}

const fn block_len(&self) -> usize {
/// The block length of this cipher algorithm.
#[must_use]
pub const fn block_len(&self) -> usize {
self.block_len
}

Expand Down Expand Up @@ -354,8 +410,7 @@ impl UnboundCipherKey {
///
/// # Errors
///
/// * [`Unspecified`] if `key_bytes.len()` does not match the
/// length required by `algorithm`.
/// * [`Unspecified`] if `key_bytes.len()` does not match the length required by `algorithm`.
pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result<Self, Unspecified> {
let key_bytes = Buffer::new(key_bytes.to_vec());
Ok(UnboundCipherKey {
Expand Down Expand Up @@ -438,7 +493,9 @@ impl EncryptingKey {
self.less_safe_encrypt(in_out, context)
}

/// Encrypts the data provided in `in_out` in-place using the provided `CipherContext`.
/// Encrypts the data provided in `in_out` in-place using the provided `EncryptionContext`.
/// This is considered "less safe" because the caller could potentially construct
/// a `EncryptionContext` from a previously used IV (initialization vector).
/// Returns a references to the decrypted data.
///
/// # Errors
Expand Down
Loading

0 comments on commit 6f3885f

Please sign in to comment.