diff options
author | Matthias Gierlings <[email protected]> | 2016-10-27 19:00:23 +0200 |
---|---|---|
committer | Matthias Gierlings <[email protected]> | 2016-10-28 10:49:38 +0200 |
commit | 9ad816a5d8d74105558640b2f37baec50d8b920f (patch) | |
tree | 8400746b4ce9915244c91aa4dcaa1cfb05b508ff /src/lib/mac | |
parent | 425a2c2497387b7b5804738a77c757b93e630322 (diff) |
Implements GMAC with GHASH.
Adds support for Galois Message Authentication Code calculation based on
GHASH, rather than GCM_Mode.
Diffstat (limited to 'src/lib/mac')
-rw-r--r-- | src/lib/mac/gmac/gmac.cpp | 107 | ||||
-rw-r--r-- | src/lib/mac/gmac/gmac.h | 35 | ||||
-rw-r--r-- | src/lib/mac/mac.cpp | 11 |
3 files changed, 109 insertions, 44 deletions
diff --git a/src/lib/mac/gmac/gmac.cpp b/src/lib/mac/gmac/gmac.cpp index 5d82456ae..946e22cf0 100644 --- a/src/lib/mac/gmac/gmac.cpp +++ b/src/lib/mac/gmac/gmac.cpp @@ -9,27 +9,22 @@ namespace Botan { -GMAC* GMAC::make(const Spec& spec) - { - if(spec.arg_count() == 1) - { - if(auto bc = BlockCipher::create(spec.arg(0))) - return new GMAC(bc.release()); - } - return nullptr; - } - GMAC::GMAC(BlockCipher* cipher) - : m_iv(), m_aad(), - m_gcm(GCM_Encryption(cipher)), m_cipher(cipher->clone()) - { - } + : GHASH(), + m_aad_buf(), + m_cipher(cipher), + m_initialized(false) + {} void GMAC::clear() { - m_gcm.clear(); - zeroise(m_iv); - zeroise(m_aad); + GHASH::clear(); + m_H.resize(GCM_BS); + m_H_ad.resize(GCM_BS); + m_ghash.resize(GCM_BS); + m_cipher->clear(); + m_aad_buf.clear(); + m_initialized = false; } std::string GMAC::name() const @@ -39,38 +34,90 @@ std::string GMAC::name() const size_t GMAC::output_length() const { - return m_gcm.tag_size(); + return GCM_BS; + } + +void GMAC::add_data(const byte input[], size_t size) + { + m_ad_len += size; + + // buffer partial blocks till we received a full input block + // or final is called. + m_aad_buf.insert(m_aad_buf.end(), input, input + size); + if(m_aad_buf.size() >= GCM_BS) + { + // process all complete input blocks. + ghash_update(m_ghash, + m_aad_buf.data(), + m_aad_buf.size() - (m_aad_buf.size() % GCM_BS)); + + // remove all processed blocks from buffer. + m_aad_buf.erase(m_aad_buf.begin(), + m_aad_buf.end() - (m_aad_buf.size() % GCM_BS)); + } } -void GMAC::add_data(const byte input[], size_t length) +void GMAC::key_schedule(const byte key[], size_t size) { - m_aad.insert(m_aad.end(), input, input + length); + clear(); + m_cipher->set_key(key, size); + m_cipher->encrypt(m_H_ad.data(), m_H.data()); } void GMAC::start(const std::vector<byte>& nonce) { - m_iv.assign(nonce.begin(), nonce.end()); + start(nonce.data(), nonce.size()); } void GMAC::start(const secure_vector<byte>& nonce) { - m_iv.assign(nonce.begin(), nonce.end()); + start(nonce.data(), nonce.size()); + } + +void GMAC::start(const byte nonce[], size_t nonce_len) + { + secure_vector<byte> y0(GCM_BS); + + if(nonce_len == 12) + { + copy_mem(y0.data(), nonce, nonce_len); + y0[GCM_BS - 1] = 1; + } + else + { + ghash_update(y0, nonce, nonce_len); + add_final_block(y0, 0, nonce_len); + } + + secure_vector<byte> m_enc_y0(GCM_BS); + m_cipher->encrypt(y0.data(), m_enc_y0.data()); + GHASH::start(m_enc_y0.data(), m_enc_y0.size()); + m_initialized = true; } void GMAC::final_result(byte mac[]) { - secure_vector<byte> result; - m_gcm.set_associated_data(m_aad.data(), m_aad.size()); - m_gcm.start(m_iv); - m_gcm.finish(result); + // This ensures the GMAC computation has been initialized with a fresh + // nonce. The aim of this check is to prevent developers from re-using + // nonces (and potential nonce-reuse attacks). + BOTAN_ASSERT(m_initialized, + "The GMAC computation has not been initialized with a fresh " + "nonce."); + // process the rest of the aad buffer. Even if it is a partial block only + // ghash_update will process it properly. + if(m_aad_buf.size() > 0) + { + ghash_update(m_ghash, + m_aad_buf.data(), + m_aad_buf.size()); + } + secure_vector<byte> result = GHASH::final(); std::copy(result.begin(), result.end(), mac); - - zeroise(m_aad); - m_aad.clear(); + clear(); } MessageAuthenticationCode* GMAC::clone() const { - return new GMAC(m_cipher->clone()); + return new GMAC(BlockCipher::create(m_cipher->name()).release()); } } diff --git a/src/lib/mac/gmac/gmac.h b/src/lib/mac/gmac/gmac.h index d83236b32..b651c2e11 100644 --- a/src/lib/mac/gmac/gmac.h +++ b/src/lib/mac/gmac/gmac.h @@ -8,9 +8,9 @@ #ifndef BOTAN_GMAC_H__ #define BOTAN_GMAC_H__ -#include <botan/types.h> -#include <botan/mac.h> #include <botan/gcm.h> +#include <botan/mac.h> +#include <botan/types.h> #include <algorithm> namespace Botan { @@ -18,7 +18,9 @@ namespace Botan { /** * GMAC */ -class BOTAN_DLL GMAC : public MessageAuthenticationCode +class BOTAN_DLL GMAC : public MessageAuthenticationCode, + public GHASH + { public: void clear() override; @@ -31,6 +33,15 @@ class BOTAN_DLL GMAC : public MessageAuthenticationCode * calculation. * * @param nonce Initialization vector. + * @param nonce_len size of initialization vector. + */ + void start(const byte nonce[], size_t nonce_len); + + /** + * Must be called to set the initialization vector prior to GMAC + * calculation. + * + * @param nonce Initialization vector. */ void start(const secure_vector<byte>& nonce); @@ -44,7 +55,7 @@ class BOTAN_DLL GMAC : public MessageAuthenticationCode Key_Length_Specification key_spec() const { - return m_gcm.key_spec(); + return m_cipher->key_spec(); } /** @@ -54,23 +65,19 @@ class BOTAN_DLL GMAC : public MessageAuthenticationCode */ explicit GMAC(BlockCipher* cipher); - static GMAC* make(const Spec& spec); - GMAC(const GMAC&) = delete; GMAC& operator=(const GMAC&) = delete; + private: void add_data(const byte[], size_t) override; void final_result(byte[]) override; + void start_msg(const byte nonce[], size_t nonce_len); + void key_schedule(const byte key[], size_t size) override; - void key_schedule(const byte key[], size_t size) override - { - m_gcm.set_key(key, size); - } - - secure_vector<byte> m_iv; - secure_vector<byte> m_aad; - GCM_Encryption m_gcm; + static const size_t GCM_BS = 16; + secure_vector<byte> m_aad_buf; std::unique_ptr<BlockCipher> m_cipher; + bool m_initialized; }; } diff --git a/src/lib/mac/mac.cpp b/src/lib/mac/mac.cpp index f2c5557c7..2fa321a67 100644 --- a/src/lib/mac/mac.cpp +++ b/src/lib/mac/mac.cpp @@ -45,6 +45,17 @@ MessageAuthenticationCode::create(const std::string& algo_spec, { const SCAN_Name req(algo_spec); +#if defined(BOTAN_HAS_GMAC) + if(req.algo_name() == "GMAC" && req.arg_count() == 1) + { + if(provider.empty() || provider == "base") + { + if(auto bc = BlockCipher::create(req.arg(0))) + return std::unique_ptr<MessageAuthenticationCode>(new GMAC(bc.release())); + } + } +#endif + #if defined(BOTAN_HAS_HMAC) if(req.algo_name() == "HMAC" && req.arg_count() == 1) { |