From f4942e9ffde4e2a6b1ea796781e2a1ea2f125246 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Mon, 12 Aug 2019 10:08:00 +0200 Subject: [PATCH] src/backup/data_blob.rs - DataBlobWriter: impl. encrypted blobs --- src/backup/data_blob.rs | 93 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 2 deletions(-) diff --git a/src/backup/data_blob.rs b/src/backup/data_blob.rs index 62490fbc..c78aaf88 100644 --- a/src/backup/data_blob.rs +++ b/src/backup/data_blob.rs @@ -294,6 +294,59 @@ impl DataBlob { use std::io::{Read, BufRead, Write, Seek, SeekFrom}; +struct CryptWriter { + writer: W, + encr_buf: [u8; 64*1024], + iv: [u8; 16], + crypter: openssl::symm::Crypter, +} + +impl CryptWriter { + + fn new(writer: W, config: &CryptConfig) -> Result { + let mut iv = [0u8; 16]; + proxmox::sys::linux::fill_with_random_data(&mut iv)?; + + let crypter = config.data_crypter(&iv)?; + + Ok(Self { writer, iv, crypter, encr_buf: [0u8; 64*1024] }) + } + + fn finish(mut self) -> Result<(W, [u8; 16], [u8; 16]), Error> { + let rest = self.crypter.finalize(&mut self.encr_buf)?; + if rest > 0 { + self.writer.write_all(&self.encr_buf[..rest])?; + } + + self.writer.flush()?; + + let mut tag = [0u8; 16]; + self.crypter.get_tag(&mut tag)?; + + Ok((self.writer, self.iv, tag)) + } +} + +impl Write for CryptWriter { + + fn write(&mut self, buf: &[u8]) -> Result { + let count = self.crypter.update(buf, &mut self.encr_buf) + .map_err(|err| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("crypter update failed - {}", err)) + })?; + + self.writer.write_all(&self.encr_buf[..count])?; + + Ok(count) + } + + fn flush(&mut self) -> Result<(), std::io::Error> { + Ok(()) + } +} + struct ChecksumWriter<'a, W> { writer: W, hasher: crc32fast::Hasher, @@ -325,8 +378,8 @@ impl <'a, W: Write> Write for ChecksumWriter<'a, W> { fn write(&mut self, buf: &[u8]) -> Result { self.hasher.update(buf); if let Some(ref mut signer) = self.signer { - signer.update(buf). - map_err(|err| { + signer.update(buf) + .map_err(|err| { std::io::Error::new( std::io::ErrorKind::Other, format!("hmac update failed - {}", err)) @@ -345,6 +398,7 @@ enum BlobWriterState<'a, W: Write> { Compressed { compr: zstd::stream::write::Encoder> }, Signed { csum_writer: ChecksumWriter<'a, W> }, SignedCompressed { compr: zstd::stream::write::Encoder> }, + Encrypted { crypt_writer: CryptWriter> }, } /// Write compressed data blobs @@ -404,6 +458,22 @@ impl <'a, W: Write + Seek> DataBlobWriter<'a, W> { Ok(Self { state: BlobWriterState::SignedCompressed { compr }}) } + pub fn new_encrypted(mut writer: W, config: &'a CryptConfig) -> Result { + writer.seek(SeekFrom::Start(0))?; + let head = EncryptedDataBlobHeader { + head: DataBlobHeader { magic: ENCRYPTED_BLOB_MAGIC_1_0, crc: [0; 4] }, + iv: [0u8; 16], + tag: [0u8; 16], + }; + unsafe { + writer.write_le_value(head)?; + } + + let csum_writer = ChecksumWriter::new(writer, None); + let crypt_writer = CryptWriter::new(csum_writer, config)?; + Ok(Self { state: BlobWriterState::Encrypted { crypt_writer }}) + } + pub fn finish(self) -> Result { match self.state { BlobWriterState::Uncompressed { csum_writer } => { @@ -462,6 +532,19 @@ impl <'a, W: Write + Seek> DataBlobWriter<'a, W> { return Ok(writer) } + BlobWriterState::Encrypted { crypt_writer } => { + let (csum_writer, iv, tag) = crypt_writer.finish()?; + let (mut writer, crc, _) = csum_writer.finish()?; + + let head = EncryptedDataBlobHeader { + head: DataBlobHeader { magic: ENCRYPTED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() }, + iv, tag, + }; + unsafe { + writer.write_le_value(head)?; + } + return Ok(writer) + } } } } @@ -482,6 +565,9 @@ impl <'a, W: Write + Seek> Write for DataBlobWriter<'a, W> { BlobWriterState::SignedCompressed { ref mut compr } => { compr.write(buf) } + BlobWriterState::Encrypted { ref mut crypt_writer } => { + crypt_writer.write(buf) + } } } @@ -499,6 +585,9 @@ impl <'a, W: Write + Seek> Write for DataBlobWriter<'a, W> { BlobWriterState::SignedCompressed { ref mut compr } => { compr.flush() } + BlobWriterState::Encrypted { ref mut crypt_writer } => { + crypt_writer.flush() + } } } }