scuffle_rtmp/handshake/complex/
mod.rs1use std::io::{self, Seek, Write};
8
9use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
10use bytes::{BufMut, Bytes, BytesMut};
11use digest::DigestProcessor;
12use rand::Rng;
13use scuffle_bytes_util::BytesCursorExt;
14
15use super::{RTMP_HANDSHAKE_SIZE, RtmpVersion, ServerHandshakeState, TIME_VERSION_LENGTH, current_time};
16
17pub mod digest;
18pub mod error;
19
20pub const RTMP_SERVER_VERSION: u32 = 0x04050001;
23
24pub const RTMP_DIGEST_LENGTH: usize = 32;
28
29pub const RTMP_SERVER_KEY_FIRST_HALF: &[u8] = b"Genuine Adobe Flash Media Server 001";
31
32pub const RTMP_CLIENT_KEY_FIRST_HALF: &[u8] = b"Genuine Adobe Flash Player 001";
34
35pub const RTMP_SERVER_KEY: &[u8] = &[
38 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
39 0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a,
40 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab,
41 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae,
42];
43
44#[derive(Debug, PartialEq, Eq, Clone, Copy)]
54pub enum SchemaVersion {
55 Schema0,
57 Schema1,
59}
60
61pub struct ComplexHandshakeServer {
63 version: RtmpVersion,
64 requested_version: RtmpVersion,
65 state: ServerHandshakeState,
66 schema_version: SchemaVersion,
67 c1_digest: Bytes,
68 c1_timestamp: u32,
69 c1_version: u32,
70}
71
72impl Default for ComplexHandshakeServer {
73 fn default() -> Self {
74 Self {
75 state: ServerHandshakeState::ReadC0C1,
76 c1_digest: Bytes::default(),
77 c1_timestamp: 0,
78 version: RtmpVersion::Version3,
79 requested_version: RtmpVersion(0),
80 c1_version: 0,
81 schema_version: SchemaVersion::Schema0,
82 }
83 }
84}
85
86impl ComplexHandshakeServer {
87 pub fn is_finished(&self) -> bool {
89 self.state == ServerHandshakeState::Finish
90 }
91
92 pub fn handshake(&mut self, input: &mut io::Cursor<Bytes>, output: &mut Vec<u8>) -> Result<(), crate::error::RtmpError> {
94 match self.state {
95 ServerHandshakeState::ReadC0C1 => {
96 self.read_c0(input)?;
97 self.read_c1(input)?;
98 self.write_s0(output)?;
99 self.write_s1(output)?;
100 self.write_s2(output)?;
101 self.state = ServerHandshakeState::ReadC2;
102 }
103 ServerHandshakeState::ReadC2 => {
104 self.read_c2(input)?;
105 self.state = ServerHandshakeState::Finish;
106 }
107 ServerHandshakeState::Finish => {}
108 }
109
110 Ok(())
111 }
112
113 fn read_c0(&mut self, input: &mut io::Cursor<Bytes>) -> Result<(), crate::error::RtmpError> {
114 self.requested_version = RtmpVersion(input.read_u8()?);
117
118 self.version = RtmpVersion::Version3;
121
122 Ok(())
123 }
124
125 fn read_c1(&mut self, input: &mut io::Cursor<Bytes>) -> Result<(), crate::error::RtmpError> {
126 let c1_bytes = input.extract_bytes(RTMP_HANDSHAKE_SIZE)?;
127
128 self.c1_timestamp = (&c1_bytes[0..4]).read_u32::<BigEndian>()?;
130
131 self.c1_version = (&c1_bytes[4..8]).read_u32::<BigEndian>()?;
133
134 let data_digest = DigestProcessor::new(c1_bytes, RTMP_CLIENT_KEY_FIRST_HALF);
136
137 let (c1_digest_data, schema_version) = data_digest.read_digest()?;
138
139 self.c1_digest = c1_digest_data;
140 self.schema_version = schema_version;
141
142 Ok(())
143 }
144
145 fn read_c2(&mut self, input: &mut io::Cursor<Bytes>) -> Result<(), crate::error::RtmpError> {
146 input.seek_relative(RTMP_HANDSHAKE_SIZE as i64)?;
149
150 Ok(())
151 }
152
153 fn write_s0(&mut self, output: &mut Vec<u8>) -> Result<(), crate::error::RtmpError> {
154 output.write_u8(self.version.0)?; Ok(())
159 }
160
161 fn write_s1(&self, output: &mut Vec<u8>) -> Result<(), crate::error::RtmpError> {
162 let mut writer = BytesMut::new().writer();
163
164 writer.write_u32::<BigEndian>(current_time())?;
166
167 writer.write_u32::<BigEndian>(RTMP_SERVER_VERSION)?;
169
170 let mut rng = rand::rng();
173 for _ in 0..RTMP_HANDSHAKE_SIZE - TIME_VERSION_LENGTH {
174 writer.write_u8(rng.random())?;
175 }
176
177 let data_digest = DigestProcessor::new(writer.into_inner().freeze(), RTMP_SERVER_KEY_FIRST_HALF);
179
180 data_digest.generate_and_fill_digest(self.schema_version)?.write_to(output)?;
182
183 Ok(())
184 }
185
186 fn write_s2(&self, output: &mut Vec<u8>) -> Result<(), crate::error::RtmpError> {
187 let start = output.len();
188
189 output.write_u32::<BigEndian>(current_time())?;
191
192 output.write_u32::<BigEndian>(self.c1_timestamp)?;
194
195 let mut rng = rand::rng();
198
199 for _ in 0..RTMP_HANDSHAKE_SIZE - RTMP_DIGEST_LENGTH - TIME_VERSION_LENGTH {
202 output.write_u8(rng.random())?;
203 }
204
205 let key_digest = DigestProcessor::new(Bytes::new(), RTMP_SERVER_KEY);
208
209 let key = key_digest.make_digest(&self.c1_digest, &[])?;
212 let data_digest = DigestProcessor::new(Bytes::new(), &key);
213
214 let digest = data_digest.make_digest(&output[start..start + RTMP_HANDSHAKE_SIZE - RTMP_DIGEST_LENGTH], &[])?;
219
220 output.write_all(&digest)?; Ok(())
225 }
226}