aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/dev/todo.rst1
-rw-r--r--doc/relnotes/1_11_13.rst2
-rw-r--r--doc/website/algos.rst3
-rw-r--r--src/lib/engine/core_engine/lookup_mac.cpp10
-rw-r--r--src/lib/mac/siphash/info.txt1
-rw-r--r--src/lib/mac/siphash/siphash.cpp123
-rw-r--r--src/lib/mac/siphash/siphash.h45
-rw-r--r--src/tests/data/mac/siphash.vec4
-rw-r--r--src/tests/test_hash.cpp20
-rw-r--r--src/tests/test_mac.cpp28
10 files changed, 229 insertions, 8 deletions
diff --git a/doc/dev/todo.rst b/doc/dev/todo.rst
index 870fd294c..42f8690d1 100644
--- a/doc/dev/todo.rst
+++ b/doc/dev/todo.rst
@@ -13,7 +13,6 @@ Basic Algorithms
* scrypt
* BLAKE2
* EdDSA
- * SipHash
* Skein-MAC
* IETF standard HKDF (RFC 5869)
* ARIA (Korean block cipher, RFCs 5794 and 6209)
diff --git a/doc/relnotes/1_11_13.rst b/doc/relnotes/1_11_13.rst
index f617ec3b9..e3d9bced2 100644
--- a/doc/relnotes/1_11_13.rst
+++ b/doc/relnotes/1_11_13.rst
@@ -12,6 +12,8 @@ Version 1.11.13, Not Yet Released
* Add DTLS-SRTP negotiation defined in RFC 5764
+* Add SipHash
+
* Add SHA-512/256
* The format of serialized TLS sessions has changed. Additiionally, PEM
diff --git a/doc/website/algos.rst b/doc/website/algos.rst
index 5184564af..795f718e0 100644
--- a/doc/website/algos.rst
+++ b/doc/website/algos.rst
@@ -57,12 +57,13 @@ Hash functions
* Obsolete or insecure hashes MD5, MD4, MD2
* Non-cryptographic checksums Adler32, CRC24, CRC32
-Authentication Codes
+Authentication Codes and PRFs
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* HMAC
* CMAC (aka OMAC1)
* Poly1305
+ * SipHash
* Obsolete designs CBC-MAC and ANSI X9.19 DES-MAC
Other Useful Things
diff --git a/src/lib/engine/core_engine/lookup_mac.cpp b/src/lib/engine/core_engine/lookup_mac.cpp
index ba5cd69c6..d5e16cf44 100644
--- a/src/lib/engine/core_engine/lookup_mac.cpp
+++ b/src/lib/engine/core_engine/lookup_mac.cpp
@@ -25,6 +25,10 @@
#include <botan/poly1305.h>
#endif
+#if defined(BOTAN_HAS_SIPHASH)
+ #include <botan/siphash.h>
+#endif
+
#if defined(BOTAN_HAS_ANSI_X919_MAC)
#include <botan/x919_mac.h>
#endif
@@ -53,6 +57,12 @@ Core_Engine::find_mac(const SCAN_Name& request,
return new Poly1305;
#endif
+#if defined(BOTAN_HAS_SIPHASH)
+ if(request.algo_name() == "SipHash")
+ return new SipHash(request.arg_as_integer(0, 2),
+ request.arg_as_integer(1, 4));
+#endif
+
#if defined(BOTAN_HAS_CBC_MAC)
if(request.algo_name() == "CBC-MAC" && request.arg_count() == 1)
return new CBC_MAC(af.make_block_cipher(request.arg(0)));
diff --git a/src/lib/mac/siphash/info.txt b/src/lib/mac/siphash/info.txt
new file mode 100644
index 000000000..98c4d0986
--- /dev/null
+++ b/src/lib/mac/siphash/info.txt
@@ -0,0 +1 @@
+define SIPHASH 20150110
diff --git a/src/lib/mac/siphash/siphash.cpp b/src/lib/mac/siphash/siphash.cpp
new file mode 100644
index 000000000..bc242d4ac
--- /dev/null
+++ b/src/lib/mac/siphash/siphash.cpp
@@ -0,0 +1,123 @@
+/*
+* SipHash
+* (C) 2014,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/siphash.h>
+#include <botan/rotate.h>
+#include <botan/loadstor.h>
+#include <botan/internal/xor_buf.h>
+
+namespace Botan {
+
+namespace {
+
+void SipRounds(u64bit M, secure_vector<u64bit>& V, size_t r)
+ {
+ u64bit V0 = V[0], V1 = V[1], V2 = V[2], V3 = V[3];
+
+ V3 ^= M;
+ for(size_t i = 0; i != r; ++i)
+ {
+ V0 += V1; V2 += V3;
+ V1 = rotate_left(V1, 13);
+ V3 = rotate_left(V3, 16);
+ V1 ^= V0; V3 ^= V2;
+ V0 = rotate_left(V0, 32);
+
+ V2 += V1; V0 += V3;
+ V1 = rotate_left(V1, 17);
+ V3 = rotate_left(V3, 21);
+ V1 ^= V2; V3 ^= V0;
+ V2 = rotate_left(V2, 32);
+ }
+ V0 ^= M;
+
+ V[0] = V0; V[1] = V1; V[2] = V2; V[3] = V3;
+ }
+
+}
+
+void SipHash::add_data(const byte input[], size_t length)
+ {
+ m_words += length;
+
+ if(m_mbuf_pos)
+ {
+ while(length && m_mbuf_pos != 8)
+ {
+ m_mbuf = (m_mbuf >> 8) | (static_cast<u64bit>(input[0]) << 56);
+ ++m_mbuf_pos;
+ ++input;
+ length--;
+ }
+
+ if(m_mbuf_pos == 8)
+ {
+ SipRounds(m_mbuf, m_V, m_C);
+ m_mbuf_pos = 0;
+ m_mbuf = 0;
+ }
+ }
+
+ while(length >= 8)
+ {
+ SipRounds(load_le<u64bit>(input, 0), m_V, m_C);
+ input += 8;
+ length -= 8;
+ }
+
+ for(size_t i = 0; i != length; ++i)
+ {
+ m_mbuf = (m_mbuf >> 8) | (static_cast<u64bit>(input[i]) << 56);
+ m_mbuf_pos++;
+ }
+ }
+
+void SipHash::final_result(byte mac[])
+ {
+ m_mbuf = (m_mbuf >> (64-m_mbuf_pos*8)) | (static_cast<u64bit>(m_words) << 56);
+ SipRounds(m_mbuf, m_V, m_C);
+
+ m_V[2] ^= 0xFF;
+ SipRounds(0, m_V, m_D);
+
+ const u64bit X = m_V[0] ^ m_V[1] ^ m_V[2] ^ m_V[3];
+
+ store_le(X, mac);
+
+ m_mbuf = 0;
+ m_mbuf_pos = 0;
+ m_words = 0;
+ }
+
+void SipHash::key_schedule(const byte key[], size_t)
+ {
+ const u64bit K0 = load_le<u64bit>(key, 0);
+ const u64bit K1 = load_le<u64bit>(key, 1);
+
+ m_V.resize(4);
+ m_V[0] = K0 ^ 0x736F6D6570736575;
+ m_V[1] = K1 ^ 0x646F72616E646F6D;
+ m_V[2] = K0 ^ 0x6C7967656E657261;
+ m_V[3] = K1 ^ 0x7465646279746573;
+ }
+
+void SipHash::clear()
+ {
+ m_V.clear();
+ }
+
+std::string SipHash::name() const
+ {
+ return "SipHash(" + std::to_string(m_C) + "," + std::to_string(m_D) + ")";
+ }
+
+MessageAuthenticationCode* SipHash::clone() const
+ {
+ return new SipHash(m_C, m_D);
+ }
+
+}
diff --git a/src/lib/mac/siphash/siphash.h b/src/lib/mac/siphash/siphash.h
new file mode 100644
index 000000000..ec57864eb
--- /dev/null
+++ b/src/lib/mac/siphash/siphash.h
@@ -0,0 +1,45 @@
+/*
+* SipHash
+* (C) 2014,2015 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_SIPHASH_H__
+#define BOTAN_SIPHASH_H__
+
+#include <botan/mac.h>
+
+namespace Botan {
+
+class BOTAN_DLL SipHash : public MessageAuthenticationCode
+ {
+ public:
+ SipHash(size_t c = 2, size_t d = 4) : m_C(c), m_D(d) {}
+
+ void clear();
+ std::string name() const;
+
+ MessageAuthenticationCode* clone() const;
+
+ size_t output_length() const { return 8; }
+
+ Key_Length_Specification key_spec() const
+ {
+ return Key_Length_Specification(16);
+ }
+ private:
+ void add_data(const byte[], size_t);
+ void final_result(byte[]);
+ void key_schedule(const byte[], size_t);
+
+ const size_t m_C, m_D;
+ secure_vector<u64bit> m_V;
+ u64bit m_mbuf = 0;
+ size_t m_mbuf_pos = 0;
+ byte m_words = 0;
+ };
+
+}
+
+#endif
diff --git a/src/tests/data/mac/siphash.vec b/src/tests/data/mac/siphash.vec
new file mode 100644
index 000000000..7e4bfed04
--- /dev/null
+++ b/src/tests/data/mac/siphash.vec
@@ -0,0 +1,4 @@
+[SipHash(2,4)]
+Key = 000102030405060708090A0B0C0D0E0F
+In = 000102030405060708090A0B0C0D0E
+Out = E545BE4961CA29A1
diff --git a/src/tests/test_hash.cpp b/src/tests/test_hash.cpp
index 242988c80..fb8d54e1f 100644
--- a/src/tests/test_hash.cpp
+++ b/src/tests/test_hash.cpp
@@ -42,9 +42,11 @@ size_t hash_test(const std::string& algo,
continue;
}
+ const std::vector<byte> in = hex_decode(in_hex);
+
std::unique_ptr<HashFunction> hash(proto->clone());
- hash->update(hex_decode(in_hex));
+ hash->update(in);
auto h = hash->final();
@@ -58,7 +60,7 @@ size_t hash_test(const std::string& algo,
hash->update("some discarded input");
hash->clear();
- hash->update(hex_decode(in_hex));
+ hash->update(in);
h = hash->final();
@@ -68,6 +70,20 @@ size_t hash_test(const std::string& algo,
<< " (with discarded input)\n";
++fails;
}
+
+ if(in.size() > 1)
+ {
+ hash->update(in[0]);
+ hash->update(&in[1], in.size() - 1);
+ h = hash->final();
+
+ if(h != hex_decode_locked(out_hex))
+ {
+ std::cout << algo << " " << provider << " got " << hex_encode(h) << " != " << out_hex
+ << " (with offset input)\n";
+ ++fails;
+ }
+ }
}
return fails;
diff --git a/src/tests/test_mac.cpp b/src/tests/test_mac.cpp
index 45092d4f3..8be57afbe 100644
--- a/src/tests/test_mac.cpp
+++ b/src/tests/test_mac.cpp
@@ -45,16 +45,36 @@ size_t mac_test(const std::string& algo,
std::unique_ptr<MessageAuthenticationCode> mac(proto->clone());
+ const std::vector<byte> in = hex_decode(in_hex);
+ const std::vector<byte> exp = hex_decode(out_hex);
+
mac->set_key(hex_decode(key_hex));
- mac->update(hex_decode(in_hex));
- auto h = mac->final();
+ mac->update(in);
+
+ const std::vector<byte> out = unlock(mac->final());
- if(h != hex_decode_locked(out_hex))
+ if(out != exp)
{
- std::cout << algo << " " << provider << " got " << hex_encode(h) << " != " << out_hex << "\n";
+ std::cout << algo << " " << provider << " got " << hex_encode(out) << " != " << hex_encode(exp) << "\n";
++fails;
}
+
+ if(in.size() > 2)
+ {
+ mac->set_key(hex_decode(key_hex));
+ mac->update(in[0]);
+ mac->update(&in[1], in.size() - 2);
+ mac->update(in[in.size()-1]);
+
+ const std::vector<byte> out2 = unlock(mac->final());
+
+ if(out2 != exp)
+ {
+ std::cout << algo << " " << provider << " got " << hex_encode(out2) << " != " << hex_encode(exp) << "\n";
+ ++fails;
+ }
+ }
}
return fails;