Skip to content

Commit a7a640c

Browse files
author
Andreas Auernhammer
committed
refactor {Enc/Dec}Writer to use Box<[u8]> instead of Vec<u8>
This commit replaces the buffer in {Enc/Dec}Writer with a Box<[u8]>. The reason is that non-sophisticated benchmarks showed that truncating the Vec after a write to the inner writer were relatively expensive. Further, this commit improves the `Counter<A>` implementation such that it now returns just a reference to the nonce instead of allocating and copying a new one per fragment.
1 parent 956c86a commit a7a640c

File tree

2 files changed

+99
-58
lines changed

2 files changed

+99
-58
lines changed

src/aead.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::error::{Exceeded, Invalid, NotAuthentic};
1+
use crate::error::{Exceeded, Invalid, NotAuthentic};
22
use std::marker::PhantomData;
33

44
pub trait Algorithm {
@@ -89,27 +89,36 @@ impl<'a, A: Algorithm> From<&'a [u8]> for Aad<'a, A> {
8989
}
9090

9191
pub(crate) struct Counter<A: Algorithm> {
92-
nonce: [u8; 8],
93-
seq_num: u32,
92+
nonce: [u8; 12],
93+
pub seq_num: u32,
94+
exceeded: bool,
9495
phantom_data: PhantomData<A>,
9596
}
9697

9798
impl<A: Algorithm> Counter<A> {
9899
pub fn zero(nonce: Nonce<A>) -> Self {
100+
let mut value = [0; 12];
101+
&mut value[..8].copy_from_slice(&nonce.0);
99102
Counter {
100-
nonce: nonce.0,
103+
nonce: value,
101104
seq_num: 0,
105+
exceeded: false,
102106
phantom_data: PhantomData,
103107
}
104108
}
105109

106-
pub fn next(&mut self) -> Result<[u8; 12], Exceeded> {
107-
let seq_num = self.seq_num.checked_add(1).ok_or(Exceeded)?;
110+
#[inline]
111+
pub fn next<'a>(&'a mut self) -> Result<&'a [u8; 12], Exceeded> {
112+
if self.exceeded {
113+
return Err(Exceeded);
114+
}
108115

109-
let mut nonce = [0; 12];
110-
&nonce[..8].copy_from_slice(self.nonce.as_ref());
111-
nonce[8..].copy_from_slice(self.seq_num.to_le_bytes().as_ref());
112-
self.seq_num = seq_num;
113-
Ok(nonce)
116+
self.nonce[8..].copy_from_slice(self.seq_num.to_le_bytes().as_ref());
117+
if let Some(seq_num) = self.seq_num.checked_add(1) {
118+
self.seq_num = seq_num;
119+
} else {
120+
self.exceeded = true;
121+
}
122+
Ok(&self.nonce)
114123
}
115124
}

src/writer.rs

