diff --git a/test/utility/frame.cpp b/test/utility/frame.cpp index d79637aa8a..786ef0ba38 100644 --- a/test/utility/frame.cpp +++ b/test/utility/frame.cpp @@ -410,6 +410,43 @@ BOOST_AUTO_TEST_CASE( continuous_word_mask ) { BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) ); } +BOOST_AUTO_TEST_CASE( continuous_byte_mask ) { + uint8_t input[16]; + uint8_t output[16]; + + uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x00}; + + frame::masking_key_type key; + key.c[0] = 0x00; + key.c[1] = 0x01; + key.c[2] = 0x02; + key.c[3] = 0x03; + + // One call + size_t pkey,pkey_temp; + pkey = frame::prepare_masking_key(key); + std::fill_n(input,16,0x00); + std::fill_n(output,16,0x00); + frame::byte_mask_circ(input,output,15,pkey); + BOOST_CHECK( std::equal(output,output+16,masked) ); + + // calls not split on word boundaries + pkey = frame::prepare_masking_key(key); + std::fill_n(input,16,0x00); + std::fill_n(output,16,0x00); + + pkey_temp = frame::byte_mask_circ(input,output,7,pkey); + BOOST_CHECK( std::equal(output,output+7,masked) ); + BOOST_CHECK( pkey_temp == frame::circshift_prepared_key(pkey,3) ); + + pkey_temp = frame::byte_mask_circ(input+7,output+7,8,pkey_temp); + BOOST_CHECK( std::equal(output,output+16,masked) ); + BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) ); +} + BOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) { uint8_t buffer[16]; @@ -444,6 +481,40 @@ BOOST_AUTO_TEST_CASE( continuous_word_mask_inplace ) { BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) ); } +BOOST_AUTO_TEST_CASE( continuous_byte_mask_inplace ) { + uint8_t buffer[16]; + + uint8_t masked[16] = {0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x03, + 0x00, 0x01, 0x02, 0x00}; + + frame::masking_key_type key; + key.c[0] = 0x00; + key.c[1] = 0x01; + key.c[2] = 0x02; + key.c[3] = 0x03; + + // One call + size_t pkey,pkey_temp; + pkey = frame::prepare_masking_key(key); + std::fill_n(buffer,16,0x00); + frame::byte_mask_circ(buffer,15,pkey); + BOOST_CHECK( std::equal(buffer,buffer+16,masked) ); + + // calls not split on word boundaries + pkey = frame::prepare_masking_key(key); + std::fill_n(buffer,16,0x00); + + pkey_temp = frame::byte_mask_circ(buffer,7,pkey); + BOOST_CHECK( std::equal(buffer,buffer+7,masked) ); + BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) ); + + pkey_temp = frame::byte_mask_circ(buffer+7,8,pkey_temp); + BOOST_CHECK( std::equal(buffer,buffer+16,masked) ); + BOOST_CHECK_EQUAL( pkey_temp, frame::circshift_prepared_key(pkey,3) ); +} + BOOST_AUTO_TEST_CASE( continuous_word_mask2 ) { uint8_t buffer[12] = {0xA6, 0x15, 0x97, 0xB9, 0x81, 0x50, 0xAC, 0xBA, diff --git a/websocketpp/frame.hpp b/websocketpp/frame.hpp index 202a1dddd3..0a09de5830 100644 --- a/websocketpp/frame.hpp +++ b/websocketpp/frame.hpp @@ -831,6 +831,58 @@ inline size_t word_mask_circ(uint8_t* data, size_t length, size_t prepared_key){ return word_mask_circ(data,data,length,prepared_key); } +/// Circular byte aligned mask/unmask +/** + * Performs a circular mask/unmask in byte sized chunks using pre-prepared keys + * that store state between calls. Best for providing streaming masking or + * unmasking of small chunks at a time of a larger message. Requires that the + * underlying allocated size of the data buffer be a multiple of the word size. + * Data in the buffer after `length` will be overwritten only with the same + * values that were originally present. + * + * word_mask returns a copy of prepared_key circularly shifted based on the + * length value. The returned value may be fed back into byte_mask when more + * data is available. + * + * @param data Character buffer to mask + * + * @param length Length of data + * + * @param prepared_key Prepared key to use. + * + * @return the prepared_key shifted to account for the input length + */ +inline size_t byte_mask_circ(uint8_t * input, uint8_t * output, size_t length, + size_t prepared_key) +{ + uint32_converter key; + key.i = prepared_key; + + for (size_t i = 0; i < length; ++i) { + output[i] = input[i] ^ key.c[i % 4]; + } + + return circshift_prepared_key(prepared_key,length % 4); +} + +/// Circular byte aligned mask/unmask (in place) +/** + * In place version of byte_mask_circ + * + * @see byte_mask_circ + * + * @param data Character buffer to read from and write to + * + * @param length Length of data + * + * @param prepared_key Prepared key to use. + * + * @return the prepared_key shifted to account for the input length + */ +inline size_t byte_mask_circ(uint8_t* data, size_t length, size_t prepared_key){ + return byte_mask_circ(data,data,length,prepared_key); +} + } // namespace frame } // namespace websocketpp