use std::io::{Cursor, Read};
use std::fmt;
use std::cmp::{PartialEq,Eq};
use std::hash::{Hash, Hasher};
use crate::{
Result,
HeaderCoding,
Encryption,
ValueEncoder,
ValueDecoder,
ZffError,
ZffErrorKind,
SignatureFlag,
};
use crate::{
ERROR_HEADER_DECODER_MISMATCH_IDENTIFIER,
DEFAULT_LENGTH_VALUE_HEADER_LENGTH,
DEFAULT_LENGTH_HEADER_IDENTIFIER,
HEADER_IDENTIFIER_OBJECT_HEADER,
ERROR_INVALID_SIGNATURE_FLAG_VALUE,
ERROR_INVALID_OBJECT_TYPE_FLAG_VALUE,
};
use crate::header::{
EncryptionHeader,
CompressionHeader,
DescriptionHeader,
};
#[derive(Debug,Clone)]
pub struct ObjectHeader {
version: u8,
object_number: u64,
encryption_header: Option<EncryptionHeader>,
compression_header: CompressionHeader,
signature_flag: SignatureFlag,
description_header: DescriptionHeader,
object_type: ObjectType
}
impl ObjectHeader {
pub fn new(version: u8,
object_number: u64,
encryption_header: Option<EncryptionHeader>,
compression_header: CompressionHeader,
signature_flag: SignatureFlag,
description_header: DescriptionHeader,
object_type: ObjectType) -> ObjectHeader {
Self {
version,
object_number,
encryption_header,
compression_header,
signature_flag,
description_header,
object_type,
}
}
pub fn set_object_number(&mut self, object_number: u64) {
self.object_number = object_number
}
pub fn object_number(&self) -> u64 {
self.object_number
}
pub fn description_header(&self) -> DescriptionHeader {
self.description_header.clone()
}
pub fn object_type(&self) -> ObjectType {
self.object_type.clone()
}
pub fn encryption_header(&self) -> Option<&EncryptionHeader> {
self.encryption_header.as_ref()
}
pub fn compression_header(&self) -> CompressionHeader {
self.compression_header.clone()
}
pub fn has_per_chunk_signatures(&self) -> bool {
matches!(&self.signature_flag, SignatureFlag::PerChunkSignatures)
}
pub fn has_hash_signatures(&self) -> bool {
!matches!(&self.signature_flag, SignatureFlag::NoSignatures)
}
pub fn signature_flag(&self) -> &SignatureFlag {
&self.signature_flag
}
pub fn encode_encrypted_header_directly<K>(&self, key: K) -> Result<Vec<u8>>
where
K: AsRef<[u8]>,
{
let mut vec = Vec::new();
let mut encoded_header = self.encode_encrypted_header(key)?;
let identifier = HEADER_IDENTIFIER_OBJECT_HEADER;
let encoded_header_length = 4 + 8 + (encoded_header.len() as u64); vec.append(&mut identifier.to_be_bytes().to_vec());
vec.append(&mut encoded_header_length.to_le_bytes().to_vec());
vec.append(&mut encoded_header);
Ok(vec)
}
fn encode_encrypted_header<K>(&self, key: K) -> Result<Vec<u8>>
where
K: AsRef<[u8]>
{
let encryption_header = match &self.encryption_header {
None => return Err(ZffError::new(ZffErrorKind::MissingEncryptionHeader, "")),
Some(header) => {
header
}
};
let encryption_flag: u8 = 2;
let mut vec = Vec::new();
vec.append(&mut self.version.encode_directly());
vec.append(&mut self.object_number.encode_directly());
vec.push(encryption_flag);
vec.append(&mut encryption_header.encode_directly());
let mut data_to_encrypt = Vec::new();
data_to_encrypt.append(&mut self.encode_content());
let encrypted_data = Encryption::encrypt_header(
key, data_to_encrypt,
encryption_header.nonce(),
encryption_header.algorithm()
)?;
vec.append(&mut encrypted_data.encode_directly());
Ok(vec)
}
fn encode_content(&self) -> Vec<u8> {
let mut vec = Vec::new();
vec.append(&mut self.compression_header.encode_directly());
vec.push(self.signature_flag.clone() as u8);
vec.append(&mut self.description_header.encode_directly());
vec.push(self.object_type.clone() as u8);
vec
}
pub fn decode_encrypted_header_with_password<R, P>(data: &mut R, password: P) -> Result<ObjectHeader>
where
R: Read,
P: AsRef<[u8]>,
{
if !Self::check_identifier(data) {
return Err(ZffError::new(ZffErrorKind::HeaderDecodeMismatchIdentifier, ERROR_HEADER_DECODER_MISMATCH_IDENTIFIER));
};
let header_length = Self::decode_header_length(data)? as usize;
let mut header_content = vec![0u8; header_length-DEFAULT_LENGTH_HEADER_IDENTIFIER-DEFAULT_LENGTH_VALUE_HEADER_LENGTH];
data.read_exact(&mut header_content)?;
let mut cursor = Cursor::new(header_content);
let header_version = u8::decode_directly(&mut cursor)?;
let object_number = u64::decode_directly(&mut cursor)?;
let encryption_flag = u8::decode_directly(&mut cursor)?;
if encryption_flag != 2 {
return Err(ZffError::new(ZffErrorKind::HeaderDecodeEncryptedHeader, ""));
}
let encryption_header = EncryptionHeader::decode_directly(&mut cursor)?;
let encrypted_data = Vec::<u8>::decode_directly(&mut cursor)?;
let encryption_key = encryption_header.decrypt_encryption_key(password)?;
let nonce = encryption_header.nonce();
let algorithm = encryption_header.algorithm();
let decrypted_data = Encryption::decrypt_header(encryption_key, encrypted_data, nonce, algorithm)?;
let mut cursor = Cursor::new(decrypted_data);
let (compression_header,
signature_flag,
description_header,
object_type) = Self::decode_inner_content(&mut cursor)?;
let object_header = Self::new(
header_version,
object_number,
Some(encryption_header),
compression_header,
signature_flag,
description_header,
object_type);
Ok(object_header)
}
fn decode_inner_content<R: Read>(inner_content: &mut R) -> Result<(
CompressionHeader,
SignatureFlag,
DescriptionHeader,
ObjectType,
)> {
let compression_header = CompressionHeader::decode_directly(inner_content)?;
let signature_flag = match u8::decode_directly(inner_content)? {
0 => SignatureFlag::NoSignatures,
1 => SignatureFlag::HashValueSignatureOnly,
2 => SignatureFlag::PerChunkSignatures,
value => return Err(ZffError::new(ZffErrorKind::InvalidFlagValue, format!("{ERROR_INVALID_SIGNATURE_FLAG_VALUE} {value}"))),
};
let description_header = DescriptionHeader::decode_directly(inner_content)?;
let object_type = match u8::decode_directly(inner_content)? {
0 => ObjectType::Physical,
1 => ObjectType::Logical,
value => return Err(ZffError::new(ZffErrorKind::InvalidFlagValue, format!("{ERROR_INVALID_OBJECT_TYPE_FLAG_VALUE}{value}"))),
};
let inner_content = (
compression_header,
signature_flag,
description_header,
object_type);
Ok(inner_content)
}
}
#[repr(u8)]
#[derive(Debug,Clone,Eq,PartialEq,Hash)]
pub enum ObjectType {
Physical = 0,
Logical = 1,
}
impl fmt::Display for ObjectType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
ObjectType::Physical => "Physical",
ObjectType::Logical => "Logical",
};
write!(f, "{}", msg)
}
}
impl HeaderCoding for ObjectHeader {
type Item = ObjectHeader;
fn identifier() -> u32 {
HEADER_IDENTIFIER_OBJECT_HEADER
}
fn version(&self) -> u8 {
self.version
}
fn encode_directly(&self) -> Vec<u8> {
let mut vec = Vec::new();
let mut encoded_object_number = self.object_number.encode_directly();
let mut encoded_header = self.encode_header();
let identifier = Self::identifier();
let encoded_header_length = (DEFAULT_LENGTH_HEADER_IDENTIFIER + DEFAULT_LENGTH_VALUE_HEADER_LENGTH + encoded_header.len() + encoded_object_number.len() + 1) as u64; vec.append(&mut identifier.to_be_bytes().to_vec());
vec.append(&mut encoded_header_length.to_le_bytes().to_vec());
vec.push(self.version);
vec.append(&mut encoded_object_number);
vec.append(&mut encoded_header);
vec
}
fn encode_header(&self) -> Vec<u8> {
let mut vec = Vec::new();
match &self.encryption_header {
None => {
let encryption_flag: u8 = 0;
vec.push(encryption_flag);
},
Some(header) => {
let encryption_flag: u8 = 1;
vec.push(encryption_flag);
vec.append(&mut header.encode_directly());
},
};
vec.append(&mut self.encode_content());
vec
}
fn decode_content(data: Vec<u8>) -> Result<ObjectHeader> {
let mut cursor = Cursor::new(data);
let version = u8::decode_directly(&mut cursor)?;
let object_number = u64::decode_directly(&mut cursor)?;
let encryption_flag = u8::decode_directly(&mut cursor)?;
let encryption_header = match encryption_flag {
0 => None,
1 => Some(EncryptionHeader::decode_directly(&mut cursor)?),
flag_value => return Err(ZffError::new(ZffErrorKind::HeaderDecodeEncryptedHeader, flag_value.to_string()))
};
let (compression_header,
signature_flag,
description_header,
object_type) = Self::decode_inner_content(&mut cursor)?;
let object_header = Self::new(
version,
object_number,
encryption_header,
compression_header,
signature_flag,
description_header,
object_type);
Ok(object_header)
}
}
impl PartialEq for ObjectHeader {
fn eq(&self, other: &Self) -> bool {
self.object_number == other.object_number
}
}
impl Eq for ObjectHeader {}
impl Hash for ObjectHeader {
fn hash<H: Hasher>(&self, state: &mut H) {
self.object_number.hash(state);
}
}