1 use anyhow
::{bail, Error}
;
3 use std
::io
::{Read, BufReader}
;
4 use proxmox
::tools
::io
::ReadExt
;
8 enum BlobReaderState
<R
: Read
> {
9 Uncompressed { expected_crc: u32, csum_reader: ChecksumReader<R> }
,
10 Compressed { expected_crc: u32, decompr: zstd::stream::read::Decoder<BufReader<ChecksumReader<R>>> }
,
11 Encrypted { expected_crc: u32, decrypt_reader: CryptReader<BufReader<ChecksumReader<R>>> }
,
12 EncryptedCompressed { expected_crc: u32, decompr: zstd::stream::read::Decoder<BufReader<CryptReader<BufReader<ChecksumReader<R>>>>> }
,
16 pub struct DataBlobReader
<R
: Read
> {
17 state
: BlobReaderState
<R
>,
20 // zstd_safe::DCtx is not sync but we are, since
21 // the only public interface is on mutable reference
22 unsafe impl<R
: Read
> Sync
for DataBlobReader
<R
> {}
24 impl <R
: Read
> DataBlobReader
<R
> {
26 pub fn new(mut reader
: R
, config
: Option
<Arc
<CryptConfig
>>) -> Result
<Self, Error
> {
28 let head
: DataBlobHeader
= unsafe { reader.read_le_value()? }
;
30 UNCOMPRESSED_BLOB_MAGIC_1_0
=> {
31 let expected_crc
= u32::from_le_bytes(head
.crc
);
32 let csum_reader
= ChecksumReader
::new(reader
, None
);
33 Ok(Self { state: BlobReaderState::Uncompressed { expected_crc, csum_reader }
})
35 COMPRESSED_BLOB_MAGIC_1_0
=> {
36 let expected_crc
= u32::from_le_bytes(head
.crc
);
37 let csum_reader
= ChecksumReader
::new(reader
, None
);
39 let decompr
= zstd
::stream
::read
::Decoder
::new(csum_reader
)?
;
40 Ok(Self { state: BlobReaderState::Compressed { expected_crc, decompr }
})
42 ENCRYPTED_BLOB_MAGIC_1_0
=> {
43 let expected_crc
= u32::from_le_bytes(head
.crc
);
44 let mut iv
= [0u8; 16];
45 let mut expected_tag
= [0u8; 16];
46 reader
.read_exact(&mut iv
)?
;
47 reader
.read_exact(&mut expected_tag
)?
;
48 let csum_reader
= ChecksumReader
::new(reader
, None
);
49 let decrypt_reader
= CryptReader
::new(BufReader
::with_capacity(64*1024, csum_reader
), iv
, expected_tag
, config
.unwrap())?
;
50 Ok(Self { state: BlobReaderState::Encrypted { expected_crc, decrypt_reader }
})
52 ENCR_COMPR_BLOB_MAGIC_1_0
=> {
53 let expected_crc
= u32::from_le_bytes(head
.crc
);
54 let mut iv
= [0u8; 16];
55 let mut expected_tag
= [0u8; 16];
56 reader
.read_exact(&mut iv
)?
;
57 reader
.read_exact(&mut expected_tag
)?
;
58 let csum_reader
= ChecksumReader
::new(reader
, None
);
59 let decrypt_reader
= CryptReader
::new(BufReader
::with_capacity(64*1024, csum_reader
), iv
, expected_tag
, config
.unwrap())?
;
60 let decompr
= zstd
::stream
::read
::Decoder
::new(decrypt_reader
)?
;
61 Ok(Self { state: BlobReaderState::EncryptedCompressed { expected_crc, decompr }
})
63 _
=> bail
!("got wrong magic number {:?}", head
.magic
)
67 pub fn finish(self) -> Result
<R
, Error
> {
69 BlobReaderState
::Uncompressed { csum_reader, expected_crc }
=> {
70 let (reader
, crc
, _
) = csum_reader
.finish()?
;
71 if crc
!= expected_crc
{
72 bail
!("blob crc check failed");
76 BlobReaderState
::Compressed { expected_crc, decompr }
=> {
77 let csum_reader
= decompr
.finish().into_inner();
78 let (reader
, crc
, _
) = csum_reader
.finish()?
;
79 if crc
!= expected_crc
{
80 bail
!("blob crc check failed");
84 BlobReaderState
::Encrypted { expected_crc, decrypt_reader }
=> {
85 let csum_reader
= decrypt_reader
.finish()?
.into_inner();
86 let (reader
, crc
, _
) = csum_reader
.finish()?
;
87 if crc
!= expected_crc
{
88 bail
!("blob crc check failed");
92 BlobReaderState
::EncryptedCompressed { expected_crc, decompr }
=> {
93 let decrypt_reader
= decompr
.finish().into_inner();
94 let csum_reader
= decrypt_reader
.finish()?
.into_inner();
95 let (reader
, crc
, _
) = csum_reader
.finish()?
;
96 if crc
!= expected_crc
{
97 bail
!("blob crc check failed");
105 impl <R
: Read
> Read
for DataBlobReader
<R
> {
107 fn read(&mut self, buf
: &mut [u8]) -> Result
<usize, std
::io
::Error
> {
108 match &mut self.state
{
109 BlobReaderState
::Uncompressed { csum_reader, .. }
=> {
110 csum_reader
.read(buf
)
112 BlobReaderState
::Compressed { decompr, .. }
=> {
115 BlobReaderState
::Encrypted { decrypt_reader, .. }
=> {
116 decrypt_reader
.read(buf
)
118 BlobReaderState
::EncryptedCompressed { decompr, .. }
=> {