use { super::{ define, define::SchemaVersion, errors::{DigestError, DigestErrorValue}, }, bytes::BytesMut, bytesio::bytes_reader::BytesReader, hmac::{Hmac, Mac, NewMac}, sha2::Sha256, }; pub struct DigestProcessor { reader: BytesReader, key: BytesMut, } impl DigestProcessor { pub fn new(data: BytesMut, key: BytesMut) -> Self { Self { reader: BytesReader::new(data), key, } } /* return validate digest and schema version*/ pub fn read_digest(&mut self) -> Result<(BytesMut, SchemaVersion), DigestError> { if let Ok(digest) = self.generate_and_validate(SchemaVersion::Schema0) { return Ok((digest, SchemaVersion::Schema0)); } let digest = self.generate_and_validate(SchemaVersion::Schema1)?; Ok((digest, SchemaVersion::Schema1)) } pub fn generate_and_fill_digest(&mut self) -> Result, DigestError> { let (left_part, _, right_part) = self.cook_raw_message(SchemaVersion::Schema0)?; let raw_message = [left_part.clone(), right_part.clone()].concat(); let computed_digest = self.make_digest(raw_message)?; let result = [left_part, computed_digest, right_part].concat(); Ok(result) } pub fn generate_digest(&mut self) -> Result { let (left_part, _, right_part) = self.cook_raw_message(SchemaVersion::Schema0)?; let raw_message = [left_part, right_part].concat(); let digest = self.make_digest(raw_message)?; Ok(digest) } fn find_digest_offset(&mut self, version: SchemaVersion) -> Result { let mut digest_offset: usize = 0; match version { SchemaVersion::Schema0 => { digest_offset += self.reader.get(772)? as usize; digest_offset += self.reader.get(773)? as usize; digest_offset += self.reader.get(774)? as usize; digest_offset += self.reader.get(775)? as usize; digest_offset %= 728; digest_offset += 776; } SchemaVersion::Schema1 => { digest_offset += self.reader.get(8)? as usize; digest_offset += self.reader.get(9)? as usize; digest_offset += self.reader.get(10)? as usize; digest_offset += self.reader.get(11)? as usize; digest_offset %= 728; digest_offset += 12; } SchemaVersion::Unknown => { return Err(DigestError { value: DigestErrorValue::UnknowSchema, }); } } Ok(digest_offset) } /* +-----------------------------------------------------------+ | 764 bytes | * +--------------+-----------------------+--------------------+ * | left part | digest data (32 bytes)| right part | * +--------------+-----------------------+--------------------+ * | / digest offset pice together the left part and right part to get the raw message. */ fn cook_raw_message( &mut self, version: SchemaVersion, ) -> Result<(BytesMut, BytesMut, BytesMut), DigestError> { let digest_offset: usize = self.find_digest_offset(version)?; let mut new_reader = BytesReader::new(self.reader.get_remaining_bytes()); let left_part = new_reader.read_bytes(digest_offset)?; let digest_data = new_reader.read_bytes(define::RTMP_DIGEST_LENGTH)?; let right_part = new_reader.extract_remaining_bytes(); Ok((left_part, digest_data, right_part)) } pub fn make_digest(&mut self, raw_message: Vec) -> Result { let mut mac = Hmac::::new_from_slice(&self.key[..]).unwrap(); mac.update(&raw_message); let result = mac.finalize().into_bytes(); if result.len() != define::RTMP_DIGEST_LENGTH { return Err(DigestError { value: DigestErrorValue::DigestLengthNotCorrect, }); } let mut rv = BytesMut::new(); rv.extend_from_slice(result.as_slice()); Ok(rv) } fn generate_and_validate(&mut self, version: SchemaVersion) -> Result { let (left_part, digest_data, right_part) = self.cook_raw_message(version)?; let raw_message = [left_part, right_part].concat(); let computed_digest = self.make_digest(raw_message)?; if digest_data == computed_digest { return Ok(digest_data); } Err(DigestError { value: DigestErrorValue::CannotGenerate, }) } }