summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-11-03 13:17:30 +0100
committerJustus Winter <justus@sequoia-pgp.org>2021-11-03 13:21:16 +0100
commitbb4d049aab46ba0303d7e7d683f836f4ea9d5aa6 (patch)
tree178012410415503d7b3d7757acf53bf69bcd9529
parent478d57a0a31e2981b29b735bc643d3ebfcc06164 (diff)
openpgp: Avoid double buffering in symmetric::Decryptor.
- Fixes #773.
-rw-r--r--openpgp/src/crypto/symmetric.rs78
1 files changed, 19 insertions, 59 deletions
diff --git a/openpgp/src/crypto/symmetric.rs b/openpgp/src/crypto/symmetric.rs
index 6245d08a..de24e00a 100644
--- a/openpgp/src/crypto/symmetric.rs
+++ b/openpgp/src/crypto/symmetric.rs
@@ -6,7 +6,7 @@ use std::fmt;
use crate::Result;
use crate::SymmetricAlgorithm;
-use crate::{vec_resize, vec_truncate};
+use crate::vec_resize;
use crate::{
parse::Cookie,
};
@@ -48,8 +48,6 @@ pub struct Decryptor<'a> {
block_size: usize,
// Up to a block of unread data.
buffer: Vec<u8>,
- // Ciphertext buffer.
- ciphertext: Vec<u8>,
}
assert_send_and_sync!(Decryptor<'_>);
@@ -82,44 +80,10 @@ impl<'a> Decryptor<'a> {
dec,
block_size,
buffer: Vec::with_capacity(block_size),
- ciphertext: Vec::with_capacity(8 * 1024),
})
}
}
-// Fills `buffer` with data from `R` and returns the number of bytes
-// actually read. This will only return less than `buffer.len()`
-// bytes if the end of the file is reached or an error is encountered.
-fn read_exact<R: io::Read>(reader: &mut R, mut buffer: &mut [u8])
- -> io::Result<usize>
-{
- let mut read = 0;
-
- while !buffer.is_empty() {
- match reader.read(buffer) {
- Ok(0) => break,
- Ok(n) => {
- read += n;
- let tmp = buffer;
- buffer = &mut tmp[n..];
- },
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
- Err(e) => {
- // We don't buffer the error. Instead, we assume that
- // the same error will be encountered if the user
- // tries to read from source again.
- if read > 0 {
- return Ok(read);
- } else {
- return Err(e);
- }
- },
- }
- }
-
- Ok(read)
-}
-
// Note: this implementation tries *very* hard to make sure we don't
// gratuitiously do a short read. Specifically, if the return value
// is less than `plaintext.len()`, then it is either because we
@@ -143,22 +107,21 @@ impl<'a> io::Read for Decryptor<'a> {
// 2. Decrypt as many whole blocks as `plaintext` can hold.
let mut to_copy
= ((plaintext.len() - pos) / self.block_size) * self.block_size;
- vec_resize(&mut self.ciphertext, to_copy);
- let result = read_exact(&mut self.source, &mut self.ciphertext[..]);
+ let result = self.source.data_consume(to_copy);
let short_read;
- match result {
- Ok(amount) => {
- short_read = amount < to_copy;
- to_copy = amount;
- vec_truncate(&mut self.ciphertext, to_copy);
+ let ciphertext = match result {
+ Ok(data) => {
+ short_read = data.len() < to_copy;
+ to_copy = data.len().min(to_copy);
+ &data[..to_copy]
},
// We encountered an error, but we did read some.
Err(_) if pos > 0 => return Ok(pos),
Err(e) => return Err(e),
- }
+ };
self.dec.decrypt(&mut plaintext[pos..pos + to_copy],
- &self.ciphertext[..])
+ ciphertext)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
format!("{}", e)))?;
@@ -173,26 +136,23 @@ impl<'a> io::Read for Decryptor<'a> {
assert!(0 < to_copy);
assert!(to_copy < self.block_size);
- vec_resize(&mut self.ciphertext, self.block_size);
- let result = read_exact(&mut self.source, &mut self.ciphertext[..]);
- match result {
- Ok(amount) => {
- // Make sure `ciphertext` is not larger than the
- // amount of data that was actually read.
- vec_truncate(&mut self.ciphertext, amount);
-
+ let to_read = self.block_size;
+ let result = self.source.data_consume(to_read);
+ let ciphertext = match result {
+ Ok(data) => {
// Make sure we don't read more than is available.
- to_copy = cmp::min(to_copy, self.ciphertext.len());
+ to_copy = cmp::min(to_copy, data.len());
+ &data[..data.len().min(to_read)]
},
// We encountered an error, but we did read some.
Err(_) if pos > 0 => return Ok(pos),
Err(e) => return Err(e),
- }
- assert!(self.ciphertext.len() <= self.block_size);
+ };
+ assert!(ciphertext.len() <= self.block_size);
- vec_resize(&mut self.buffer, self.ciphertext.len());
+ vec_resize(&mut self.buffer, ciphertext.len());
- self.dec.decrypt(&mut self.buffer, &self.ciphertext[..])
+ self.dec.decrypt(&mut self.buffer, ciphertext)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput,
format!("{}", e)))?;