conmonrs/streaming_server/web/
accept_key.rs1use data_encoding::BASE64;
4
5const GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
7
8pub(super) fn accept_key(key: &[u8]) -> String {
17 BASE64.encode(&sha1(&[key, GUID].concat()))
18}
19
20fn sha1(data: &[u8]) -> [u8; 20] {
22 let mut message = data.to_vec();
25 message.push(0x80);
26 message.resize((message.len() + 8).next_multiple_of(64) - 8, 0);
27 let bits = (data.len() as u64).wrapping_mul(8);
28 message.extend_from_slice(&bits.to_be_bytes());
29
30 let mut state: [u32; 5] = [
31 0x6745_2301,
32 0xEFCD_AB89,
33 0x98BA_DCFE,
34 0x1032_5476,
35 0xC3D2_E1F0,
36 ];
37 for block in message.as_chunks::<64>().0 {
38 let mut w = [0u32; 80];
39 for (word, bytes) in w.iter_mut().zip(block.as_chunks::<4>().0) {
40 *word = u32::from_be_bytes(*bytes);
41 }
42 for t in 16..80 {
43 w[t] = (w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]).rotate_left(1);
44 }
45
46 let [mut a, mut b, mut c, mut d, mut e] = state;
47 for (t, word) in w.iter().enumerate() {
48 let (f, k) = match t {
49 0..20 => ((b & c) | (!b & d), 0x5A82_7999),
50 20..40 => (b ^ c ^ d, 0x6ED9_EBA1),
51 40..60 => ((b & c) | (b & d) | (c & d), 0x8F1B_BCDC),
52 _ => (b ^ c ^ d, 0xCA62_C1D6),
53 };
54 let temp = a
55 .rotate_left(5)
56 .wrapping_add(f)
57 .wrapping_add(e)
58 .wrapping_add(k)
59 .wrapping_add(*word);
60 (a, b, c, d, e) = (temp, a, b.rotate_left(30), c, d);
61 }
62 for (sum, value) in state.iter_mut().zip([a, b, c, d, e]) {
63 *sum = sum.wrapping_add(value);
64 }
65 }
66
67 let mut digest = [0; 20];
68 for (bytes, word) in digest.as_chunks_mut::<4>().0.iter_mut().zip(state) {
69 *bytes = word.to_be_bytes();
70 }
71 digest
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use data_encoding::HEXLOWER;
78
79 #[test]
80 fn accept_key_of_rfc_6455() {
81 assert_eq!(
82 accept_key(b"dGhlIHNhbXBsZSBub25jZQ=="),
83 "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="
84 );
85 }
86
87 #[test]
88 fn sha1_test_vectors() {
89 for (data, repeat, digest) in [
90 ("abc", 1, "a9993e364706816aba3e25717850c26c9cd0d89d"),
92 (
93 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
94 1,
95 "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
96 ),
97 ("a", 1_000_000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"),
98 (
99 "0123456701234567012345670123456701234567012345670123456701234567",
100 10,
101 "dea356a2cddd90c7a7ecedc5ebb563934f460452",
102 ),
103 ("", 1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
105 ("a", 55, "c1c8bbdc22796e28c0e15163d20899b65621d65a"),
106 ("a", 56, "c2db330f6083854c99d4b5bfb6e8f29f201be699"),
107 ("a", 63, "03f09f5b158a7a8cdad920bddc29b81c18a551f5"),
108 ("a", 64, "0098ba824b5c16427bd7a1122a5a442a25ec644d"),
109 ("a", 65, "11655326c708d70319be2610e8a57d9a5b959d3b"),
110 ] {
111 assert_eq!(
112 HEXLOWER.encode(&sha1(data.repeat(repeat).as_bytes())),
113 digest,
114 "{repeat} times {data:?}"
115 );
116 }
117 }
118}