// siphash.h - written and placed in public domain by Jeffrey Walton. /// \file siphash.h /// \brief Classes for SipHash message authentication code /// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length /// message and 128-bit secret key. It was designed to be efficient even for short inputs, with /// performance comparable to non-cryptographic hash functions. /// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. ///
  SecByteBlock key(16);
///   prng.GenerateBlock(key, key.size());
///
///   SipHash<2,4,false> hash(key, key.size());
///   hash.Update(...);
///   hash.Final(...);
/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. ///
  SecByteBlock key(16);
///   prng.GenerateBlock(key, key.size());
///
///   SipHash<2,4,true> hash(key, key.size());
///   hash.Update(...);
///   hash.Final(...);
/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: /// a fast short-input PRF /// \since Crypto++ 6.0 #ifndef CRYPTOPP_SIPHASH_H #define CRYPTOPP_SIPHASH_H #include "cryptlib.h" #include "secblock.h" #include "misc.h" NAMESPACE_BEGIN(CryptoPP) /// \brief SipHash message authentication code information /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size template class SipHash_Info : public FixedKeyLength<16> { public: CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SipHash";} CRYPTOPP_CONSTANT(DIGESTSIZE = (T_128bit ? 16 : 8)) }; /// \brief SipHash message authentication code base class /// \tparam C the number of compression rounds /// \tparam D the number of finalization rounds /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size template class SipHash_Base : public MessageAuthenticationCode, public SipHash_Info { public: static std::string StaticAlgorithmName() { return std::string(SipHash_Info::StaticAlgorithmName())+"-"+IntToString(C)+"-"+IntToString(D); } virtual ~SipHash_Base() {} SipHash_Base() : m_idx(0) {} virtual unsigned int DigestSize() const {return SipHash_Info::DIGESTSIZE;} virtual size_t MinKeyLength() const {return SipHash_Info::MIN_KEYLENGTH;} virtual size_t MaxKeyLength() const {return SipHash_Info::MAX_KEYLENGTH;} virtual size_t DefaultKeyLength() const {return SipHash_Info::DEFAULT_KEYLENGTH;} virtual size_t GetValidKeyLength(size_t keylength) const {CRYPTOPP_UNUSED(keylength); return SipHash_Info::DEFAULT_KEYLENGTH;} virtual IV_Requirement IVRequirement() const {return SimpleKeyingInterface::NOT_RESYNCHRONIZABLE;} virtual unsigned int IVSize() const {return 0;} virtual unsigned int OptimalBlockSize() const {return sizeof(word64);} virtual unsigned int OptimalDataAlignment () const {return GetAlignmentOf();} virtual void Update(const byte *input, size_t length); virtual void TruncatedFinal(byte *digest, size_t digestSize); protected: virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms); virtual void Restart(); inline void SIPROUND() { m_v[0] += m_v[1]; m_v[1] = rotlConstant<13>(m_v[1]); m_v[1] ^= m_v[0]; m_v[0] = rotlConstant<32>(m_v[0]); m_v[2] += m_v[3]; m_v[3] = rotlConstant<16>(m_v[3]); m_v[3] ^= m_v[2]; m_v[0] += m_v[3]; m_v[3] = rotlConstant<21>(m_v[3]); m_v[3] ^= m_v[0]; m_v[2] += m_v[1]; m_v[1] = rotlConstant<17>(m_v[1]); m_v[1] ^= m_v[2]; m_v[2] = rotlConstant<32>(m_v[2]); } private: FixedSizeSecBlock m_v; FixedSizeSecBlock m_k; FixedSizeSecBlock m_b; // Tail bytes FixedSizeSecBlock m_acc; size_t m_idx; }; /// \brief SipHash message authentication code /// \tparam C the number of compression rounds /// \tparam D the number of finalization rounds /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size /// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length /// message and 128-bit secret key. It was designed to be efficient even for short inputs, with /// performance comparable to non-cryptographic hash functions. /// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following. ///
  SecByteBlock key(16);
