// // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BEAST_WEBSOCKET_DETAIL_MASK_HPP #define BEAST_WEBSOCKET_DETAIL_MASK_HPP #include #include #include #include #include #include namespace beast { namespace websocket { namespace detail { // Pseudo-random source of mask keys // template class maskgen_t { Generator g_; public: using result_type = typename Generator::result_type; maskgen_t(); result_type operator()() noexcept; void rekey(); }; template maskgen_t::maskgen_t() { rekey(); } template auto maskgen_t::operator()() noexcept -> result_type { for(;;) if(auto key = g_()) return key; } template void maskgen_t<_>::rekey() { std::random_device rng; std::array e; for(auto& i : e) i = rng(); std::seed_seq ss(e.begin(), e.end()); g_.seed(ss); } using maskgen = maskgen_t; //------------------------------------------------------------------------------ using prepared_key_type = std::conditional::type; inline void prepare_key(std::uint32_t& prepared, std::uint32_t key) { prepared = key; } inline void prepare_key(std::uint64_t& prepared, std::uint32_t key) { prepared = (static_cast(key) << 32) | key; } template inline typename std::enable_if::value, T>::type ror(T t, unsigned n = 1) { auto constexpr bits = static_cast( sizeof(T) * CHAR_BIT); n &= bits-1; return static_cast((t << (bits - n)) | ( static_cast::type>(t) >> n)); } // 32-bit Unoptimized // template void mask_inplace_general( boost::asio::mutable_buffer const& b, std::uint32_t& key) { using boost::asio::buffer_cast; using boost::asio::buffer_size; auto n = buffer_size(b); auto p = buffer_cast(b); for(auto i = n / sizeof(key); i; --i) { *p ^= key ; ++p; *p ^= (key >> 8); ++p; *p ^= (key >>16); ++p; *p ^= (key >>24); ++p; } n %= sizeof(key); switch(n) { case 3: p[2] ^= (key >>16); case 2: p[1] ^= (key >> 8); case 1: p[0] ^= key; key = ror(key, n*8); default: break; } } // 64-bit unoptimized // template void mask_inplace_general( boost::asio::mutable_buffer const& b, std::uint64_t& key) { using boost::asio::buffer_cast; using boost::asio::buffer_size; auto n = buffer_size(b); auto p = buffer_cast(b); for(auto i = n / sizeof(key); i; --i) { *p ^= key ; ++p; *p ^= (key >> 8); ++p; *p ^= (key >>16); ++p; *p ^= (key >>24); ++p; *p ^= (key >>32); ++p; *p ^= (key >>40); ++p; *p ^= (key >>48); ++p; *p ^= (key >>56); ++p; } n %= sizeof(key); switch(n) { case 7: p[6] ^= (key >>16); case 6: p[5] ^= (key >> 8); case 5: p[4] ^= key; case 4: p[3] ^= (key >>24); case 3: p[2] ^= (key >>16); case 2: p[1] ^= (key >> 8); case 1: p[0] ^= key; key = ror(key, n*8); default: break; } } inline void mask_inplace( boost::asio::mutable_buffer const& b, std::uint32_t& key) { mask_inplace_general(b, key); } inline void mask_inplace( boost::asio::mutable_buffer const& b, std::uint64_t& key) { mask_inplace_general(b, key); } // Apply mask in place // template void mask_inplace( MutableBuffers const& bs, KeyType& key) { for(auto const& b : bs) mask_inplace(b, key); } } // detail } // websocket } // beast #endif