aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Gierlings <[email protected]>2016-02-03 22:38:41 +0100
committerMatthias Gierlings <[email protected]>2016-10-27 19:42:32 +0200
commit425a2c2497387b7b5804738a77c757b93e630322 (patch)
treedfe9d327cfcf1bfe3a628b8f007200ff18083daf
parent1b9d13aed71152d61fab7e0ba016d1951909bac5 (diff)
Added implementation for GMAC
- Added GMAC class - Integrated GMAC into MAC-Class test bench. Run GMAC tests using ./botan-test mac
-rw-r--r--src/lib/mac/gmac/gmac.cpp76
-rw-r--r--src/lib/mac/gmac/gmac.h77
-rw-r--r--src/lib/mac/gmac/info.txt6
-rw-r--r--src/lib/mac/mac.cpp4
-rw-r--r--src/lib/mac/mac.h22
-rw-r--r--src/lib/modes/aead/gcm/gcm.cpp4
-rw-r--r--src/lib/modes/aead/gcm/gcm.h99
-rw-r--r--src/tests/data/mac/gmac.vec80
-rw-r--r--src/tests/test_mac.cpp22
9 files changed, 332 insertions, 58 deletions
diff --git a/src/lib/mac/gmac/gmac.cpp b/src/lib/mac/gmac/gmac.cpp
new file mode 100644
index 000000000..5d82456ae
--- /dev/null
+++ b/src/lib/mac/gmac/gmac.cpp
@@ -0,0 +1,76 @@
+/*
+ * GMAC
+ * (C) 2016 Matthias Gierlings, René Korthaus
+ *
+ * Botan is released under the Simplified BSD License (see license.txt)
+ */
+
+#include <botan/gmac.h>
+
+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())
+ {
+ }
+
+void GMAC::clear()
+ {
+ m_gcm.clear();
+ zeroise(m_iv);
+ zeroise(m_aad);
+ }
+
+std::string GMAC::name() const
+ {
+ return "GMAC(" + m_cipher->name() + ")";
+ }
+
+size_t GMAC::output_length() const
+ {
+ return m_gcm.tag_size();
+ }
+
+void GMAC::add_data(const byte input[], size_t length)
+ {
+ m_aad.insert(m_aad.end(), input, input + length);
+ }
+
+void GMAC::start(const std::vector<byte>& nonce)
+ {
+ m_iv.assign(nonce.begin(), nonce.end());
+ }
+
+void GMAC::start(const secure_vector<byte>& nonce)
+ {
+ m_iv.assign(nonce.begin(), nonce.end());
+ }
+
+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);
+ std::copy(result.begin(), result.end(), mac);
+
+ zeroise(m_aad);
+ m_aad.clear();
+ }
+
+MessageAuthenticationCode* GMAC::clone() const
+ {
+ return new GMAC(m_cipher->clone());
+ }
+}
diff --git a/src/lib/mac/gmac/gmac.h b/src/lib/mac/gmac/gmac.h
new file mode 100644
index 000000000..d83236b32
--- /dev/null
+++ b/src/lib/mac/gmac/gmac.h
@@ -0,0 +1,77 @@
+/*
+ * GMAC
+ * (C) 2016 Matthias Gierlings, René Korthaus
+ *
+ * Botan is released under the Simplified BSD License (see license.txt)
+ */
+
+#ifndef BOTAN_GMAC_H__
+#define BOTAN_GMAC_H__
+
+#include <botan/types.h>
+#include <botan/mac.h>
+#include <botan/gcm.h>
+#include <algorithm>
+
+namespace Botan {
+
+/**
+* GMAC
+*/
+class BOTAN_DLL GMAC : public MessageAuthenticationCode
+ {
+ public:
+ void clear() override;
+ std::string name() const override;
+ size_t output_length() const override;
+ MessageAuthenticationCode* clone() const override;
+
+ /**
+ * Must be called to set the initialization vector prior to GMAC
+ * calculation.
+ *
+ * @param nonce Initialization vector.
+ */
+ void start(const secure_vector<byte>& nonce);
+
+ /**
+ * Must be called to set the initialization vector prior to GMAC
+ * calculation.
+ *
+ * @param nonce Initialization vector.
+ */
+ void start(const std::vector<byte>& nonce);
+
+ Key_Length_Specification key_spec() const
+ {
+ return m_gcm.key_spec();
+ }
+
+ /**
+ * Creates a new GMAC instance.
+ *
+ * @param cipher the underlying block cipher to use
+ */
+ 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 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;
+ std::unique_ptr<BlockCipher> m_cipher;
+ };
+
+}
+#endif
diff --git a/src/lib/mac/gmac/info.txt b/src/lib/mac/gmac/info.txt
new file mode 100644
index 000000000..921690c93
--- /dev/null
+++ b/src/lib/mac/gmac/info.txt
@@ -0,0 +1,6 @@
+define GMAC 20160207
+
+<requires>
+gcm
+mac
+</requires>
diff --git a/src/lib/mac/mac.cpp b/src/lib/mac/mac.cpp
index 70807b39f..f2c5557c7 100644
--- a/src/lib/mac/mac.cpp
+++ b/src/lib/mac/mac.cpp
@@ -17,6 +17,10 @@
#include <botan/cmac.h>
#endif
+#if defined(BOTAN_HAS_GMAC)
+ #include <botan/gmac.h>
+#endif
+
#if defined(BOTAN_HAS_HMAC)
#include <botan/hmac.h>
#endif
diff --git a/src/lib/mac/mac.h b/src/lib/mac/mac.h
index f3befc512..9c3614f33 100644
--- a/src/lib/mac/mac.h
+++ b/src/lib/mac/mac.h
@@ -59,7 +59,27 @@ class BOTAN_DLL MessageAuthenticationCode : public Buffered_Computation,
virtual bool verify_mac(const byte in[], size_t length);
/**
- * @return a new object representing the same algorithm as *this
+ * Verify a MAC.
+ * @param in the MAC to verify as a byte array
+ * @return true if the MAC is valid, false otherwise
+ */
+ virtual bool verify_mac(const std::vector<byte>& in)
+ {
+ return verify_mac(in.data(), in.size());
+ }
+
+ /**
+ * Verify a MAC.
+ * @param in the MAC to verify as a byte array
+ * @return true if the MAC is valid, false otherwise
+ */
+ virtual bool verify_mac(const secure_vector<byte>& in)
+ {
+ return verify_mac(in.data(), in.size());
+ }
+
+ /**
+ * Get a new object representing the same algorithm as *this
*/
virtual MessageAuthenticationCode* clone() const = 0;
diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp
index a73e5ee5b..6e1bd82f7 100644
--- a/src/lib/modes/aead/gcm/gcm.cpp
+++ b/src/lib/modes/aead/gcm/gcm.cpp
@@ -93,9 +93,9 @@ void GHASH::key_schedule(const byte key[], size_t length)
m_text_len = 0;
}
-void GHASH::start(const byte nonce[], size_t len)
+void GHASH::start(const secure_vector<byte>& nonce)
{
- m_nonce.assign(nonce, nonce + len);
+ m_nonce = nonce;
m_ghash = m_H_ad;
}
diff --git a/src/lib/modes/aead/gcm/gcm.h b/src/lib/modes/aead/gcm/gcm.h
index 6902bc1fa..964bd5062 100644
--- a/src/lib/modes/aead/gcm/gcm.h
+++ b/src/lib/modes/aead/gcm/gcm.h
@@ -14,7 +14,52 @@
namespace Botan {
-class GHASH;
+/**
+* GCM's GHASH
+* Maybe a Transform?
+*/
+class BOTAN_DLL GHASH : public SymmetricAlgorithm
+ {
+ public:
+ void set_associated_data(const byte ad[], size_t ad_len);
+
+ secure_vector<byte> nonce_hash(const byte nonce[], size_t len);
+
+ void start(const secure_vector<byte>& nonce);
+
+ /*
+ * Assumes input len is multiple of 16
+ */
+ void update(const byte in[], size_t len);
+
+ secure_vector<byte> final();
+
+ Key_Length_Specification key_spec() const override
+ { return Key_Length_Specification(16); }
+
+ size_t input_size() const { return m_text_len; }
+
+ void clear() override;
+
+ std::string name() const override { return "GHASH"; }
+ private:
+ void key_schedule(const byte key[], size_t key_len) override;
+
+ void gcm_multiply(secure_vector<byte>& x) const;
+
+ void ghash_update(secure_vector<byte>& x,
+ const byte input[], size_t input_len);
+
+ void add_final_block(secure_vector<byte>& x,
+ size_t ad_len, size_t pt_len);
+
+ secure_vector<byte> m_H;
+ secure_vector<byte> m_H_ad;
+ secure_vector<byte> m_nonce;
+ secure_vector<byte> m_ghash;
+ size_t m_ad_len = 0, m_text_len = 0;
+ };
+
/**
* GCM Mode
@@ -28,6 +73,8 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode
size_t update_granularity() const override;
+ void update(secure_vector<byte>& blocks, size_t offset = 0) override = 0;
+
Key_Length_Specification key_spec() const override;
// GCM supports arbitrary nonce lengths
@@ -35,6 +82,8 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode
size_t tag_size() const override { return m_tag_size; }
+ size_t input_size() const { return m_ghash->input_size(); }
+
void clear() override;
std::string provider() const override;
@@ -51,7 +100,9 @@ class BOTAN_DLL GCM_Mode : public AEAD_Mode
private:
void start_msg(const byte nonce[], size_t nonce_len) override;
+ private:
void key_schedule(const byte key[], size_t length) override;
+ secure_vector<byte> start_raw(const byte nonce[], size_t nonce_len) override;
};
/**
@@ -102,51 +153,5 @@ class BOTAN_DLL GCM_Decryption final : public GCM_Mode
void finish(secure_vector<byte>& final_block, size_t offset = 0) override;
};
-
-/**
-* GCM's GHASH
-* Maybe a Transform?
-*/
-class BOTAN_DLL GHASH : public SymmetricAlgorithm
- {
- public:
- void set_associated_data(const byte ad[], size_t ad_len);
-
- secure_vector<byte> nonce_hash(const byte nonce[], size_t len);
-
- void start(const byte nonce[], size_t len);
-
- /*
- * Assumes input len is multiple of 16
- */
- void update(const byte in[], size_t len);
-
- secure_vector<byte> final();
-
- Key_Length_Specification key_spec() const override
- { return Key_Length_Specification(16); }
-
- void clear() override;
-
- std::string name() const override { return "GHASH"; }
- private:
- void key_schedule(const byte key[], size_t key_len) override;
-
- void gcm_multiply(secure_vector<byte>& x) const;
-
- void ghash_update(secure_vector<byte>& x,
- const byte input[], size_t input_len);
-
- void add_final_block(secure_vector<byte>& x,
- size_t ad_len, size_t pt_len);
-
- secure_vector<byte> m_H;
- secure_vector<byte> m_H_ad;
- secure_vector<byte> m_nonce;
- secure_vector<byte> m_ghash;
- size_t m_ad_len = 0, m_text_len = 0;
- };
-
}
-
#endif
diff --git a/src/tests/data/mac/gmac.vec b/src/tests/data/mac/gmac.vec
new file mode 100644
index 000000000..47a94d553
--- /dev/null
+++ b/src/tests/data/mac/gmac.vec
@@ -0,0 +1,80 @@
+# Testvectors in this file have been generated using the Bouncy Castle Crypto
+# API version 1.54 (https://www.bouncycastle.org)
+
+[GMAC(AES-128)]
+IV = 000000000000000000000000
+Key = 00000000000000000000000000000000
+In =
+Out = 58E2FCCEFA7E3061367F1D57A4E7455A
+
+IV = 000000000000000000000000
+Key = 00000000000000000000000000000000
+In = 00000000000000000000000000000000
+Out = 21C2EB20CD2214DBDF34C9B82ECB7ED2
+
+IV = FFFFFFFFFFFFFFFFFFFFFFFF
+Key = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+In = 00000000000000000000000000000000
+Out = B19E0699327D423B057C95D258AC3129
+
+IV = 00000000
+Key = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+In = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+Out = 95394A79D3A4E94A419D2EA464005F79
+
+IV = 860490BADBD9D69CB13322C8
+Key = 03E76EBD8695CAAA623817AEDF12A6FE
+In = 06CEBA51C28BBEF65FF07B3E265A8905F950B6763498E2A35275E40B985EA459E3AEA0E7B8701E2EBC5C7FC73657F0FE25C4
+Out = 09A226837D34C6881BB1E4377C29F781
+
+IV = 7F3726E3698857F573877988
+Key = 0679238B9E5FD7AFA8F4D5B3AF08671E
+In = 90B3319E2973E670B392678CA177BB24CF0343D1F8AD0C6A2812C2C7A012D6667BC2F1B74F7F6EBDBE9491AE6AD36FDA0052
+Out = 02972297D35F920876FA42F3BC588D95
+
+IV = 2B4F4D6E9C4AC0778DFE1185
+Key = C592DFFD2C340191E688C78BBCDE9B14
+In = D184E694CE693FA39E3EC026500B771B3C7F51A8F9E9B7DE609A6E34B92A967F26B453AEBD6011421CE21C4C500459997A32
+Out = 6174D3E5298EE97224ABA305196FB34E
+
+[GMAC(AES-192)]
+IV = 000000000000000000000000
+Key = 000000000000000000000000000000000000000000000000
+In =
+Out = CD33B28AC773F74BA00ED1F312572435
+
+IV = 38709F4B067D1714DD63F428
+Key = F3582246D1DD6AE73F855C82B774E94E8143D9F8354A9F66
+In = E924266E9687AF9C8E1E23EBCF80AD90EE072B3FC2B57C020708AED47A5D69DF5748B985D8D78BF48D63A4149C3EF72440CC
+Out = 749EE0A6FEE5DEC22E58C597E1CD047C
+
+IV = A47E708697F2B8D98E7F5CA1
+Key = 890EB916B61FD6101400ED06FECB89C342B95396E635B3D6
+In = E18155FDF859872A7491B847B80C5070A1FE9728E752129D54DBE616B4616FA4697CA45DF7C9292F845AC4CA3EE120701924
+Out = 2A73023EE22E85937CC61C8575E962D4
+
+IV = 80947F9A7FE0AED56AFCE4CD
+Key = 2622E5104C164548437A131BC45BA080E70BEF18AC1B0AAB
+In = 485DDEF269A377AD7B29AD1E2055A08EA01E0DCA4B83F4DF5668C0197EFF6B8B835ED75BB4046813ADBAE0F900811119C5F4
+Out = B36E1D2CECBA1EAEB3C43CC3AAED9C15
+
+[GMAC(AES-256)]
+IV = 000000000000000000000000
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+In =
+Out = 530F8AFBC74536B9A963B4F1C4CB738B
+
+IV = 6A9588E108A7F8A01407476D
+Key = 124A6263F56093DE70CBD45B2F57450B99DB7C068B0E11DA674D267CB739CF4C
+In = F07D4DC8F1D32903DAFCDF1F3CA792AFC325D36D8E82E0EA0F6519AE81F4DF905F3DD78076F02FFE74341EB3E606A8ED6DF0
+Out = 9F82882851DD41F38334C3E5337C80AA
+
+IV = 551D960E1C2FBCB565E00E61
+Key = DB8F74ABDE797BF29215A9D1883E5BCE4B0334A2C7891F82D3DCC106EC026F7B
+In = 6C4399B071B67B9F5495DA20F40D23A8A9FA86D3217D9226C43F7BA5E083C96280D13EA65324131631A2ED573F80568DC47B
+Out = 1A55AC6CB46B8001BAA02BA64FAB7B89
+
+IV = FB09C848E7ECE36527B7FB70
+Key = 0994C9E2A62E30A727BC69AE2DACC8823B00DD2888ECE29C2CB764A38FD30FBB
+In = 4E1F2940DA4E4F5616304E7E398070FD106B32B68A0A47977CD008760F0972B5B519FD91C4AEDE49AC869D0766AF8C1A8309
+Out = FFF8F5311D7A16F78930F319EC3E9F8A
diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp
index 6183e88f7..10236dfff 100644
--- a/src/tests/test_mac.cpp
+++ b/src/tests/test_mac.cpp
@@ -1,5 +1,6 @@
/*
* (C) 2014,2015 Jack Lloyd
+* (C) 2016 René Korthaus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,6 +11,10 @@
#include <botan/mac.h>
#endif
+#if defined(BOTAN_HAS_GMAC)
+ #include <botan/gmac.h>
+#endif
+
namespace Botan_Tests {
namespace {
@@ -20,13 +25,14 @@ class Message_Auth_Tests : public Text_Based_Test
{
public:
Message_Auth_Tests() :
- Text_Based_Test("mac", {"Key", "In", "Out"}) {}
+ Text_Based_Test("mac", {"Key", "In", "Out"}, {"IV"}) {}
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override
{
const std::vector<uint8_t> key = get_req_bin(vars, "Key");
const std::vector<uint8_t> input = get_req_bin(vars, "In");
const std::vector<uint8_t> expected = get_req_bin(vars, "Out");
+ const std::vector<uint8_t> iv = get_opt_bin(vars, "IV");
Test::Result result(algo);
@@ -54,14 +60,14 @@ class Message_Auth_Tests : public Text_Based_Test
result.test_eq(provider, mac->name(), algo);
mac->set_key(key);
- mac->update(input);
-
- result.test_eq(provider, "correct mac", mac->final(), expected);
- // Test to make sure clear() resets what we need it to
- mac->set_key( key );
- mac->update( "some discarded input");
- mac->clear();
+#if defined(BOTAN_HAS_GMAC)
+ // GMAC needs to set an IV
+ if(Botan::GMAC* gmac = dynamic_cast<Botan::GMAC*>(mac.get()))
+ {
+ gmac->start(iv);
+ }
+#endif
// do the same to test verify_mac()
mac->set_key(key);