sheave_core/handshake.rs
1//! # Types for the handshake step in RTMP.
2//!
3//! In RTMP, first, both sides are required doing handshake.
4//! It is done respectively following steps:
5//!
6//! 1. Specifies RTMP version.
7//! 2. Exchanges handshake data each other.
8//! 3. Returns partner's handshake data.
9//!
10//! ## RTMP version
11//!
12//! 1 byte to specify a kind of encryption.
13//! Default is 3.
14//! This means doing handshake as the Raw RTMP, that is, not to encrypt.
15//! Server should respond 3 if encryption specified by client has not implemented.
16//! In this case, client can either degrade version to 3 or disconnect with server.
17//!
18//! ## Handshake
19//!
20//! 1536 bytes of actual handshake data.
21//! Note this can be imprinted HMAC-SHA256 diegst/signature according to version of Flash Player/Flash Media Server.
22//! Concretely, it is imprinted when respective version is following:
23//!
24//! * Flash Player: `>= 9`
25//! * Flash Media Server: `>= 3`
26//!
27//! ### Examples
28//!
29//! Both sides are required taking following steps each version.
30//!
31//! * Below Flash Player 9/Flash Media Server 3
32//!
33//! ```rust
34//! use std::time::Duration;
35//! use sheave_core::handshake::{
36//! Handshake,
37//! Version
38//! };
39//!
40//! let handshake = Handshake::new(Duration::default(), Version::UNSIGNED);
41//! ```
42//!
43//! * And above Flash Player 9/Flash Media Server 3
44//!
45//! ```rust
46//! use std::time::Duration;
47//! use sheave_core::handshake::{
48//! Handshake,
49//! Version,
50//! EncryptionAlgorithm
51//! };
52//!
53//! // In a case of exchanging client-side request with server-side response.
54//! let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
55//! client_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
56//! let mut key: Vec<u8> = Vec::new();
57//! key.extend_from_slice(Handshake::SERVER_KEY);
58//! key.extend_from_slice(Handshake::COMMON_KEY);
59//! client_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
60//! assert!(client_handshake.did_signature_match(EncryptionAlgorithm::NotEncrypted, key.as_slice()));
61//!
62//! // In a case of exchanging server-side request with client-side response.
63//! let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
64//! server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
65//! let mut key: Vec<u8> = Vec::new();
66//! key.extend_from_slice(Handshake::CLIENT_KEY);
67//! key.extend_from_slice(Handshake::COMMON_KEY);
68//! server_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
69//! assert!(server_handshake.did_signature_match(EncryptionAlgorithm::NotEncrypted, key.as_slice()));
70//! ```
71//!
72//! ### Encryption
73//!
74//! Currently, to implement handshake encryption isn't planned following causes:
75//!
76//! 1. Connected socket is in full view from outside. This is insecure though chunk is encrypted.
77//! 2. If chunk encryption is implemented on RTMPTS, To decrypt chunk/socket takes both sides time in no small way. This is inefficient for real-time communications.
78//! 3. Therefore I'm thinking we should leave encryption to only HTTPS.
79
80mod version;
81mod encryption_algorithm;
82
83use std::time::Duration;
84use rand::fill;
85use digest::{
86 CtOutput,
87 OutputSizeUser
88};
89use sha2::Sha256;
90use hmac::{
91 Hmac,
92 Mac
93};
94pub use self::{
95 version::Version,
96 encryption_algorithm::EncryptionAlgorithm
97};
98
99type HmacSha256 = Hmac<Sha256>;
100
101/// The 1536 bytes handshake data.
102/// This respectively consists of following parts:
103///
104/// |Range|Representation|
105/// | :- | :- |
106/// |First 4 bytes|Timestamp (in milliseconds)|
107/// |Second 4 bytes|Flash Player version/Flash Media Server version|
108/// |Remained bytes|Randoms for handshake (may be contained digest/signature)|
109#[derive(Debug)]
110pub struct Handshake([u8; 1536]);
111
112impl Handshake {
113 /// The key which is used to imprint any client-side digest.
114 pub const CLIENT_KEY: &'static [u8] = b"Genuine Adobe Flash Player 001";
115 /// The key which is used to imprint any server-side digest.
116 pub const SERVER_KEY: &'static [u8] = b"Genuine Adobe Flash Media Server 001";
117 /// The key which is used to imprint any signature.
118 /// Both sides are required to contain this into a key of signature.
119 pub const COMMON_KEY: &'static [u8] = &[
120 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
121 ];
122
123 /// Constructs handshake data.
124 ///
125 /// # Examples
126 ///
127 /// ```rust
128 /// use std::time::Duration;
129 /// use sheave_core::handshake::{
130 /// Handshake,
131 /// Version,
132 /// EncryptionAlgorithm
133 /// };
134 ///
135 /// // If you are a client.
136 /// let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
137 /// // If you are a server.
138 /// let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
139 /// ```
140 pub fn new(timestamp: Duration, version: Version) -> Self {
141 let mut handshake_bytes: [u8; 1536] = [0; 1536];
142 let timestamp_bytes = (timestamp.as_millis() as u32).to_be_bytes();
143 let version_bytes: [u8; 4] = version.into();
144 handshake_bytes[..4].copy_from_slice(timestamp_bytes.as_slice());
145 handshake_bytes[4..8].copy_from_slice(version_bytes.as_slice());
146 fill(&mut handshake_bytes[8..]);
147 Self(handshake_bytes)
148 }
149
150 /// Gets all handshake data.
151 pub fn get_bytes(&self) -> &[u8] {
152 &self.0
153 }
154
155 /// Gets first 4 bytes as timestamp.
156 pub fn get_timestamp(&self) -> Duration {
157 let mut timestamp_bytes: [u8; 4] = [0; 4];
158 timestamp_bytes.copy_from_slice(&self.0[..4]);
159 Duration::from_millis(u32::from_be_bytes(timestamp_bytes) as u64)
160 }
161
162 /// Gets second 4 bytes as Flash Player version/Flash Media Server version.
163 pub fn get_version(&self) -> Version {
164 let mut version_bytes: [u8; 4] = [0; 4];
165 version_bytes.copy_from_slice(&self.0[4..8]);
166 version_bytes.into()
167 }
168
169 fn get_digest_position(&self, encryption_algorithm: EncryptionAlgorithm) -> usize {
170 let offset: usize;
171 let adder: usize;
172 match encryption_algorithm {
173 EncryptionAlgorithm::NotEncrypted => {
174 offset = 8;
175 adder = 12;
176 },
177 _ => {
178 offset = 772;
179 adder = 776;
180 }
181 }
182 self.0[offset..(offset + 4)].iter().map(|byte| usize::from(*byte)).sum::<usize>() % 728 + adder
183 }
184
185 fn get_digest_message(&self, encryption_algorithm: EncryptionAlgorithm) -> Vec<u8> {
186 let digest_position = self.get_digest_position(encryption_algorithm);
187 let mut message: Vec<u8> = Vec::new();
188 message.extend_from_slice(&self.0[..digest_position]);
189 message.extend_from_slice(&self.0[(digest_position + HmacSha256::output_size())..]);
190 message
191 }
192
193 fn compute_digest(&self, encryption_algorithm: EncryptionAlgorithm, key: &[u8]) -> CtOutput<HmacSha256> {
194 let message = self.get_digest_message(encryption_algorithm);
195 let mut hmac = HmacSha256::new_from_slice(key).unwrap();
196 hmac.update(message.as_slice());
197 hmac.finalize()
198 }
199
200 /// Gets a digest contained in this handshake bytes.
201 /// Note its place is different by whether encrypts handshake bytes.
202 ///
203 /// # Examples
204 ///
205 /// ```rust
206 /// use std::time::Instant;
207 /// use sheave_core::handshake::{
208 /// EncryptionAlgorithm,
209 /// Handshake,
210 /// Version
211 /// };
212 ///
213 /// let handshake = Handshake::new(Instant::now().elapsed(), Version::LATEST_CLIENT);
214 ///
215 /// assert_ne!(handshake.get_digest(EncryptionAlgorithm::NotEncrypted), handshake.get_digest(EncryptionAlgorithm::DiffieHellman))
216 /// ```
217 pub fn get_digest(&self, encryption_algorithm: EncryptionAlgorithm) -> &[u8] {
218 let digest_position = self.get_digest_position(encryption_algorithm);
219 &self.0[digest_position..(digest_position + HmacSha256::output_size())]
220 }
221
222 /// Imprints an HMAC-SHA256 digest into handshake data.
223 ///
224 /// # Examples
225 ///
226 /// ```rust
227 /// use std::time::Duration;
228 /// use sheave_core::handshake::{
229 /// Handshake,
230 /// Version,
231 /// EncryptionAlgorithm
232 /// };
233 ///
234 /// // In a case of sending client-side request.
235 /// let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
236 /// client_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
237 ///
238 /// // In a case of sending server-side request.
239 /// let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
240 /// server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
241 /// ```
242 pub fn imprint_digest(&mut self, encryption_algorithm: EncryptionAlgorithm, key: &[u8]) {
243 let digest_position = self.get_digest_position(encryption_algorithm);
244 let digest = self.compute_digest(encryption_algorithm, key);
245 self.0[digest_position..(digest_position + HmacSha256::output_size())].copy_from_slice(digest.into_bytes().as_slice());
246 }
247
248 /// Checks whether imprinted digest matches with one computed by given key.
249 ///
250 /// # Examples
251 ///
252 /// ```rust
253 /// use std::time::Duration;
254 /// use sheave_core::handshake::{
255 /// Handshake,
256 /// Version,
257 /// EncryptionAlgorithm
258 /// };
259 ///
260 /// // In a case of checking server-side request.
261 /// let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
262 /// server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
263 /// assert!(server_handshake.did_digest_match(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY));
264 ///
265 /// // In a case of checking client-side request.
266 /// let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
267 /// server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
268 /// assert!(server_handshake.did_digest_match(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY));
269 /// ```
270 pub fn did_digest_match(&self, encryption_algorithm: EncryptionAlgorithm, key: &[u8]) -> bool {
271 let expected = self.compute_digest(encryption_algorithm, key);
272 self.get_digest(encryption_algorithm) == expected.into_bytes().as_slice()
273 }
274
275 fn get_signature_position(&self) -> usize {
276 self.0.len() - HmacSha256::output_size()
277 }
278
279 fn get_signature_message(&self) -> &[u8] {
280 let signature_position = self.get_signature_position();
281 &self.0[..signature_position]
282 }
283
284 fn compute_signature(&self, encryption_algorithm: EncryptionAlgorithm, key: &[u8]) -> CtOutput<HmacSha256> {
285 let digest = self.get_digest(encryption_algorithm);
286 let mut hmac = HmacSha256::new_from_slice(key).unwrap();
287 hmac.update(digest);
288 let key_from_digest = hmac.finalize();
289
290 let message = self.get_signature_message();
291 let mut hmac = HmacSha256::new_from_slice(key_from_digest.into_bytes().as_slice()).unwrap();
292 hmac.update(message);
293 hmac.finalize()
294 }
295
296 /// Gets a signature contained into this handshake bytes.
297 pub fn get_signature(&self) -> &[u8] {
298 let signature_position = self.get_signature_position();
299 &self.0[signature_position..]
300
301 }
302
303 /// Imprints an HMAC-SHA256 signature into handshake data.
304 ///
305 /// # Examples
306 ///
307 /// ```rust
308 /// use std::time::Duration;
309 /// use sheave_core::handshake::{
310 /// Handshake,
311 /// Version,
312 /// EncryptionAlgorithm
313 /// };
314 ///
315 /// // In a case of exchanging client-side request with server-side response.
316 /// let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
317 /// client_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
318 /// let mut key: Vec<u8> = Vec::new();
319 /// key.extend_from_slice(Handshake::SERVER_KEY);
320 /// key.extend_from_slice(Handshake::COMMON_KEY);
321 /// client_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
322 ///
323 /// // In a case of exchanging server-side request with client-side response.
324 /// let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
325 /// server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
326 /// let mut key: Vec<u8> = Vec::new();
327 /// key.extend_from_slice(Handshake::CLIENT_KEY);
328 /// key.extend_from_slice(Handshake::COMMON_KEY);
329 /// server_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
330 /// ```
331 pub fn imprint_signature(&mut self, encryption_algorithm: EncryptionAlgorithm, key: &[u8]) {
332 let signature_position = self.get_signature_position();
333 let signature = self.compute_signature(encryption_algorithm, key);
334 self.0[signature_position..].copy_from_slice(signature.into_bytes().as_slice());
335 }
336
337 /// Checks whether imprinted signature matches one computed by given key.
338 ///
339 /// # Examples
340 ///
341 /// ```rust
342 /// use std::time::Duration;
343 /// use sheave_core::handshake::{
344 /// Handshake,
345 /// Version,
346 /// EncryptionAlgorithm
347 /// };
348 ///
349 /// // In a case of checking client-side response.
350 /// let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
351 /// client_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
352 /// let mut key: Vec<u8> = Vec::new();
353 /// key.extend_from_slice(Handshake::SERVER_KEY);
354 /// key.extend_from_slice(Handshake::COMMON_KEY);
355 /// client_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
356 /// assert!(client_handshake.did_signature_match(EncryptionAlgorithm::NotEncrypted, key.as_slice()));
357 ///
358 /// // In a case of checking server-side response.
359 /// let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
360 /// server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
361 /// let mut key: Vec<u8> = Vec::new();
362 /// key.extend_from_slice(Handshake::CLIENT_KEY);
363 /// key.extend_from_slice(Handshake::COMMON_KEY);
364 /// server_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
365 /// assert!(server_handshake.did_signature_match(EncryptionAlgorithm::NotEncrypted, key.as_slice()));
366 /// ```
367 pub fn did_signature_match(&self, encryption_algorithm: EncryptionAlgorithm, key: &[u8]) -> bool {
368 let expected = self.compute_signature(encryption_algorithm, key);
369 self.get_signature() == expected.into_bytes().as_slice()
370 }
371}
372
373impl From<[u8; 1536]> for Handshake {
374 fn from(handshake_bytes: [u8; 1536]) -> Self {
375 Self(handshake_bytes)
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382
383 #[test]
384 fn did_client_digest_match() {
385 let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
386 client_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
387 assert!(client_handshake.did_digest_match(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY))
388 }
389
390 #[test]
391 fn did_server_digest_match() {
392 let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
393 server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
394 assert!(server_handshake.did_digest_match(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY))
395 }
396
397 #[test]
398 fn did_client_signature_match() {
399 let mut client_handshake = Handshake::new(Duration::default(), Version::LATEST_CLIENT);
400 client_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::CLIENT_KEY);
401 let mut key: Vec<u8> = Vec::new();
402 key.extend_from_slice(Handshake::SERVER_KEY);
403 key.extend_from_slice(Handshake::COMMON_KEY);
404 client_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
405 assert!(client_handshake.did_signature_match(EncryptionAlgorithm::NotEncrypted, key.as_slice()))
406 }
407
408 #[test]
409 fn did_server_signature_match() {
410 let mut server_handshake = Handshake::new(Duration::default(), Version::LATEST_SERVER);
411 server_handshake.imprint_digest(EncryptionAlgorithm::NotEncrypted, Handshake::SERVER_KEY);
412 let mut key: Vec<u8> = Vec::new();
413 key.extend_from_slice(Handshake::CLIENT_KEY);
414 key.extend_from_slice(Handshake::COMMON_KEY);
415 server_handshake.imprint_signature(EncryptionAlgorithm::NotEncrypted, key.as_slice());
416 assert!(server_handshake.did_signature_match(EncryptionAlgorithm::NotEncrypted, key.as_slice()))
417 }
418}