///   prng.GenerateBlock(key, key.size());
///
///   SipHash<2,4,false> hash(key, key.size());
///   hash.Update(...);
///   hash.Final(...);
/// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following. ///
  SecByteBlock key(16);
///   prng.GenerateBlock(key, key.size());
///
///   SipHash<2,4,true> hash(key, key.size());
///   hash.Update(...);
///   hash.Final(...);
/// \sa Jean-Philippe Aumasson and Daniel J. Bernstein SipHash: /// a fast short-input PRF /// \since Crypto++ 6.0 template class SipHash : public SipHash_Base { public: /// \brief Create a SipHash SipHash() {this->UncheckedSetKey(NULLPTR, 0, g_nullNameValuePairs);} /// \brief Create a SipHash /// \param key a byte array used to key the cipher /// \param length the size of the byte array, in bytes SipHash(const byte *key, unsigned int length) {this->UncheckedSetKey(key, length, g_nullNameValuePairs);} }; template void SipHash_Base::Update(const byte *input, size_t length) { CRYPTOPP_ASSERT((input && length) || !length); if (!length) return; if (m_idx) { size_t head = STDMIN(size_t(8U-m_idx), length); memcpy(m_acc+m_idx, input, head); m_idx += head; input += head; length -= head; if (m_idx == 8) { word64 m = GetWord(true, LITTLE_ENDIAN_ORDER, m_acc); m_v[3] ^= m; for (unsigned int i = 0; i < C; ++i) SIPROUND(); m_v[0] ^= m; m_b[0] += 8; m_idx = 0; } } while (length >= 8) { word64 m = GetWord(false, LITTLE_ENDIAN_ORDER, input); m_v[3] ^= m; for (unsigned int i = 0; i < C; ++i) SIPROUND(); m_v[0] ^= m; m_b[0] += 8; input += 8; length -= 8; } CRYPTOPP_ASSERT(length < 8); size_t tail = length % 8; if (tail) { memcpy(m_acc+m_idx, input, tail); m_idx += tail; } } template void SipHash_Base::TruncatedFinal(byte *digest, size_t digestSize) { CRYPTOPP_ASSERT(digest); // Pointer is valid ThrowIfInvalidTruncatedSize(digestSize); // The high octet holds length and is digested mod 256 m_b[0] += m_idx; m_b[0] <<= 56U; switch (m_idx) { case 7: m_b[0] |= ((word64)m_acc[6]) << 48; // fall through case 6: m_b[0] |= ((word64)m_acc[5]) << 40; // fall through case 5: m_b[0] |= ((word64)m_acc[4]) << 32; // fall through case 4: m_b[0] |= ((word64)m_acc[3]) << 24; // fall through case 3: m_b[0] |= ((word64)m_acc[2]) << 16; // fall through case 2: m_b[0] |= ((word64)m_acc[1]) << 8; // fall through case 1: m_b[0] |= ((word64)m_acc[0]); // fall through case 0: break; } m_v[3] ^= m_b[0]; for (unsigned int i=0; i::DIGESTSIZE)); Restart(); } template void SipHash_Base::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) { CRYPTOPP_UNUSED(params); if (key && length) { m_k[0] = GetWord(false, LITTLE_ENDIAN_ORDER, key); m_k[1] = GetWord(false, LITTLE_ENDIAN_ORDER, key+8); } else { // Avoid Coverity finding m_k[0] = m_k[1] = 0; } Restart(); } template void SipHash_Base::Restart () { m_v[0] = W64LIT(0x736f6d6570736575); m_v[1] = W64LIT(0x646f72616e646f6d); m_v[2] = W64LIT(0x6c7967656e657261); m_v[3] = W64LIT(0x7465646279746573); m_v[3] ^= m_k[1]; m_v[2] ^= m_k[0]; m_v[1] ^= m_k[1]; m_v[0] ^= m_k[0]; if (T_128bit) { m_v[1] ^= 0xee; } m_idx = 0; m_b[0] = 0; } NAMESPACE_END #endif // CRYPTOPP_SIPHASH_H