ゴミ箱
mask.hpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9 
10 #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_MASK_HPP
11 #define BOOST_BEAST_WEBSOCKET_DETAIL_MASK_HPP
12 
13 #include <boost/asio/buffer.hpp>
14 #include <array>
15 #include <climits>
16 #include <cstdint>
17 #include <random>
18 #include <type_traits>
19 
20 namespace boost {
21 namespace beast {
22 namespace websocket {
23 namespace detail {
24 
25 // Pseudo-random source of mask keys
26 //
27 template<class Generator>
28 class maskgen_t
29 {
30  Generator g_;
31 
32 public:
33  using result_type =
34  typename Generator::result_type;
35 
36  maskgen_t();
37 
39  operator()() noexcept;
40 
41  void
42  rekey();
43 };
44 
45 template<class Generator>
46 maskgen_t<Generator>::maskgen_t()
47 {
48  rekey();
49 }
50 
51 template<class Generator>
52 auto
55 {
56  for(;;)
57  if(auto key = g_())
58  return key;
59 }
60 
61 template<class _>
62 void
64 {
65  std::random_device rng;
66 #if 0
67  std::array<std::uint32_t, 32> e;
68  for(auto& i : e)
69  i = rng();
70  // VFALCO This constructor causes
71  // address sanitizer to fail, no idea why.
72  std::seed_seq ss(e.begin(), e.end());
73  g_.seed(ss);
74 #else
75  g_.seed(rng());
76 #endif
77 }
78 
79 // VFALCO NOTE This generator has 5KB of state!
80 //using maskgen = maskgen_t<std::mt19937>;
82 
83 //------------------------------------------------------------------------------
84 
85 using prepared_key =
86  std::conditional<sizeof(void*) == 8,
87  std::uint64_t, std::uint32_t>::type;
88 
89 inline
90 void
91 prepare_key(std::uint32_t& prepared, std::uint32_t key)
92 {
93  prepared = key;
94 }
95 
96 inline
97 void
98 prepare_key(std::uint64_t& prepared, std::uint32_t key)
99 {
100  prepared =
101  (static_cast<std::uint64_t>(key) << 32) | key;
102 }
103 
104 template<class T>
105 inline
106 typename std::enable_if<std::is_integral<T>::value, T>::type
107 ror(T t, unsigned n = 1)
108 {
109  auto constexpr bits =
110  static_cast<unsigned>(
111  sizeof(T) * CHAR_BIT);
112  n &= bits-1;
113  return static_cast<T>((t << (bits - n)) | (
114  static_cast<typename std::make_unsigned<T>::type>(t) >> n));
115 }
116 
117 // 32-bit optimized
118 //
119 template<class = void>
120 void
122  boost::asio::mutable_buffer const& b,
123  std::uint32_t& key)
124 {
125  using boost::asio::buffer_cast;
126  using boost::asio::buffer_size;
127  auto n = buffer_size(b);
128  auto p = buffer_cast<std::uint8_t*>(b);
129  if(n >= sizeof(key))
130  {
131  // Bring p to 4-byte alignment
132  auto const i = reinterpret_cast<
133  std::uintptr_t>(p) & (sizeof(key)-1);
134  switch(i)
135  {
136  case 1: p[2] ^= static_cast<std::uint8_t>(key >> 16);
137  case 2: p[1] ^= static_cast<std::uint8_t>(key >> 8);
138  case 3: p[0] ^= static_cast<std::uint8_t>(key);
139  {
140  auto const d = static_cast<
141  unsigned>(sizeof(key) - i);
142  key = ror(key, 8*d);
143  n -= d;
144  p += d;
145  }
146  default:
147  break;
148  }
149  }
150 
151  // Mask 4 bytes at a time
152  for(auto i = n / sizeof(key); i; --i)
153  {
154  *reinterpret_cast<
155  std::uint32_t*>(p) ^= key;
156  p += sizeof(key);
157  }
158 
159  // Leftovers
160  n &= sizeof(key)-1;
161  switch(n)
162  {
163  case 3: p[2] ^= static_cast<std::uint8_t>(key >> 16);
164  case 2: p[1] ^= static_cast<std::uint8_t>(key >> 8);
165  case 1: p[0] ^= static_cast<std::uint8_t>(key);
166  key = ror(key, static_cast<unsigned>(8*n));
167  default:
168  break;
169  }
170 }
171 
172 // 64-bit optimized
173 //
174 template<class = void>
175 void
177  boost::asio::mutable_buffer const& b,
178  std::uint64_t& key)
179 {
180  using boost::asio::buffer_cast;
181  using boost::asio::buffer_size;
182  auto n = buffer_size(b);
183  auto p = buffer_cast<std::uint8_t*>(b);
184  if(n >= sizeof(key))
185  {
186  // Bring p to 8-byte alignment
187  auto const i = reinterpret_cast<
188  std::uintptr_t>(p) & (sizeof(key)-1);
189  switch(i)
190  {
191  case 1: p[6] ^= static_cast<std::uint8_t>(key >> 48);
192  case 2: p[5] ^= static_cast<std::uint8_t>(key >> 40);
193  case 3: p[4] ^= static_cast<std::uint8_t>(key >> 32);
194  case 4: p[3] ^= static_cast<std::uint8_t>(key >> 24);
195  case 5: p[2] ^= static_cast<std::uint8_t>(key >> 16);
196  case 6: p[1] ^= static_cast<std::uint8_t>(key >> 8);
197  case 7: p[0] ^= static_cast<std::uint8_t>(key);
198  {
199  auto const d = static_cast<
200  unsigned>(sizeof(key) - i);
201  key = ror(key, 8*d);
202  n -= d;
203  p += d;
204  }
205  default:
206  break;
207  }
208  }
209 
210  // Mask 8 bytes at a time
211  for(auto i = n / sizeof(key); i; --i)
212  {
213  *reinterpret_cast<
214  std::uint64_t*>(p) ^= key;
215  p += sizeof(key);
216  }
217 
218  // Leftovers
219  n &= sizeof(key)-1;
220  switch(n)
221  {
222  case 7: p[6] ^= static_cast<std::uint8_t>(key >> 48);
223  case 6: p[5] ^= static_cast<std::uint8_t>(key >> 40);
224  case 5: p[4] ^= static_cast<std::uint8_t>(key >> 32);
225  case 4: p[3] ^= static_cast<std::uint8_t>(key >> 24);
226  case 3: p[2] ^= static_cast<std::uint8_t>(key >> 16);
227  case 2: p[1] ^= static_cast<std::uint8_t>(key >> 8);
228  case 1: p[0] ^= static_cast<std::uint8_t>(key);
229  key = ror(key, static_cast<unsigned>(8*n));
230  default:
231  break;
232  }
233 }
234 
235 inline
236 void
238  boost::asio::mutable_buffer const& b,
239  std::uint32_t& key)
240 {
241  mask_inplace_fast(b, key);
242 }
243 
244 inline
245 void
247  boost::asio::mutable_buffer const& b,
248  std::uint64_t& key)
249 {
250  mask_inplace_fast(b, key);
251 }
252 
253 // Apply mask in place
254 //
255 template<class MutableBuffers, class KeyType>
256 void
258  MutableBuffers const& bs, KeyType& key)
259 {
260  for(boost::asio::mutable_buffer b : bs)
261  mask_inplace(b, key);
262 }
263 
264 } // detail
265 } // websocket
266 } // beast
267 } // boost
268 
269 #endif
Definition: async_result.hpp:20
void prepare_key(std::uint32_t &prepared, std::uint32_t key)
Definition: mask.hpp:91
result_type operator()() noexcept
Definition: mask.hpp:53
void mask_inplace_fast(boost::asio::mutable_buffer const &b, std::uint32_t &key)
Definition: mask.hpp:121
std::enable_if< std::is_integral< T >::value, T >::type ror(T t, unsigned n=1)
Definition: mask.hpp:107
std::conditional< sizeof(void *)==8, std::uint64_t, std::uint32_t >::type prepared_key
Definition: mask.hpp:87
void rekey()
Definition: mask.hpp:63
void mask_inplace(boost::asio::mutable_buffer const &b, std::uint32_t &key)
Definition: mask.hpp:237
typename Generator::result_type result_type
Definition: mask.hpp:34