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