1 // siphash.h - written and placed in public domain by Jeffrey Walton.
2 
3 /// \file siphash.h
4 /// \brief Classes for SipHash message authentication code
5 /// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length
6 ///   message and 128-bit secret key. It was designed to be efficient even for short inputs, with
7 ///   performance comparable to non-cryptographic hash functions.
8 /// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following.
9 ///   <pre>  SecByteBlock key(16);
10 ///   prng.GenerateBlock(key, key.size());
11 ///
12 ///   SipHash<2,4,false> hash(key, key.size());
13 ///   hash.Update(...);
14 ///   hash.Final(...);</pre>
15 /// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following.
16 ///   <pre>  SecByteBlock key(16);
17 ///   prng.GenerateBlock(key, key.size());
18 ///
19 ///   SipHash<2,4,true> hash(key, key.size());
20 ///   hash.Update(...);
21 ///   hash.Final(...);</pre>
22 /// \sa Jean-Philippe Aumasson and Daniel J. Bernstein <A HREF="http://131002.net/siphash/siphash.pdf">SipHash:
23 ///   a fast short-input PRF</A>
24 /// \since Crypto++ 6.0
25 
26 #ifndef CRYPTOPP_SIPHASH_H
27 #define CRYPTOPP_SIPHASH_H
28 
29 #include "cryptlib.h"
30 #include "secblock.h"
31 #include "misc.h"
32 
NAMESPACE_BEGIN(CryptoPP)33 NAMESPACE_BEGIN(CryptoPP)
34 
35 /// \brief SipHash message authentication code information
36 /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size
37 template <bool T_128bit>
38 class SipHash_Info : public FixedKeyLength<16>
39 {
40 public:
41 	CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SipHash";}
42 	CRYPTOPP_CONSTANT(DIGESTSIZE = (T_128bit ? 16 : 8));
43 };
44 
45 /// \brief SipHash message authentication code base class
46 /// \tparam C the number of compression rounds
47 /// \tparam D the number of finalization rounds
48 /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size
49 template <unsigned int C, unsigned int D, bool T_128bit>
50 class SipHash_Base : public MessageAuthenticationCode, public SipHash_Info<T_128bit>
51 {
52 public:
StaticAlgorithmName()53 	static std::string StaticAlgorithmName() {
54 		return std::string(SipHash_Info<T_128bit>::StaticAlgorithmName())+"-"+IntToString(C)+"-"+IntToString(D);
55 	}
56 
~SipHash_Base()57 	virtual ~SipHash_Base() {}
58 
SipHash_Base()59 	SipHash_Base() : m_idx(0) {}
60 
DigestSize()61 	virtual unsigned int DigestSize() const
62 		{return SipHash_Info<T_128bit>::DIGESTSIZE;}
MinKeyLength()63 	virtual size_t MinKeyLength() const
64 		{return SipHash_Info<T_128bit>::MIN_KEYLENGTH;}
MaxKeyLength()65 	virtual size_t MaxKeyLength() const
66 		{return SipHash_Info<T_128bit>::MAX_KEYLENGTH;}
DefaultKeyLength()67 	virtual size_t DefaultKeyLength() const
68 		{return SipHash_Info<T_128bit>::DEFAULT_KEYLENGTH;}
GetValidKeyLength(size_t keylength)69 	virtual size_t GetValidKeyLength(size_t keylength) const
70 		{CRYPTOPP_UNUSED(keylength); return SipHash_Info<T_128bit>::DEFAULT_KEYLENGTH;}
IVRequirement()71 	virtual IV_Requirement IVRequirement() const
72 		{return SimpleKeyingInterface::NOT_RESYNCHRONIZABLE;}
IVSize()73 	virtual unsigned int IVSize() const
74 		{return 0;}
OptimalBlockSize()75 	virtual unsigned int OptimalBlockSize() const
76 		{return sizeof(word64);}
OptimalDataAlignment()77 	virtual unsigned int OptimalDataAlignment () const
78 		{return GetAlignmentOf<word64>();}
79 
80 	virtual void Update(const byte *input, size_t length);
81 	virtual void TruncatedFinal(byte *digest, size_t digestSize);
82 
83 protected:
84 
85 	virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
86 	virtual void Restart();
87 
SIPROUND()88 	inline void SIPROUND()
89 	{
90 		m_v[0] += m_v[1];
91 		m_v[1] = rotlConstant<13>(m_v[1]);
92 		m_v[1] ^= m_v[0];
93 		m_v[0] = rotlConstant<32>(m_v[0]);
94 		m_v[2] += m_v[3];
95 		m_v[3] = rotlConstant<16>(m_v[3]);
96 		m_v[3] ^= m_v[2];
97 		m_v[0] += m_v[3];
98 		m_v[3] = rotlConstant<21>(m_v[3]);
99 		m_v[3] ^= m_v[0];
100 		m_v[2] += m_v[1];
101 		m_v[1] = rotlConstant<17>(m_v[1]);
102 		m_v[1] ^= m_v[2];
103 		m_v[2] = rotlConstant<32>(m_v[2]);
104 	}
105 
106 private:
107 	FixedSizeSecBlock<word64, 4> m_v;
108 	FixedSizeSecBlock<word64, 2> m_k;
109 	FixedSizeSecBlock<word64, 2> m_b;
110 
111 	// Tail bytes
112 	FixedSizeSecBlock<byte, 8> m_acc;
113 	size_t m_idx;
114 };
115 
116 /// \brief SipHash message authentication code
117 /// \tparam C the number of compression rounds
118 /// \tparam D the number of finalization rounds
119 /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size
120 /// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length
121 ///   message and 128-bit secret key. It was designed to be efficient even for short inputs, with
122 ///   performance comparable to non-cryptographic hash functions.
123 /// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following.
124 ///   <pre>  SecByteBlock key(16);
125 ///   prng.GenerateBlock(key, key.size());
126 ///
127 ///   SipHash<2,4,false> hash(key, key.size());
128 ///   hash.Update(...);
129 ///   hash.Final(...);</pre>
130 /// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following.
131 ///   <pre>  SecByteBlock key(16);
132 ///   prng.GenerateBlock(key, key.size());
133 ///
134 ///   SipHash<2,4,true> hash(key, key.size());
135 ///   hash.Update(...);
136 ///   hash.Final(...);</pre>
137 /// \sa Jean-Philippe Aumasson and Daniel J. Bernstein <A HREF="http://131002.net/siphash/siphash.pdf">SipHash:
138 ///   a fast short-input PRF</A>
139 /// \since Crypto++ 6.0
140 template <unsigned int C=2, unsigned int D=4, bool T_128bit=false>
141 class SipHash : public SipHash_Base<C, D, T_128bit>
142 {
143 public:
144 	/// \brief Create a SipHash
SipHash()145 	SipHash()
146 		{this->UncheckedSetKey(NULLPTR, 0, g_nullNameValuePairs);}
147 	/// \brief Create a SipHash
148 	/// \param key a byte array used to key the cipher
149 	/// \param length the size of the byte array, in bytes
SipHash(const byte * key,unsigned int length)150 	SipHash(const byte *key, unsigned int length)
151 		{this->ThrowIfInvalidKeyLength(length);
152 		 this->UncheckedSetKey(key, length, g_nullNameValuePairs);}
153 };
154 
155 template <unsigned int C, unsigned int D, bool T_128bit>
Update(const byte * input,size_t length)156 void SipHash_Base<C,D,T_128bit>::Update(const byte *input, size_t length)
157 {
158 	CRYPTOPP_ASSERT((input && length) || !length);
159 	if (!length) return;
160 
161 	if (m_idx)
162 	{
163 		size_t head = STDMIN(size_t(8U-m_idx), length);
164 		memcpy(m_acc+m_idx, input, head);
165 		m_idx += head; input += head; length -= head;
166 
167 		if (m_idx == 8)
168 		{
169 			word64 m = GetWord<word64>(true, LITTLE_ENDIAN_ORDER, m_acc);
170 			m_v[3] ^= m;
171 			for (unsigned int i = 0; i < C; ++i)
172 				SIPROUND();
173 
174 			m_v[0] ^= m;
175 			m_b[0] += 8;
176 
177 			m_idx = 0;
178 		}
179 	}
180 
181 	while (length >= 8)
182 	{
183 		word64 m = GetWord<word64>(false, LITTLE_ENDIAN_ORDER, input);
184 		m_v[3] ^= m;
185 		for (unsigned int i = 0; i < C; ++i)
186 			SIPROUND();
187 
188 		m_v[0] ^= m;
189 		m_b[0] += 8;
190 
191 		input += 8;
192 		length -= 8;
193 	}
194 
195 	CRYPTOPP_ASSERT(length < 8);
196 	size_t tail = length % 8;
197 	if (tail)
198 	{
199 		memcpy(m_acc+m_idx, input, tail);
200 		m_idx += tail;
201 	}
202 }
203 
204 template <unsigned int C, unsigned int D, bool T_128bit>
TruncatedFinal(byte * digest,size_t digestSize)205 void SipHash_Base<C,D,T_128bit>::TruncatedFinal(byte *digest, size_t digestSize)
206 {
207 	CRYPTOPP_ASSERT(digest);      // Pointer is valid
208 
209 	ThrowIfInvalidTruncatedSize(digestSize);
210 
211 	// The high octet holds length and is digested mod 256
212 	m_b[0] += m_idx; m_b[0] <<= 56U;
213 	switch (m_idx)
214 	{
215 		case 7:
216 			m_b[0] |= ((word64)m_acc[6]) << 48;
217 			// fall through
218 		case 6:
219 			m_b[0] |= ((word64)m_acc[5]) << 40;
220 			// fall through
221 		case 5:
222 			m_b[0] |= ((word64)m_acc[4]) << 32;
223 			// fall through
224 		case 4:
225 			m_b[0] |= ((word64)m_acc[3]) << 24;
226 			// fall through
227 		case 3:
228 			m_b[0] |= ((word64)m_acc[2]) << 16;
229 			// fall through
230 		case 2:
231 			m_b[0] |= ((word64)m_acc[1]) << 8;
232 			// fall through
233 		case 1:
234 			m_b[0] |= ((word64)m_acc[0]);
235 			// fall through
236 		case 0:
237 			break;
238 	}
239 
240 	m_v[3] ^= m_b[0];
241 
242 	for (unsigned int i=0; i<C; i++)
243 		SIPROUND();
244 
245 	m_v[0] ^= m_b[0];
246 
247 	if (T_128bit)
248 		m_v[2] ^= 0xee;
249 	else
250 		m_v[2] ^= 0xff;
251 
252 	for (unsigned int i=0; i<D; i++)
253 		SIPROUND();
254 
255 	m_b[0] = m_v[0] ^ m_v[1] ^ m_v[2] ^ m_v[3];
256 	m_b[0] = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, m_b[0]);
257 
258 	if (T_128bit)
259 	{
260 		m_v[1] ^= 0xdd;
261 		for (unsigned int i = 0; i<D; ++i)
262 			SIPROUND();
263 
264 		m_b[1] = m_v[0] ^ m_v[1] ^ m_v[2] ^ m_v[3];
265 		m_b[1] = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, m_b[1]);
266 	}
267 
268 	memcpy_s(digest, digestSize, m_b.begin(), STDMIN(digestSize, (size_t)SipHash_Info<T_128bit>::DIGESTSIZE));
269 	Restart();
270 }
271 
272 template <unsigned int C, unsigned int D, bool T_128bit>
UncheckedSetKey(const byte * key,unsigned int length,const NameValuePairs & params)273 void SipHash_Base<C,D,T_128bit>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
274 {
275 	CRYPTOPP_UNUSED(params);
276 	if (key && length)
277 	{
278 		m_k[0] = GetWord<word64>(false, LITTLE_ENDIAN_ORDER, key);
279 		m_k[1] = GetWord<word64>(false, LITTLE_ENDIAN_ORDER, key+8);
280 	}
281 	else
282 	{
283 		// Avoid Coverity finding
284 		m_k[0] = m_k[1] = 0;
285 	}
286 	Restart();
287 }
288 
289 template <unsigned int C, unsigned int D, bool T_128bit>
Restart()290 void SipHash_Base<C,D,T_128bit>::Restart ()
291 {
292 	m_v[0] = W64LIT(0x736f6d6570736575);
293 	m_v[1] = W64LIT(0x646f72616e646f6d);
294 	m_v[2] = W64LIT(0x6c7967656e657261);
295 	m_v[3] = W64LIT(0x7465646279746573);
296 
297 	m_v[3] ^= m_k[1];
298 	m_v[2] ^= m_k[0];
299 	m_v[1] ^= m_k[1];
300 	m_v[0] ^= m_k[0];
301 
302 	if (T_128bit)
303 	{
304 		m_v[1] ^= 0xee;
305 	}
306 
307 	m_idx = 0;
308 	m_b[0] = 0;
309 }
310 
311 NAMESPACE_END
312 
313 #endif // CRYPTOPP_SIPHASH_H
314