// // Copyright (c) 2016-2017 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) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_WEBSOCKET_DETAIL_MASK_HPP #define BOOST_BEAST_WEBSOCKET_DETAIL_MASK_HPP #include #include #include #include #include #include #include namespace boost { 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; #if 0 std::array e; for(auto& i : e) i = rng(); // VFALCO This constructor causes // address sanitizer to fail, no idea why. std::seed_seq ss(e.begin(), e.end()); g_.seed(ss); #else g_.seed(rng()); #endif } // VFALCO NOTE This generator has 5KB of state! //using maskgen = maskgen_t; using maskgen = maskgen_t; //------------------------------------------------------------------------------ using prepared_key = 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 optimized // template void mask_inplace_fast( boost::asio::mutable_buffer const& b, std::uint32_t& key) { auto n = b.size(); auto p = reinterpret_cast(b.data()); if(n >= sizeof(key)) { // Bring p to 4-byte alignment auto const i = reinterpret_cast< std::uintptr_t>(p) & (sizeof(key)-1); switch(i) { case 1: p[2] ^= static_cast(key >> 16); BOOST_BEAST_FALLTHROUGH; case 2: p[1] ^= static_cast(key >> 8); BOOST_BEAST_FALLTHROUGH; case 3: p[0] ^= static_cast(key); { auto const d = static_cast(sizeof(key) - i); key = ror(key, 8*d); n -= d; p += d; BOOST_BEAST_FALLTHROUGH; } default: break; } } // Mask 4 bytes at a time for(auto i = n / sizeof(key); i; --i) { *reinterpret_cast< std::uint32_t*>(p) ^= key; p += sizeof(key); } // Leftovers n &= sizeof(key)-1; switch(n) { case 3: p[2] ^= static_cast(key >> 16); BOOST_BEAST_FALLTHROUGH; case 2: p[1] ^= static_cast(key >> 8); BOOST_BEAST_FALLTHROUGH; case 1: p[0] ^= static_cast(key); key = ror(key, static_cast(8*n)); BOOST_BEAST_FALLTHROUGH; default: break; } } // 64-bit optimized // template void mask_inplace_fast( boost::asio::mutable_buffer const& b, std::uint64_t& key) { auto n = b.size(); auto p = reinterpret_cast(b.data()); if(n >= sizeof(key)) { // Bring p to 8-byte alignment auto const i = reinterpret_cast< std::uintptr_t>(p) & (sizeof(key)-1); switch(i) { case 1: p[6] ^= static_cast(key >> 48); case 2: p[5] ^= static_cast(key >> 40); case 3: p[4] ^= static_cast(key >> 32); case 4: p[3] ^= static_cast(key >> 24); case 5: p[2] ^= static_cast(key >> 16); case 6: p[1] ^= static_cast(key >> 8); case 7: p[0] ^= static_cast(key); { auto const d = static_cast< unsigned>(sizeof(key) - i); key = ror(key, 8*d); n -= d; p += d; } default: break; } } // Mask 8 bytes at a time for(auto i = n / sizeof(key); i; --i) { *reinterpret_cast< std::uint64_t*>(p) ^= key; p += sizeof(key); } // Leftovers n &= sizeof(key)-1; switch(n) { case 7: p[6] ^= static_cast(key >> 48); case 6: p[5] ^= static_cast(key >> 40); case 5: p[4] ^= static_cast(key >> 32); case 4: p[3] ^= static_cast(key >> 24); case 3: p[2] ^= static_cast(key >> 16); case 2: p[1] ^= static_cast(key >> 8); case 1: p[0] ^= static_cast(key); key = ror(key, static_cast(8*n)); default: break; } } inline void mask_inplace( boost::asio::mutable_buffer const& b, std::uint32_t& key) { mask_inplace_fast(b, key); } inline void mask_inplace( boost::asio::mutable_buffer const& b, std::uint64_t& key) { mask_inplace_fast(b, key); } // Apply mask in place // template void mask_inplace( MutableBuffers const& bs, KeyType& key) { for(boost::asio::mutable_buffer b : bs) mask_inplace(b, key); } } // detail } // websocket } // beast } // boost #endif