diff options
-rw-r--r-- | doc/dev/todo.rst | 1 | ||||
-rw-r--r-- | doc/relnotes/1_11_13.rst | 2 | ||||
-rw-r--r-- | doc/website/algos.rst | 3 | ||||
-rw-r--r-- | src/lib/engine/core_engine/lookup_mac.cpp | 10 | ||||
-rw-r--r-- | src/lib/mac/siphash/info.txt | 1 | ||||
-rw-r--r-- | src/lib/mac/siphash/siphash.cpp | 123 | ||||
-rw-r--r-- | src/lib/mac/siphash/siphash.h | 45 | ||||
-rw-r--r-- | src/tests/data/mac/siphash.vec | 4 | ||||
-rw-r--r-- | src/tests/test_hash.cpp | 20 | ||||
-rw-r--r-- | src/tests/test_mac.cpp | 28 |
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; |