From 689c03ed0e9ba3ccaf10653e784475faa8ba94de Mon Sep 17 00:00:00 2001 From: Daniel Scharrer <~@ds.me> Date: Wed, 1 Jan 2025 18:48:17 +0100 Subject: [PATCH 1/3] iteratedhash: Add support for using a pre-initialized state --- src/crypto/iteratedhash.hpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/crypto/iteratedhash.hpp b/src/crypto/iteratedhash.hpp index 02930845..37f7202a 100644 --- a/src/crypto/iteratedhash.hpp +++ b/src/crypto/iteratedhash.hpp @@ -51,6 +51,7 @@ class iterated_hash : public checksum_base< iterated_hash > { typedef typename transform::byte_order byte_order; static const size_t block_size = transform::block_size; static const size_t hash_size = transform::hash_size / sizeof(hash_word); + typedef hash_word state_t[hash_size]; void init() { count_lo = count_hi = 0; transform::init(state); } @@ -58,9 +59,20 @@ class iterated_hash : public checksum_base< iterated_hash > { void finalize(char * result); + static void prepare_state(const char * data, size_t count, state_t state) { + transform::init(state); + hash(state, data, count * block_size); + } + + void init(const state_t init_state, size_t init_count) { + count_lo = hash_word(init_count * block_size); + count_hi = hash_word(util::safe_right_shift<8 * sizeof(hash_word)>(init_count * block_size)); + std::memcpy(state, init_state, sizeof(state)); + } + private: - size_t hash(const char * input, size_t length); + static size_t hash(state_t state, const char * input, size_t length); void pad(size_t last_block_size, char pad_first = '\x80'); hash_word bit_count_hi() const { @@ -69,7 +81,7 @@ class iterated_hash : public checksum_base< iterated_hash > { hash_word bit_count_lo() const { return count_lo << 3; } char buffer[block_size]; - hash_word state[hash_size]; + state_t state; hash_word count_lo, count_hi; @@ -91,7 +103,7 @@ void iterated_hash::update(const char * data, size_t length) { if(num != 0) { // process left over data if(num + length >= block_size) { std::memcpy(buffer + num, data, block_size - num); - hash(buffer, block_size); + hash(state, buffer, block_size); data += (block_size - num); length -= (block_size - num); // drop through and do the rest @@ -103,7 +115,7 @@ void iterated_hash::update(const char * data, size_t length) { // now process the input data in blocks of BlockSize bytes and save the leftovers to m_data if(length >= block_size) { - size_t left_over = hash(data, length); + size_t left_over = hash(state, data, length); data += (length - left_over); length = left_over; } @@ -114,7 +126,7 @@ void iterated_hash::update(const char * data, size_t length) { } template -size_t iterated_hash::hash(const char * input, size_t length) { +size_t iterated_hash::hash(hash_word state[hash_size], const char * input, size_t length) { if(byte_order::native() && util::is_aligned(input)) { @@ -157,7 +169,7 @@ void iterated_hash::pad(size_t last_block_size, char pad_first) { memset(buffer + num, 0, last_block_size - num); } else { memset(buffer + num, 0, block_size - num); - hash(buffer, block_size); + hash(state, buffer, block_size); memset(buffer, 0, last_block_size); } } @@ -172,7 +184,7 @@ void iterated_hash::finalize(char * result) { byte_order::store(bit_count_lo(), buffer + size + order); byte_order::store(bit_count_hi(), buffer + size + sizeof(hash_word) - order); - hash(buffer, block_size); + hash(state, buffer, block_size); byte_order::store(state, hash_size, result); From 5545a515eadd206bf9afdb42b39f65f360a94c82 Mon Sep 17 00:00:00 2001 From: Daniel Scharrer <~@ds.me> Date: Wed, 1 Jan 2025 18:49:16 +0100 Subject: [PATCH 2/3] pbkdf2: Reuse common hash state between iterations --- src/crypto/pbkdf2.hpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/crypto/pbkdf2.hpp b/src/crypto/pbkdf2.hpp index 653d8654..d1bf28b6 100644 --- a/src/crypto/pbkdf2.hpp +++ b/src/crypto/pbkdf2.hpp @@ -43,36 +43,35 @@ namespace crypto { template struct hmac { + typedef typename T::state_t state_t; enum constants { block_size = T::block_size, hash_size = T::hash_size * sizeof(typename T::hash_word), }; - void init(const char ikey[block_size]) { - inner.init(); - inner.update(ikey, block_size); + void init(const state_t istate) { + inner.init(istate, 1); } void update(const char * data, size_t length) { inner.update(data, length); } - void finalize(const char okey[block_size], char mac[hash_size]) { + void finalize(const state_t ostate, char mac[hash_size]) { char buffer[hash_size]; inner.finalize(buffer); T outer; - outer.init(); - outer.update(okey, block_size); + outer.init(ostate, 1); outer.update(buffer, hash_size); outer.finalize(mac); } - static void prepare_key(const char * password, size_t length, - char ikey[block_size], char okey[block_size]) { + static void prepare_state(const char * password, size_t length, state_t istate, state_t ostate) { + char ikey[block_size], okey[block_size]; if(length > block_size) { T hash; hash.init(); @@ -89,6 +88,9 @@ struct hmac { ikey[i] = char(boost::uint8_t(ikey[i]) ^ boost::uint8_t(0x36)); } + T::prepare_state(ikey, 1, istate); + T::prepare_state(okey, 1, ostate); + } private: @@ -110,8 +112,8 @@ struct pbkdf2 { static void derive(const char * password, size_t password_length, const char * salt, size_t salt_length, size_t iterations, char * key, size_t key_length) { - char ikey[block_size], okey[block_size]; - hmac_t::prepare_key(password, password_length, ikey, okey); + typename hmac_t::state_t istate, ostate; + hmac_t::prepare_state(password, password_length, istate, ostate); for(size_t block = 1; key_length > 0; block++) { @@ -119,19 +121,19 @@ struct pbkdf2 { { char b[4] = { char(block >> 24), char(block >> 16), char(block >> 8), char(block) }; hmac_t mac; - mac.init(ikey); + mac.init(istate); mac.update(salt, salt_length); mac.update(b, sizeof(b)); - mac.finalize(okey, u); + mac.finalize(ostate, u); } char f[hash_size]; std::memcpy(f, u, hash_size); for(size_t i = 1; i < iterations; i++) { hmac_t mac; - mac.init(ikey); + mac.init(istate); mac.update(u, hash_size); - mac.finalize(okey, u); + mac.finalize(ostate, u); for(size_t j = 0; j < hash_size; j++) { f[j] = char(boost::uint8_t(f[j]) ^ boost::uint8_t(u[j])); } From 102de3e406a43cc2bc3dd0b1e9b94c78db65547a Mon Sep 17 00:00:00 2001 From: Daniel Scharrer <~@ds.me> Date: Wed, 1 Jan 2025 20:42:34 +0100 Subject: [PATCH 3/3] xchacha20: Fix derive_subkey on big endian platforms --- src/crypto/xchacha20.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/crypto/xchacha20.cpp b/src/crypto/xchacha20.cpp index fae4fe37..632cfe06 100644 --- a/src/crypto/xchacha20.cpp +++ b/src/crypto/xchacha20.cpp @@ -103,8 +103,14 @@ void xchacha20::derive_subkey(const char key[key_size], const char nonce[16], ch state[14] = util::little_endian::load(nonce + 8); state[15] = util::little_endian::load(nonce + 12); run_rounds(state); - std::memcpy(subkey, state, 16); - std::memcpy(subkey + 16, state + 12, 16); + util::little_endian::store(state[0], subkey); + util::little_endian::store(state[1], subkey + 4); + util::little_endian::store(state[2], subkey + 8); + util::little_endian::store(state[3], subkey + 12); + util::little_endian::store(state[12], subkey + 16); + util::little_endian::store(state[13], subkey + 20); + util::little_endian::store(state[14], subkey + 24); + util::little_endian::store(state[15], subkey + 28); }