src/backup/data_blob.rs: implement signed blobs
This commit is contained in:
parent
93205f942a
commit
69ecd8d5b0
|
@ -62,6 +62,7 @@ impl DataBlob {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a DataBlob, optionally compressed and/or encrypted
|
||||
pub fn encode(
|
||||
data: &[u8],
|
||||
config: Option<&CryptConfig>,
|
||||
|
@ -174,11 +175,72 @@ impl DataBlob {
|
|||
} else {
|
||||
bail!("unable to decrypt blob - missing CryptConfig");
|
||||
}
|
||||
} else if magic == &AUTH_COMPR_BLOB_MAGIC_1_0 || magic == &AUTHENTICATED_BLOB_MAGIC_1_0 {
|
||||
let header_len = std::mem::size_of::<AuthenticatedDataBlobHeader>();
|
||||
let head = unsafe {
|
||||
(&self.raw_data[..header_len]).read_le_value::<AuthenticatedDataBlobHeader>()?
|
||||
};
|
||||
|
||||
let data_start = std::mem::size_of::<AuthenticatedDataBlobHeader>();
|
||||
|
||||
// Note: only verify if we have a crypt config
|
||||
if let Some(config) = config {
|
||||
let signature = config.compute_auth_tag(&self.raw_data[data_start..]);
|
||||
if signature != head.tag {
|
||||
bail!("verifying blob signature failed");
|
||||
}
|
||||
}
|
||||
|
||||
if magic == &AUTH_COMPR_BLOB_MAGIC_1_0 {
|
||||
let data = zstd::block::decompress(&self.raw_data[data_start..], 16*1024*1024)?;
|
||||
return Ok(data);
|
||||
} else {
|
||||
return Ok(self.raw_data[data_start..].to_vec());
|
||||
}
|
||||
} else {
|
||||
bail!("Invalid blob magic number.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a signed DataBlob, optionally compressed
|
||||
pub fn create_signed(
|
||||
data: &[u8],
|
||||
config: &CryptConfig,
|
||||
compress: bool,
|
||||
) -> Result<Self, Error> {
|
||||
|
||||
if data.len() > 16*1024*1024 {
|
||||
bail!("data blob too large ({} bytes).", data.len());
|
||||
}
|
||||
|
||||
let compr_data;
|
||||
let (_compress, data, magic) = if compress {
|
||||
compr_data = zstd::block::compress(data, 1)?;
|
||||
// Note: We only use compression if result is shorter
|
||||
if compr_data.len() < data.len() {
|
||||
(true, &compr_data[..], AUTH_COMPR_BLOB_MAGIC_1_0)
|
||||
} else {
|
||||
(false, data, AUTHENTICATED_BLOB_MAGIC_1_0)
|
||||
}
|
||||
} else {
|
||||
(false, data, AUTHENTICATED_BLOB_MAGIC_1_0)
|
||||
};
|
||||
|
||||
let header_len = std::mem::size_of::<AuthenticatedDataBlobHeader>();
|
||||
let mut raw_data = Vec::with_capacity(data.len() + header_len);
|
||||
|
||||
let head = AuthenticatedDataBlobHeader {
|
||||
head: DataBlobHeader { magic, crc: [0; 4] },
|
||||
tag: config.compute_auth_tag(data),
|
||||
};
|
||||
unsafe {
|
||||
raw_data.write_le_value(head)?;
|
||||
}
|
||||
raw_data.extend_from_slice(data);
|
||||
|
||||
return Ok(DataBlob { raw_data });
|
||||
}
|
||||
|
||||
/// Create Instance from raw data
|
||||
pub fn from_raw(data: Vec<u8>) -> Result<Self, Error> {
|
||||
|
||||
|
@ -201,6 +263,14 @@ impl DataBlob {
|
|||
|
||||
let blob = DataBlob { raw_data: data };
|
||||
|
||||
Ok(blob)
|
||||
} else if magic == AUTH_COMPR_BLOB_MAGIC_1_0 || magic == AUTHENTICATED_BLOB_MAGIC_1_0 {
|
||||
if data.len() < std::mem::size_of::<AuthenticatedDataBlobHeader>() {
|
||||
bail!("authenticated blob too small ({} bytes).", data.len());
|
||||
}
|
||||
|
||||
let blob = DataBlob { raw_data: data };
|
||||
|
||||
Ok(blob)
|
||||
} else {
|
||||
bail!("unable to parse raw blob - wrong magic");
|
||||
|
|
|
@ -26,6 +26,12 @@ pub static ENCRYPTED_BLOB_MAGIC_1_0: [u8; 8] = [123, 103, 133, 190, 34, 45, 76,
|
|||
// openssl::sha::sha256(b"Proxmox Backup zstd compressed encrypted blob v1.0")[0..8]
|
||||
pub static ENCR_COMPR_BLOB_MAGIC_1_0: [u8; 8] = [230, 89, 27, 191, 11, 191, 216, 11];
|
||||
|
||||
//openssl::sha::sha256(b"Proxmox Backup authenticated blob v1.0")[0..8]
|
||||
pub static AUTHENTICATED_BLOB_MAGIC_1_0: [u8; 8] = [31, 135, 238, 226, 145, 206, 5, 2];
|
||||
|
||||
//openssl::sha::sha256(b"Proxmox Backup zstd compressed authenticated blob v1.0")[0..8]
|
||||
pub static AUTH_COMPR_BLOB_MAGIC_1_0: [u8; 8] = [126, 166, 15, 190, 145, 31, 169, 96];
|
||||
|
||||
// openssl::sha::sha256(b"Proxmox Backup fixed sized chunk index v1.0")[0..8]
|
||||
pub static FIXED_SIZED_CHUNK_INDEX_1_0: [u8; 8] = [47, 127, 65, 237, 145, 253, 15, 205];
|
||||
|
||||
|
@ -53,6 +59,19 @@ pub struct DataBlobHeader {
|
|||
pub crc: [u8; 4],
|
||||
}
|
||||
|
||||
/// Authenticated data blob binary storage format
|
||||
///
|
||||
/// The ``DataBlobHeader`` for authenticated blobs additionally contains
|
||||
/// a 16 byte HMAC tag, followed by the data:
|
||||
///
|
||||
/// (MAGIC || CRC32 || TAG || Data).
|
||||
#[derive(Endian)]
|
||||
#[repr(C,packed)]
|
||||
pub struct AuthenticatedDataBlobHeader {
|
||||
pub head: DataBlobHeader,
|
||||
pub tag: [u8; 32],
|
||||
}
|
||||
|
||||
/// Encrypted data blob binary storage format
|
||||
///
|
||||
/// The ``DataBlobHeader`` for encrypted blobs additionally contains
|
||||
|
|
Loading…
Reference in New Issue