diff options
Diffstat (limited to 'src/lib/modes/aead/gcm/gcm.cpp')
-rw-r--r-- | src/lib/modes/aead/gcm/gcm.cpp | 216 |
1 files changed, 5 insertions, 211 deletions
diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp index 57272f2ac..dfaffedb7 100644 --- a/src/lib/modes/aead/gcm/gcm.cpp +++ b/src/lib/modes/aead/gcm/gcm.cpp @@ -7,213 +7,12 @@ */ #include <botan/gcm.h> +#include <botan/ghash.h> #include <botan/block_cipher.h> -#include <botan/internal/ct_utils.h> -#include <botan/loadstor.h> #include <botan/ctr.h> -#include <botan/cpuid.h> - -#if defined(BOTAN_HAS_GCM_CLMUL) - #include <botan/internal/clmul.h> -#endif - -#if defined(BOTAN_HAS_GCM_PMULL) - #include <botan/internal/pmull.h> -#endif namespace Botan { -static const size_t GCM_BS = 16; - -void GHASH::gcm_multiply(secure_vector<uint8_t>& x, - const uint8_t input[], - size_t blocks) - { -#if defined(BOTAN_HAS_GCM_CLMUL) - if(CPUID::has_clmul()) - { - return gcm_multiply_clmul(x.data(), m_H.data(), input, blocks); - } -#endif - -#if defined(BOTAN_HAS_GCM_PMULL) - if(CPUID::has_arm_pmull()) - { - return gcm_multiply_pmull(x.data(), m_H.data(), input, blocks); - } -#endif - - CT::poison(x.data(), x.size()); - - // SSE2 might be useful here - - const uint64_t ALL_BITS = 0xFFFFFFFFFFFFFFFF; - - uint64_t X[2] = { - load_be<uint64_t>(x.data(), 0), - load_be<uint64_t>(x.data(), 1) - }; - - for(size_t b = 0; b != blocks; ++b) - { - X[0] ^= load_be<uint64_t>(input, 2*b); - X[1] ^= load_be<uint64_t>(input, 2*b+1); - - uint64_t Z[2] = { 0, 0 }; - - for(size_t i = 0; i != 64; ++i) - { - const uint64_t X0MASK = (ALL_BITS + (X[0] >> 63)) ^ ALL_BITS; - const uint64_t X1MASK = (ALL_BITS + (X[1] >> 63)) ^ ALL_BITS; - - X[0] <<= 1; - X[1] <<= 1; - - Z[0] ^= m_HM[4*i ] & X0MASK; - Z[1] ^= m_HM[4*i+1] & X0MASK; - Z[0] ^= m_HM[4*i+2] & X1MASK; - Z[1] ^= m_HM[4*i+3] & X1MASK; - } - - X[0] = Z[0]; - X[1] = Z[1]; - } - - store_be<uint64_t>(x.data(), X[0], X[1]); - CT::unpoison(x.data(), x.size()); - } - -void GHASH::ghash_update(secure_vector<uint8_t>& ghash, - const uint8_t input[], size_t length) - { - /* - This assumes if less than block size input then we're just on the - final block and should pad with zeros - */ - - const size_t full_blocks = length / GCM_BS; - const size_t final_bytes = length - (full_blocks * GCM_BS); - - if(full_blocks > 0) - { - gcm_multiply(ghash, input, full_blocks); - } - - if(final_bytes) - { - secure_vector<uint8_t> last_block(GCM_BS); - copy_mem(last_block.data(), input + full_blocks * GCM_BS, final_bytes); - gcm_multiply(ghash, last_block.data(), 1); - } - } - -void GHASH::key_schedule(const uint8_t key[], size_t length) - { - m_H.assign(key, key+length); - m_H_ad.resize(GCM_BS); - m_ad_len = 0; - m_text_len = 0; - - uint64_t H0 = load_be<uint64_t>(m_H.data(), 0); - uint64_t H1 = load_be<uint64_t>(m_H.data(), 1); - - const uint64_t R = 0xE100000000000000; - - m_HM.resize(256); - - // precompute the multiples of H - for(size_t i = 0; i != 2; ++i) - { - for(size_t j = 0; j != 64; ++j) - { - /* - we interleave H^1, H^65, H^2, H^66, ... - to make indexing nicer in the multiplication code - */ - m_HM[4*j+2*i] = H0; - m_HM[4*j+2*i+1] = H1; - - // GCM's bit ops are reversed so we carry out of the bottom - const uint64_t carry = R * (H1 & 1); - H1 = (H1 >> 1) | (H0 << 63); - H0 = (H0 >> 1) ^ carry; - } - } - } - -void GHASH::start(const uint8_t nonce[], size_t len) - { - m_nonce.assign(nonce, nonce + len); - m_ghash = m_H_ad; - } - -void GHASH::set_associated_data(const uint8_t input[], size_t length) - { - zeroise(m_H_ad); - - ghash_update(m_H_ad, input, length); - m_ad_len = length; - } - -void GHASH::update_associated_data(const uint8_t ad[], size_t length) - { - BOTAN_ASSERT(m_ghash.size() == GCM_BS, "Key was set"); - m_ad_len += length; - ghash_update(m_ghash, ad, length); - } - -void GHASH::update(const uint8_t input[], size_t length) - { - BOTAN_ASSERT(m_ghash.size() == GCM_BS, "Key was set"); - m_text_len += length; - ghash_update(m_ghash, input, length); - } - -void GHASH::add_final_block(secure_vector<uint8_t>& hash, - size_t ad_len, size_t text_len) - { - secure_vector<uint8_t> final_block(GCM_BS); - store_be<uint64_t>(final_block.data(), 8*ad_len, 8*text_len); - ghash_update(hash, final_block.data(), final_block.size()); - } - -secure_vector<uint8_t> GHASH::final() - { - add_final_block(m_ghash, m_ad_len, m_text_len); - - secure_vector<uint8_t> mac; - mac.swap(m_ghash); - - mac ^= m_nonce; - m_text_len = 0; - return mac; - } - -secure_vector<uint8_t> GHASH::nonce_hash(const uint8_t nonce[], size_t nonce_len) - { - BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time"); - secure_vector<uint8_t> y0(GCM_BS); - - ghash_update(y0, nonce, nonce_len); - add_final_block(y0, 0, nonce_len); - - return y0; - } - -void GHASH::clear() - { - zeroise(m_H); - reset(); - } - -void GHASH::reset() - { - zeroise(m_H_ad); - m_ghash.clear(); - m_nonce.clear(); - m_text_len = m_ad_len = 0; - } - /* * GCM_Mode Constructor */ @@ -255,12 +54,7 @@ std::string GCM_Mode::name() const std::string GCM_Mode::provider() const { -#if defined(BOTAN_HAS_GCM_CLMUL) - if(CPUID::has_clmul()) - return "clmul"; -#endif - - return "base"; + return m_ghash->provider(); } size_t GCM_Mode::update_granularity() const @@ -309,10 +103,10 @@ void GCM_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) m_ctr->set_iv(y0.data(), y0.size()); - secure_vector<uint8_t> m_enc_y0(GCM_BS); - m_ctr->encipher(m_enc_y0); + zeroise(y0); + m_ctr->encipher(y0); - m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); + m_ghash->start(y0.data(), y0.size()); } size_t GCM_Encryption::process(uint8_t buf[], size_t sz) |