1use {
2 super::{
3 define,
4 define::SchemaVersion,
5 errors::{DigestError, DigestErrorValue},
6 },
7 bytes::BytesMut,
8 bytesio::bytes_reader::BytesReader,
9 hmac::{Hmac, Mac, NewMac},
10 sha2::Sha256,
11};
12
13pub struct DigestProcessor {
14 reader: BytesReader,
15 key: BytesMut,
16}
17
18impl DigestProcessor {
19 pub fn new(data: BytesMut, key: BytesMut) -> Self {
20 Self {
21 reader: BytesReader::new(data),
22 key,
23 }
24 }
25
26 pub fn read_digest(&mut self) -> Result<(BytesMut, SchemaVersion), DigestError> {
28 if let Ok(digest) = self.generate_and_validate(SchemaVersion::Schema0) {
29 return Ok((digest, SchemaVersion::Schema0));
30 }
31
32 let digest = self.generate_and_validate(SchemaVersion::Schema1)?;
33 Ok((digest, SchemaVersion::Schema1))
34 }
35
36 pub fn generate_and_fill_digest(&mut self) -> Result<Vec<u8>, DigestError> {
37 let (left_part, _, right_part) = self.cook_raw_message(SchemaVersion::Schema0)?;
38 let raw_message = [left_part.clone(), right_part.clone()].concat();
39 let computed_digest = self.make_digest(raw_message)?;
40
41 let result = [left_part, computed_digest, right_part].concat();
42
43 Ok(result)
44 }
45
46 pub fn generate_digest(&mut self) -> Result<BytesMut, DigestError> {
47 let (left_part, _, right_part) = self.cook_raw_message(SchemaVersion::Schema0)?;
48 let raw_message = [left_part, right_part].concat();
49 let digest = self.make_digest(raw_message)?;
50
51 Ok(digest)
52 }
53
54 fn find_digest_offset(&mut self, version: SchemaVersion) -> Result<usize, DigestError> {
55 let mut digest_offset: usize = 0;
56
57 match version {
58 SchemaVersion::Schema0 => {
59 digest_offset += self.reader.get(772)? as usize;
60 digest_offset += self.reader.get(773)? as usize;
61 digest_offset += self.reader.get(774)? as usize;
62 digest_offset += self.reader.get(775)? as usize;
63
64 digest_offset %= 728;
65 digest_offset += 776;
66 }
67 SchemaVersion::Schema1 => {
68 digest_offset += self.reader.get(8)? as usize;
69 digest_offset += self.reader.get(9)? as usize;
70 digest_offset += self.reader.get(10)? as usize;
71 digest_offset += self.reader.get(11)? as usize;
72
73 digest_offset %= 728;
74 digest_offset += 12;
75 }
76 SchemaVersion::Unknown => {
77 return Err(DigestError {
78 value: DigestErrorValue::UnknowSchema,
79 });
80 }
81 }
82
83 Ok(digest_offset)
84 }
85 fn cook_raw_message(
97 &mut self,
98 version: SchemaVersion,
99 ) -> Result<(BytesMut, BytesMut, BytesMut), DigestError> {
100 let digest_offset: usize = self.find_digest_offset(version)?;
101
102 let mut new_reader = BytesReader::new(self.reader.get_remaining_bytes());
103
104 let left_part = new_reader.read_bytes(digest_offset)?;
105 let digest_data = new_reader.read_bytes(define::RTMP_DIGEST_LENGTH)?;
106 let right_part = new_reader.extract_remaining_bytes();
107
108 Ok((left_part, digest_data, right_part))
109 }
110 pub fn make_digest(&mut self, raw_message: Vec<u8>) -> Result<BytesMut, DigestError> {
111 let mut mac = Hmac::<Sha256>::new_from_slice(&self.key[..]).unwrap();
112 mac.update(&raw_message);
113 let result = mac.finalize().into_bytes();
114
115 if result.len() != define::RTMP_DIGEST_LENGTH {
116 return Err(DigestError {
117 value: DigestErrorValue::DigestLengthNotCorrect,
118 });
119 }
120
121 let mut rv = BytesMut::new();
122 rv.extend_from_slice(result.as_slice());
123
124 Ok(rv)
125 }
126
127 fn generate_and_validate(&mut self, version: SchemaVersion) -> Result<BytesMut, DigestError> {
128 let (left_part, digest_data, right_part) = self.cook_raw_message(version)?;
129 let raw_message = [left_part, right_part].concat();
130
131 let computed_digest = self.make_digest(raw_message)?;
132
133 if digest_data == computed_digest {
134 return Ok(digest_data);
135 }
136
137 Err(DigestError {
138 value: DigestErrorValue::CannotGenerate,
139 })
140 }
141}