aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/mac/gmac/gmac.cpp
diff options
context:
space:
mode:
authorMatthias Gierlings <[email protected]>2016-10-27 19:00:23 +0200
committerMatthias Gierlings <[email protected]>2016-10-28 10:49:38 +0200
commit9ad816a5d8d74105558640b2f37baec50d8b920f (patch)
tree8400746b4ce9915244c91aa4dcaa1cfb05b508ff /src/lib/mac/gmac/gmac.cpp
parent425a2c2497387b7b5804738a77c757b93e630322 (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/gmac/gmac.cpp')
-rw-r--r--src/lib/mac/gmac/gmac.cpp107
1 files changed, 77 insertions, 30 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());
}
}