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}