Skip to content

Commit 6f3885f

Browse files
authored
Streaming API for CBC and CTR cipher modes (#410)
* 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
1 parent 05b24c0 commit 6f3885f

File tree

7 files changed

+1136
-16
lines changed

7 files changed

+1136
-16
lines changed

aws-lc-rs/src/cipher.rs

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,58 @@
8383
//! # }
8484
//! ```
8585
//!
86+
//! ### AES-128 CBC Streaming Cipher
87+
//!
88+
//! ```rust
89+
//! # use std::error::Error;
90+
//! #
91+
//! # fn main() -> Result<(), Box<dyn Error>> {
92+
//! use aws_lc_rs::cipher::{
93+
//! StreamingDecryptingKey, StreamingEncryptingKey, UnboundCipherKey, AES_128,
94+
//! };
95+
//! let original_message = "This is a secret message!".as_bytes();
96+
//! let key_bytes: &[u8] = &[
97+
//! 0xff, 0x0b, 0xe5, 0x84, 0x64, 0x0b, 0x00, 0xc8, 0x90, 0x7a, 0x4b, 0xbf, 0x82, 0x7c,
98+
//! 0xb6, 0xd1,
99+
//! ];
100+
//! // Prepare ciphertext buffer
101+
//! let mut ciphertext_buffer = vec![0u8; original_message.len() + AES_128.block_len()];
102+
//! let ciphertext_slice = ciphertext_buffer.as_mut_slice();
103+
//!
104+
//! // Create StreamingEncryptingKey
105+
//! let key = UnboundCipherKey::new(&AES_128, key_bytes).unwrap();
106+
//! let mut encrypting_key = StreamingEncryptingKey::cbc_pkcs7(key).unwrap();
107+
//!
108+
//! // Encrypt
109+
//! let mut first_update = encrypting_key
110+
//! .update(original_message, ciphertext_slice)
111+
//! .unwrap();
112+
//! let first_update_len = first_update.written().len();
113+
//! let (context, final_update) = encrypting_key.finish(first_update.remainder_mut()).unwrap();
114+
//! let ciphertext_len = first_update_len + final_update.written().len();
115+
//! let ciphertext = &ciphertext_slice[0..ciphertext_len];
116+
//!
117+
//! // Prepare plaintext buffer
118+
//! let mut plaintext_buffer = vec![0u8; ciphertext_len + AES_128.block_len()];
119+
//! let plaintext_slice = plaintext_buffer.as_mut_slice();
120+
//!
121+
//! // Create StreamingDecryptingKey
122+
//! let key = UnboundCipherKey::new(&AES_128, key_bytes).unwrap();
123+
//! let mut decrypting_key = StreamingDecryptingKey::cbc_pkcs7(key, context).unwrap();
124+
//!
125+
//! // Decrypt
126+
//! let mut first_update = decrypting_key.update(ciphertext, plaintext_slice).unwrap();
127+
//! let first_update_len = first_update.written().len();
128+
//! let final_update = decrypting_key.finish(first_update.remainder_mut()).unwrap();
129+
//! let plaintext_len = first_update_len + final_update.written().len();
130+
//! let plaintext = &plaintext_slice[0..plaintext_len];
131+
//!
132+
//! assert_eq!(original_message, plaintext);
133+
//! #
134+
//! # Ok(())
135+
//! # }
136+
//! ```
137+
//!
86138
//! ## Constructing a `DecryptionContext` for decryption.
87139
//!
88140
//! ```rust
@@ -142,8 +194,10 @@ pub(crate) mod block;
142194
pub(crate) mod chacha;
143195
pub(crate) mod key;
144196
mod padded;
197+
mod streaming;
145198

146199
pub use padded::{PaddedBlockDecryptingKey, PaddedBlockEncryptingKey};
200+
pub use streaming::{BufferUpdate, StreamingDecryptingKey, StreamingEncryptingKey};
147201

148202
use crate::buffer::Buffer;
149203
use crate::error::Unspecified;
@@ -280,7 +334,9 @@ impl Algorithm {
280334
&self.id
281335
}
282336

283-
const fn block_len(&self) -> usize {
337+
/// The block length of this cipher algorithm.
338+
#[must_use]
339+
pub const fn block_len(&self) -> usize {
284340
self.block_len
285341
}
286342

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

441-
/// Encrypts the data provided in `in_out` in-place using the provided `CipherContext`.
496+
/// Encrypts the data provided in `in_out` in-place using the provided `EncryptionContext`.
497+
/// This is considered "less safe" because the caller could potentially construct
498+
/// a `EncryptionContext` from a previously used IV (initialization vector).
442499
/// Returns a references to the decrypted data.
443500
///
444501
/// # Errors

0 commit comments

Comments
 (0)