1 | // Copyright (c) 2016 Alex Hultman and contributors |
2 | |
3 | // This software is provided 'as-is', without any express or implied |
4 | // warranty. In no event will the authors be held liable for any damages |
5 | // arising from the use of this software. |
6 | |
7 | // Permission is granted to anyone to use this software for any purpose, |
8 | // including commercial applications, and to alter it and redistribute it |
9 | // freely, subject to the following restrictions: |
10 | |
11 | // 1. The origin of this software must not be misrepresented; you must not |
12 | // claim that you wrote the original software. If you use this software |
13 | // in a product, an acknowledgement in the product documentation would be |
14 | // appreciated but is not required. |
15 | // 2. Altered source versions must be plainly marked as such, and must not be |
16 | // misrepresented as being the original software. |
17 | // 3. This notice may not be removed or altered from any source distribution. |
18 | |
19 | #pragma once |
20 | |
21 | #include <cstddef> |
22 | #include <cstdint> |
23 | #include <string.h> |
24 | #include <string> |
25 | |
26 | class WebSocketHandshakeKeyGen |
27 | { |
28 | template<int N, typename T> |
29 | struct static_for |
30 | { |
31 | void operator()(uint32_t* a, uint32_t* b) |
32 | { |
33 | static_for<N - 1, T>()(a, b); |
34 | T::template f<N - 1>(a, b); |
35 | } |
36 | }; |
37 | |
38 | template<typename T> |
39 | struct static_for<0, T> |
40 | { |
41 | void operator()(uint32_t* /*a*/, uint32_t* /*hash*/) |
42 | { |
43 | } |
44 | }; |
45 | |
46 | template<int state> |
47 | struct Sha1Loop |
48 | { |
49 | static inline uint32_t rol(uint32_t value, size_t bits) |
50 | { |
51 | return (value << bits) | (value >> (32 - bits)); |
52 | } |
53 | static inline uint32_t blk(uint32_t b[16], size_t i) |
54 | { |
55 | return rol(b[(i + 13) & 15] ^ b[(i + 8) & 15] ^ b[(i + 2) & 15] ^ b[i], 1); |
56 | } |
57 | |
58 | template<int i> |
59 | static inline void f(uint32_t* a, uint32_t* b) |
60 | { |
61 | switch (state) |
62 | { |
63 | case 1: |
64 | a[i % 5] += |
65 | ((a[(3 + i) % 5] & (a[(2 + i) % 5] ^ a[(1 + i) % 5])) ^ a[(1 + i) % 5]) + |
66 | b[i] + 0x5a827999 + rol(a[(4 + i) % 5], 5); |
67 | a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
68 | break; |
69 | case 2: |
70 | b[i] = blk(b, i); |
71 | a[(1 + i) % 5] += |
72 | ((a[(4 + i) % 5] & (a[(3 + i) % 5] ^ a[(2 + i) % 5])) ^ a[(2 + i) % 5]) + |
73 | b[i] + 0x5a827999 + rol(a[(5 + i) % 5], 5); |
74 | a[(4 + i) % 5] = rol(a[(4 + i) % 5], 30); |
75 | break; |
76 | case 3: |
77 | b[(i + 4) % 16] = blk(b, (i + 4) % 16); |
78 | a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + |
79 | b[(i + 4) % 16] + 0x6ed9eba1 + rol(a[(4 + i) % 5], 5); |
80 | a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
81 | break; |
82 | case 4: |
83 | b[(i + 8) % 16] = blk(b, (i + 8) % 16); |
84 | a[i % 5] += (((a[(3 + i) % 5] | a[(2 + i) % 5]) & a[(1 + i) % 5]) | |
85 | (a[(3 + i) % 5] & a[(2 + i) % 5])) + |
86 | b[(i + 8) % 16] + 0x8f1bbcdc + rol(a[(4 + i) % 5], 5); |
87 | a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
88 | break; |
89 | case 5: |
90 | b[(i + 12) % 16] = blk(b, (i + 12) % 16); |
91 | a[i % 5] += (a[(3 + i) % 5] ^ a[(2 + i) % 5] ^ a[(1 + i) % 5]) + |
92 | b[(i + 12) % 16] + 0xca62c1d6 + rol(a[(4 + i) % 5], 5); |
93 | a[(3 + i) % 5] = rol(a[(3 + i) % 5], 30); |
94 | break; |
95 | case 6: b[i] += a[4 - i]; |
96 | } |
97 | } |
98 | }; |
99 | |
100 | static inline void sha1(uint32_t hash[5], uint32_t b[16]) |
101 | { |
102 | uint32_t a[5] = {hash[4], hash[3], hash[2], hash[1], hash[0]}; |
103 | static_for<16, Sha1Loop<1>>()(a, b); |
104 | static_for<4, Sha1Loop<2>>()(a, b); |
105 | static_for<20, Sha1Loop<3>>()(a, b); |
106 | static_for<20, Sha1Loop<4>>()(a, b); |
107 | static_for<20, Sha1Loop<5>>()(a, b); |
108 | static_for<5, Sha1Loop<6>>()(a, hash); |
109 | } |
110 | |
111 | static inline void base64(unsigned char* src, char* dst) |
112 | { |
113 | const char* b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; |
114 | for (int i = 0; i < 18; i += 3) |
115 | { |
116 | *dst++ = b64[(src[i] >> 2) & 63]; |
117 | *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; |
118 | *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; |
119 | *dst++ = b64[src[i + 2] & 63]; |
120 | } |
121 | *dst++ = b64[(src[18] >> 2) & 63]; |
122 | *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; |
123 | *dst++ = b64[((src[19] & 15) << 2)]; |
124 | *dst++ = '='; |
125 | } |
126 | |
127 | public: |
128 | static inline void generate(const std::string& inputStr, char output[28]) |
129 | { |
130 | char input[25] = {}; |
131 | strncpy(input, inputStr.c_str(), 25 - 1); |
132 | input[25 - 1] = '\0'; |
133 | |
134 | uint32_t b_output[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}; |
135 | uint32_t b_input[16] = {0, |
136 | 0, |
137 | 0, |
138 | 0, |
139 | 0, |
140 | 0, |
141 | 0x32353845, |
142 | 0x41464135, |
143 | 0x2d453931, |
144 | 0x342d3437, |
145 | 0x44412d39, |
146 | 0x3543412d, |
147 | 0x43354142, |
148 | 0x30444338, |
149 | 0x35423131, |
150 | 0x80000000}; |
151 | |
152 | for (int i = 0; i < 6; i++) |
153 | { |
154 | b_input[i] = (input[4 * i + 3] & 0xff) | (input[4 * i + 2] & 0xff) << 8 | |
155 | (input[4 * i + 1] & 0xff) << 16 | (input[4 * i + 0] & 0xff) << 24; |
156 | } |
157 | sha1(b_output, b_input); |
158 | uint32_t last_b[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 480}; |
159 | sha1(b_output, last_b); |
160 | for (int i = 0; i < 5; i++) |
161 | { |
162 | uint32_t tmp = b_output[i]; |
163 | char* bytes = (char*) &b_output[i]; |
164 | bytes[3] = tmp & 0xff; |
165 | bytes[2] = (tmp >> 8) & 0xff; |
166 | bytes[1] = (tmp >> 16) & 0xff; |
167 | bytes[0] = (tmp >> 24) & 0xff; |
168 | } |
169 | base64((unsigned char*) b_output, output); |
170 | } |
171 | }; |
172 | |