Lines changed: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ use std::io::Write;
5454
pub struct EncWriter<A: Algorithm, W: Write> {
5555
inner: W,
5656
algorithm: A,
57-
buffer: Vec<u8>,
57+
buffer: Box<[u8]>,
58+
pos: usize,
5859
buf_size: usize,
5960
nonce: Counter<A>,
6061
aad: [u8; 16 + 1], // TODO: replace with [u8; A::TAG_LEN + 1]
@@ -153,7 +154,14 @@ impl<A: Algorithm, W: Write> EncWriter<A, W> {
153154
/// let aad = Aad::from("Some authenticated but not encrypted data".as_bytes());
154155
///
155156
/// let mut ciphertext: Vec<u8> = Vec::default(); // Store the ciphertext in memory.
156-
/// let mut writer = EncWriter::with_buffer_size(ciphertext, &key, nonce, aad, 64 * 1024).unwrap();
157+
/// let mut writer = EncWriter::with_buffer_size(
158+
/// &mut ciphertext,
159+
/// &key,
160+
/// nonce,
161+
/// aad,
162+
/// 64 * 1024,
163+
/// )
164+
/// .unwrap();
157165
////
158166
/// // Perform some write and flush operations
159167
/// // ...
@@ -184,7 +192,8 @@ impl<A: Algorithm, W: Write> EncWriter<A, W> {
184192
Ok(EncWriter {
185193
inner: inner,
186194
algorithm: A::new(key.as_ref()),
187-
buffer: Vec::with_capacity(buf_size + A::TAG_LEN),
195+
buffer: vec![0; buf_size + A::TAG_LEN].into_boxed_slice(),
196+
pos: 0,
188197
buf_size: buf_size,
189198
nonce: nonce,
190199
aad: associated_data,
@@ -196,19 +205,16 @@ impl<A: Algorithm, W: Write> EncWriter<A, W> {
196205

197206
/// Encrypt and authenticate the buffer and write the ciphertext
198207
/// to the inner writer.
199-
fn write_buffer(&mut self) -> io::Result<()> {
200-
self.buffer.resize(self.buffer.len() + A::TAG_LEN, 0);
208+
fn write_buffer(&mut self, len: usize) -> io::Result<()> {
201209
let ciphertext = self.algorithm.seal_in_place(
202-
&self.nonce.next()?,
210+
self.nonce.next()?,
203211
&self.aad,
204-
self.buffer.as_mut_slice(),
212+
&mut self.buffer[..len + A::TAG_LEN],
205213
)?;
206214

207215
self.panicked = true;
208216
let r = self.inner.write_all(ciphertext);
209217
self.panicked = false;
210-
211-
self.buffer.clear();
212218
r
213219
}
214220
}
@@ -222,24 +228,29 @@ impl<A: Algorithm, W: Write> Write for EncWriter<A, W> {
222228
let r: io::Result<usize> = {
223229
let n = buf.len();
224230

225-
let remaining = self.buf_size - self.buffer.len();
231+
let remaining = self.buf_size - self.pos;
226232
if buf.len() <= remaining {
227-
return self.buffer.write_all(buf).and(Ok(n));
233+
self.buffer[self.pos..self.pos + buf.len()].copy_from_slice(buf);
234+
self.pos += buf.len();
235+
return Ok(buf.len());
228236
}
229237

230-
self.buffer.extend_from_slice(&buf[..remaining]);
231-
self.write_buffer()?;
238+
self.buffer[self.pos..self.buf_size].copy_from_slice(&buf[..remaining]);
239+
self.write_buffer(self.buf_size)?;
240+
self.pos = 0;
232241

233242
let buf = &buf[remaining..];
234243
let chunks = buf.chunks(self.buf_size);
235244
chunks
236245
.clone()
237246
.take(chunks.len() - 1) // Since we take only n-1 elements...
238247
.try_for_each(|chunk| {
239-
self.buffer.extend_from_slice(chunk);
240-
self.write_buffer()
248+
self.buffer[..self.buf_size].copy_from_slice(chunk);
249+
self.write_buffer(self.buf_size)
241250
})?;
242-
self.buffer.extend_from_slice(chunks.last().unwrap()); // ... there is always a last one.
251+
let last = chunks.last().unwrap(); // ... thereis always a last one.
252+
self.buffer[..last.len()].copy_from_slice(last); // ... there is always a last one.
253+
self.pos = last.len();
243254
Ok(n)
244255
};
245256
self.errored = r.is_err();
@@ -310,21 +321,23 @@ impl<A: Algorithm, W: Write> Drop for EncWriter<A, W> {
310321
/// // Use the same associated data (AAD) that was used during encryption.
311322
/// let aad = Aad::from("Some authenticated but not encrypted data".as_bytes());
312323
///
313-
/// // The ciphertext as raw byte array.
314-
/// let ciphertext = [15, 69, 209, 72, 77, 11, 165, 233, 108, 135, 157, 217,
315-
/// 175, 75, 229, 217, 210, 88, 148, 173, 187, 7, 208, 154,
316-
/// 222, 83, 56, 20, 179, 84, 114, 2, 192, 94, 54, 239, 221, 130];
317-
///
318324
/// let mut plaintext: Vec<u8> = Vec::default(); // Store the plaintext in memory.
319-
/// let mut writer = DecWriter::new(plaintext, &key, nonce, aad);
325+
/// let mut writer = DecWriter::new(&mut plaintext, &key, nonce, aad);
326+
///
327+
/// // Passing the ciphertext as raw bytes.
328+
/// writer.write(&[14, 95, 207, 89, 77, 7, 174, 168, 96, 128, 148, 207, 224,
329+
/// 86, 236, 153 ,177, 220, 133, 123, 145, 175, 149, 241, 197,
330+
/// 153, 28, 234, 143, 173, 101,243,33]).unwrap();
320331
///
321-
/// writer.write_all(&ciphertext).unwrap();
322332
/// writer.close().unwrap(); // Complete the decryption process explicitly!
333+
///
334+
/// println!("{}", String::from_utf8_lossy(plaintext.as_slice())); // Let's print the plaintext.
323335
/// ```
324336
pub struct DecWriter<A: Algorithm, W: Write> {
325337
inner: W,
326338
algorithm: A,
327-
buffer: Vec<u8>,
339+
buffer: Box<[u8]>,
340+
pos: usize,
328341
buf_size: usize,
329342
nonce: Counter<A>,
330343
aad: [u8; 16 + 1], // TODO: replace with [u8; A::TAG_LEN + 1]
@@ -371,14 +384,18 @@ impl<A: Algorithm, W: Write> DecWriter<A, W> {
371384
/// let aad = Aad::from("Some authenticated but not encrypted data".as_bytes());
372385
///
373386
/// let mut plaintext: Vec<u8> = Vec::default(); // Store the plaintext in memory.
374-
/// let mut writer = DecWriter::new(plaintext, &key, nonce, aad);
387+
/// let mut writer = DecWriter::new(&mut plaintext, &key, nonce, aad);
375388
///
376389
/// // Perform some write and flush operations
377390
/// // ...
378391
/// // For example:
379-
/// writer.write(&[8, 222, 251, 80, 228, 234, 187, 138, 86, 169, 86, 122, 170, 158, 168, 18]).unwrap();
392+
/// writer.write(&[14, 95, 207, 89, 77, 7, 174, 168, 96, 128, 148, 207, 224,
393+
/// 86, 236, 153 ,177, 220, 133, 123, 145, 175, 149, 241, 197,
394+
/// 153, 28, 234, 143, 173, 101,243,33]).unwrap();
380395
///
381396
/// writer.close().unwrap(); // Complete the decryption process explicitly!
397+
///
398+
/// println!("{}", String::from_utf8_lossy(plaintext.as_slice())); // Let's print the plaintext.
382399
/// ```
383400
pub fn new(inner: W, key: &Key<A>, nonce: Nonce<A>, aad: Aad<A>) -> Self {
384401
Self::with_buffer_size(inner, key, nonce, aad, BUF_SIZE).unwrap()
@@ -418,14 +435,25 @@ impl<A: Algorithm, W: Write> DecWriter<A, W> {
418435
/// let aad = Aad::from("Some authenticated but not encrypted data".as_bytes());
419436
///
420437
/// let mut plaintext: Vec<u8> = Vec::default(); // Store the plaintext in memory.
421-
/// let mut writer = DecWriter::with_buffer_size(plaintext, &key, nonce, aad, 64 * 1024).unwrap();
438+
/// let mut writer = DecWriter::with_buffer_size(
439+
/// &mut plaintext,
440+
/// &key,
441+
/// nonce,
442+
/// aad,
443+
/// 64 * 1024,
444+
/// )
445+
/// .unwrap();
422446
///
423447
/// // Perform some write and flush operations
424448
/// // ...
425449
/// // For example:
426-
/// writer.write(&[8, 222, 251, 80, 228, 234, 187, 138, 86, 169, 86, 122, 170, 158, 168, 18]).unwrap();
450+
/// writer.write(&[14, 95, 207, 89, 77, 7, 174, 168, 96, 128, 148, 207, 224,
451+
/// 86, 236, 153 ,177, 220, 133, 123, 145, 175, 149, 241, 197,
452+
/// 153, 28, 234, 143, 173, 101,243,33]).unwrap();
427453
///
428-
/// writer.close().unwrap(); // Complete the encryption process explicitly!
454+
/// writer.close().unwrap(); // Complete the decryption process explicitly!
455+
///
456+
/// println!("{}", String::from_utf8_lossy(plaintext.as_slice())); // Let's print the plaintext.
429457
/// ```
430458
pub fn with_buffer_size(
431459
inner: W,
@@ -451,7 +479,8 @@ impl<A: Algorithm, W: Write> DecWriter<A, W> {
451479
Ok(DecWriter {
452480
inner: inner,
453481
algorithm: A::new(key.as_ref()),
454-
buffer: Vec::with_capacity(buf_size + A::TAG_LEN),
482+
buffer: vec![0; buf_size + A::TAG_LEN].into_boxed_slice(),
483+
pos: 0,
455484
buf_size: buf_size,
456485
nonce: nonce,
457486
aad: associated_data,
@@ -463,18 +492,14 @@ impl<A: Algorithm, W: Write> DecWriter<A, W> {
463492

464493
/// Decrypt and verifies the buffer and write the plaintext
465494
/// to the inner writer.
466-
fn write_buffer(&mut self) -> io::Result<()> {
467-
let plaintext = self.algorithm.open_in_place(
468-
&self.nonce.next()?,
469-
&self.aad,
470-
self.buffer.as_mut_slice(),
471-
)?;
495+
fn write_buffer(&mut self, len: usize) -> io::Result<()> {
496+
let plaintext =
497+
self.algorithm
498+
.open_in_place(self.nonce.next()?, &self.aad, &mut self.buffer[..len])?;
472499

473500
self.panicked = true;
474501
let r = self.inner.write_all(plaintext);
475502
self.panicked = false;
476-
477-
self.buffer.clear();
478503
r
479504
}
480505
}
@@ -487,24 +512,29 @@ impl<A: Algorithm, W: Write> Write for DecWriter<A, W> {
487512
let r: io::Result<usize> = {
488513
let n = buf.len();
489514

490-
let remaining = self.buf_size + A::TAG_LEN - self.buffer.len();
515+
let remaining = self.buf_size + A::TAG_LEN - self.pos;
491516
if buf.len() <= remaining {
492-
return self.buffer.write_all(buf).and(Ok(n));
517+
self.buffer[self.pos..self.pos + buf.len()].copy_from_slice(buf);
518+
self.pos += buf.len();
519+
return Ok(n);
493520
}
494521

495-
self.buffer.extend_from_slice(&buf[..remaining]);
496-
self.write_buffer()?;
522+
self.buffer[self.pos..].copy_from_slice(&buf[..remaining]);
523+
self.write_buffer(self.buf_size + A::TAG_LEN)?;
524+
self.pos = 0;
497525

498526
let buf = &buf[remaining..];
499527
let chunks = buf.chunks(self.buf_size + A::TAG_LEN);
500528
chunks
501529
.clone()
502530
.take(chunks.len() - 1) // Since we take only n-1 elements...
503531
.try_for_each(|chunk| {
504-
self.buffer.extend_from_slice(chunk);
505-
self.write_buffer()
532+
self.buffer.copy_from_slice(chunk);
533+
self.write_buffer(self.buf_size + A::TAG_LEN)
506534
})?;
507-
self.buffer.extend_from_slice(chunks.last().unwrap()); // ... there is always a last one.
535+
let last = chunks.last().unwrap(); // ... there is always a last one.
536+
self.buffer[..last.len()].copy_from_slice(last);
537+
self.pos = last.len();
508538
Ok(n)
509539
};
510540

@@ -575,7 +605,8 @@ impl<A: Algorithm, W: Write> EncWriter<A, W> {
575605
self.closed = true;
576606
self.aad[0] = 0x80; // For the last fragment change the AAD
577607

578-
self.write_buffer().and_then(|()| self.inner.flush())
608+
self.write_buffer(self.pos)
609+
.and_then(|()| self.inner.flush())
579610
}
580611
}
581612

@@ -609,7 +640,8 @@ impl<A: Algorithm, W: Write> DecWriter<A, W> {
609640
}
610641
self.closed = true;
611642
self.aad[0] = 0x80; // For the last fragment change the AAD
612-
self.write_buffer().and_then(|()| self.inner.flush())
643+
self.write_buffer(self.pos)
644+
.and_then(|()| self.inner.flush())
613645
}
614646
}
615647

0 commit comments

Comments
 (0)