src/backup/data_blob.rs: impl. ChecksumWriter
To correctly compute crc,hmac of final data.
This commit is contained in:
		@ -294,14 +294,56 @@ impl DataBlob {
 | 
			
		||||
 | 
			
		||||
use std::io::{Read, BufRead, Write, Seek, SeekFrom};
 | 
			
		||||
 | 
			
		||||
struct ChecksumWriter<'a, W> {
 | 
			
		||||
    writer: W,
 | 
			
		||||
    hasher: crc32fast::Hasher,
 | 
			
		||||
    signer: Option<openssl::sign::Signer<'a>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl <'a, W: Write> ChecksumWriter<'a, W> {
 | 
			
		||||
 | 
			
		||||
    fn new(writer: W, signer: Option<openssl::sign::Signer<'a>>) -> Self {
 | 
			
		||||
        let hasher = crc32fast::Hasher::new();
 | 
			
		||||
        Self { writer, hasher, signer }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn finish(mut self) -> Result<(W, u32, Option<[u8; 32]>), Error> {
 | 
			
		||||
        let crc = self.hasher.finalize();
 | 
			
		||||
 | 
			
		||||
        if let Some(ref mut signer) = self.signer {
 | 
			
		||||
            let mut tag = [0u8; 32];
 | 
			
		||||
            signer.sign(&mut tag)?;
 | 
			
		||||
            Ok((self.writer, crc, Some(tag)))
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok((self.writer, crc, None))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl <'a, W: Write> Write for ChecksumWriter<'a, W> {
 | 
			
		||||
 | 
			
		||||
    fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
 | 
			
		||||
        self.hasher.update(buf);
 | 
			
		||||
        if let Some(ref mut signer) = self.signer {
 | 
			
		||||
            signer.update(buf).
 | 
			
		||||
                map_err(|err| {
 | 
			
		||||
                    std::io::Error::new(
 | 
			
		||||
                        std::io::ErrorKind::Other,
 | 
			
		||||
                        format!("hmac update failed - {}", err))
 | 
			
		||||
                })?;
 | 
			
		||||
        }
 | 
			
		||||
        self.writer.write(buf)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn flush(&mut self) -> Result<(), std::io::Error> {
 | 
			
		||||
        self.writer.flush()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum BlobWriterState<'a, W: Write> {
 | 
			
		||||
    Uncompressed { writer: W, hasher: crc32fast::Hasher },
 | 
			
		||||
    Compressed { compr: zstd::stream::write::Encoder<W>, hasher: crc32fast::Hasher },
 | 
			
		||||
    Signed {
 | 
			
		||||
        writer: W,
 | 
			
		||||
        hasher: crc32fast::Hasher,
 | 
			
		||||
        signer: openssl::sign::Signer<'a>,
 | 
			
		||||
    },
 | 
			
		||||
    Uncompressed { csum_writer: ChecksumWriter<'a, W> },
 | 
			
		||||
    Compressed { compr: zstd::stream::write::Encoder<ChecksumWriter<'a, W>> },
 | 
			
		||||
    Signed { csum_writer: ChecksumWriter<'a, W> },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Write compressed data blobs
 | 
			
		||||
@ -312,30 +354,27 @@ pub struct DataBlobWriter<'a, W: Write> {
 | 
			
		||||
impl <'a, W: Write + Seek> DataBlobWriter<'a, W> {
 | 
			
		||||
 | 
			
		||||
    pub fn new_uncompressed(mut writer: W) -> Result<Self, Error> {
 | 
			
		||||
        let hasher = crc32fast::Hasher::new();
 | 
			
		||||
        writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
        let head = DataBlobHeader { magic: UNCOMPRESSED_BLOB_MAGIC_1_0, crc: [0; 4] };
 | 
			
		||||
        unsafe {
 | 
			
		||||
            writer.write_le_value(head)?;
 | 
			
		||||
        }
 | 
			
		||||
        let state = BlobWriterState::Uncompressed { writer, hasher };
 | 
			
		||||
        Ok(Self { state })
 | 
			
		||||
        let csum_writer = ChecksumWriter::new(writer, None);
 | 
			
		||||
        Ok(Self { state: BlobWriterState::Uncompressed { csum_writer }})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_compressed(mut writer: W) -> Result<Self, Error> {
 | 
			
		||||
        let hasher = crc32fast::Hasher::new();
 | 
			
		||||
        writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
         writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
        let head = DataBlobHeader { magic: COMPRESSED_BLOB_MAGIC_1_0, crc: [0; 4] };
 | 
			
		||||
        unsafe {
 | 
			
		||||
            writer.write_le_value(head)?;
 | 
			
		||||
        }
 | 
			
		||||
        let compr = zstd::stream::write::Encoder::new(writer, 1)?;
 | 
			
		||||
        let state = BlobWriterState::Compressed { compr, hasher };
 | 
			
		||||
        Ok(Self { state })
 | 
			
		||||
        let csum_writer = ChecksumWriter::new(writer, None);
 | 
			
		||||
        let compr = zstd::stream::write::Encoder::new(csum_writer, 1)?;
 | 
			
		||||
        Ok(Self { state: BlobWriterState::Compressed { compr }})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new_signed(mut writer: W, config: &'a CryptConfig) -> Result<Self, Error> {
 | 
			
		||||
        let hasher = crc32fast::Hasher::new();
 | 
			
		||||
        writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
        let head = AuthenticatedDataBlobHeader {
 | 
			
		||||
            head: DataBlobHeader { magic: AUTHENTICATED_BLOB_MAGIC_1_0, crc: [0; 4] },
 | 
			
		||||
@ -345,16 +384,15 @@ impl <'a, W: Write + Seek> DataBlobWriter<'a, W> {
 | 
			
		||||
            writer.write_le_value(head)?;
 | 
			
		||||
        }
 | 
			
		||||
        let signer = config.data_signer();
 | 
			
		||||
 | 
			
		||||
        let state = BlobWriterState::Signed { writer, hasher, signer };
 | 
			
		||||
        Ok(Self { state })
 | 
			
		||||
        let csum_writer = ChecksumWriter::new(writer, Some(signer));
 | 
			
		||||
        Ok(Self { state:  BlobWriterState::Signed { csum_writer }})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn finish(self) -> Result<W, Error> {
 | 
			
		||||
        match self.state {
 | 
			
		||||
            BlobWriterState::Uncompressed { mut writer, hasher } => {
 | 
			
		||||
            BlobWriterState::Uncompressed { csum_writer } => {
 | 
			
		||||
                // write CRC
 | 
			
		||||
                let crc = hasher.finalize();
 | 
			
		||||
                let (mut writer, crc, _) = csum_writer.finish()?;
 | 
			
		||||
                let head = DataBlobHeader { magic: COMPRESSED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() };
 | 
			
		||||
 | 
			
		||||
                writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
@ -364,11 +402,10 @@ impl <'a, W: Write + Seek> DataBlobWriter<'a, W> {
 | 
			
		||||
 | 
			
		||||
                return Ok(writer)
 | 
			
		||||
            }
 | 
			
		||||
            BlobWriterState::Compressed { compr, hasher } => {
 | 
			
		||||
                let mut writer = compr.finish()?;
 | 
			
		||||
            BlobWriterState::Compressed { compr } => {
 | 
			
		||||
                let csum_writer = compr.finish()?;
 | 
			
		||||
                let (mut writer, crc, _) = csum_writer.finish()?;
 | 
			
		||||
 | 
			
		||||
                // write CRC
 | 
			
		||||
                let crc = hasher.finalize();
 | 
			
		||||
                let head = DataBlobHeader { magic: COMPRESSED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() };
 | 
			
		||||
 | 
			
		||||
                writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
@ -378,15 +415,13 @@ impl <'a, W: Write + Seek> DataBlobWriter<'a, W> {
 | 
			
		||||
 | 
			
		||||
                return Ok(writer)
 | 
			
		||||
            }
 | 
			
		||||
            BlobWriterState::Signed { mut writer, hasher, signer, .. } => {
 | 
			
		||||
                // write CRC and hmac
 | 
			
		||||
                let crc = hasher.finalize();
 | 
			
		||||
            BlobWriterState::Signed { csum_writer } => {
 | 
			
		||||
                let (mut writer, crc, tag) = csum_writer.finish()?;
 | 
			
		||||
 | 
			
		||||
                let mut head = AuthenticatedDataBlobHeader {
 | 
			
		||||
                let head = AuthenticatedDataBlobHeader {
 | 
			
		||||
                    head: DataBlobHeader { magic: AUTHENTICATED_BLOB_MAGIC_1_0, crc: crc.to_le_bytes() },
 | 
			
		||||
                    tag: [0u8; 32],
 | 
			
		||||
                    tag: tag.unwrap(),
 | 
			
		||||
                };
 | 
			
		||||
                signer.sign(&mut head.tag)?;
 | 
			
		||||
 | 
			
		||||
                writer.seek(SeekFrom::Start(0))?;
 | 
			
		||||
                unsafe {
 | 
			
		||||
@ -403,37 +438,28 @@ impl <'a, W: Write + Seek> Write for DataBlobWriter<'a, W> {
 | 
			
		||||
 | 
			
		||||
    fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
 | 
			
		||||
        match self.state {
 | 
			
		||||
            BlobWriterState::Uncompressed { ref mut writer, ref mut hasher } => {
 | 
			
		||||
                hasher.update(buf);
 | 
			
		||||
                writer.write(buf)
 | 
			
		||||
            BlobWriterState::Uncompressed { ref mut csum_writer } => {
 | 
			
		||||
                csum_writer.write(buf)
 | 
			
		||||
            }
 | 
			
		||||
            BlobWriterState::Compressed { ref mut compr, ref mut hasher } => {
 | 
			
		||||
                hasher.update(buf);
 | 
			
		||||
            BlobWriterState::Compressed { ref mut compr } => {
 | 
			
		||||
                compr.write(buf)
 | 
			
		||||
            }
 | 
			
		||||
            BlobWriterState::Signed { ref mut writer, ref mut hasher, ref mut signer, .. } => {
 | 
			
		||||
                hasher.update(buf);
 | 
			
		||||
                signer.update(buf).
 | 
			
		||||
                    map_err(|err| {
 | 
			
		||||
                        std::io::Error::new(
 | 
			
		||||
                            std::io::ErrorKind::Other,
 | 
			
		||||
                            format!("hmac update failed - {}", err))
 | 
			
		||||
                    })?;
 | 
			
		||||
                writer.write(buf)
 | 
			
		||||
             }
 | 
			
		||||
            BlobWriterState::Signed { ref mut csum_writer } => {
 | 
			
		||||
                csum_writer.write(buf)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn flush(&mut self) -> Result<(), std::io::Error> {
 | 
			
		||||
        match self.state {
 | 
			
		||||
            BlobWriterState::Uncompressed { ref mut writer, .. } => {
 | 
			
		||||
                writer.flush()
 | 
			
		||||
            BlobWriterState::Uncompressed { ref mut csum_writer } => {
 | 
			
		||||
                csum_writer.flush()
 | 
			
		||||
            }
 | 
			
		||||
            BlobWriterState::Compressed { ref mut compr, .. } => {
 | 
			
		||||
            BlobWriterState::Compressed { ref mut compr } => {
 | 
			
		||||
                compr.flush()
 | 
			
		||||
            }
 | 
			
		||||
            BlobWriterState::Signed { ref mut writer, .. } => {
 | 
			
		||||
                writer.flush()
 | 
			
		||||
            BlobWriterState::Signed { ref mut csum_writer } => {
 | 
			
		||||
                csum_writer.flush()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user