]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - lib/siphash.c
siphash: add cryptographically secure PRF
[mirror_ubuntu-bionic-kernel.git] / lib / siphash.c
CommitLineData
2c956a60
JD
1/* Copyright (C) 2016 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
2 *
3 * This file is provided under a dual BSD/GPLv2 license.
4 *
5 * SipHash: a fast short-input PRF
6 * https://131002.net/siphash/
7 *
8 * This implementation is specifically for SipHash2-4.
9 */
10
11#include <linux/siphash.h>
12#include <asm/unaligned.h>
13
14#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
15#include <linux/dcache.h>
16#include <asm/word-at-a-time.h>
17#endif
18
19#define SIPROUND \
20 do { \
21 v0 += v1; v1 = rol64(v1, 13); v1 ^= v0; v0 = rol64(v0, 32); \
22 v2 += v3; v3 = rol64(v3, 16); v3 ^= v2; \
23 v0 += v3; v3 = rol64(v3, 21); v3 ^= v0; \
24 v2 += v1; v1 = rol64(v1, 17); v1 ^= v2; v2 = rol64(v2, 32); \
25 } while (0)
26
27#define PREAMBLE(len) \
28 u64 v0 = 0x736f6d6570736575ULL; \
29 u64 v1 = 0x646f72616e646f6dULL; \
30 u64 v2 = 0x6c7967656e657261ULL; \
31 u64 v3 = 0x7465646279746573ULL; \
32 u64 b = ((u64)(len)) << 56; \
33 v3 ^= key->key[1]; \
34 v2 ^= key->key[0]; \
35 v1 ^= key->key[1]; \
36 v0 ^= key->key[0];
37
38#define POSTAMBLE \
39 v3 ^= b; \
40 SIPROUND; \
41 SIPROUND; \
42 v0 ^= b; \
43 v2 ^= 0xff; \
44 SIPROUND; \
45 SIPROUND; \
46 SIPROUND; \
47 SIPROUND; \
48 return (v0 ^ v1) ^ (v2 ^ v3);
49
50u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key)
51{
52 const u8 *end = data + len - (len % sizeof(u64));
53 const u8 left = len & (sizeof(u64) - 1);
54 u64 m;
55 PREAMBLE(len)
56 for (; data != end; data += sizeof(u64)) {
57 m = le64_to_cpup(data);
58 v3 ^= m;
59 SIPROUND;
60 SIPROUND;
61 v0 ^= m;
62 }
63#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
64 if (left)
65 b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
66 bytemask_from_count(left)));
67#else
68 switch (left) {
69 case 7: b |= ((u64)end[6]) << 48;
70 case 6: b |= ((u64)end[5]) << 40;
71 case 5: b |= ((u64)end[4]) << 32;
72 case 4: b |= le32_to_cpup(data); break;
73 case 3: b |= ((u64)end[2]) << 16;
74 case 2: b |= le16_to_cpup(data); break;
75 case 1: b |= end[0];
76 }
77#endif
78 POSTAMBLE
79}
80EXPORT_SYMBOL(__siphash_aligned);
81
82#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
83u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key)
84{
85 const u8 *end = data + len - (len % sizeof(u64));
86 const u8 left = len & (sizeof(u64) - 1);
87 u64 m;
88 PREAMBLE(len)
89 for (; data != end; data += sizeof(u64)) {
90 m = get_unaligned_le64(data);
91 v3 ^= m;
92 SIPROUND;
93 SIPROUND;
94 v0 ^= m;
95 }
96#if defined(CONFIG_DCACHE_WORD_ACCESS) && BITS_PER_LONG == 64
97 if (left)
98 b |= le64_to_cpu((__force __le64)(load_unaligned_zeropad(data) &
99 bytemask_from_count(left)));
100#else
101 switch (left) {
102 case 7: b |= ((u64)end[6]) << 48;
103 case 6: b |= ((u64)end[5]) << 40;
104 case 5: b |= ((u64)end[4]) << 32;
105 case 4: b |= get_unaligned_le32(end); break;
106 case 3: b |= ((u64)end[2]) << 16;
107 case 2: b |= get_unaligned_le16(end); break;
108 case 1: b |= end[0];
109 }
110#endif
111 POSTAMBLE
112}
113EXPORT_SYMBOL(__siphash_unaligned);
114#endif
115
116/**
117 * siphash_1u64 - compute 64-bit siphash PRF value of a u64
118 * @first: first u64
119 * @key: the siphash key
120 */
121u64 siphash_1u64(const u64 first, const siphash_key_t *key)
122{
123 PREAMBLE(8)
124 v3 ^= first;
125 SIPROUND;
126 SIPROUND;
127 v0 ^= first;
128 POSTAMBLE
129}
130EXPORT_SYMBOL(siphash_1u64);
131
132/**
133 * siphash_2u64 - compute 64-bit siphash PRF value of 2 u64
134 * @first: first u64
135 * @second: second u64
136 * @key: the siphash key
137 */
138u64 siphash_2u64(const u64 first, const u64 second, const siphash_key_t *key)
139{
140 PREAMBLE(16)
141 v3 ^= first;
142 SIPROUND;
143 SIPROUND;
144 v0 ^= first;
145 v3 ^= second;
146 SIPROUND;
147 SIPROUND;
148 v0 ^= second;
149 POSTAMBLE
150}
151EXPORT_SYMBOL(siphash_2u64);
152
153/**
154 * siphash_3u64 - compute 64-bit siphash PRF value of 3 u64
155 * @first: first u64
156 * @second: second u64
157 * @third: third u64
158 * @key: the siphash key
159 */
160u64 siphash_3u64(const u64 first, const u64 second, const u64 third,
161 const siphash_key_t *key)
162{
163 PREAMBLE(24)
164 v3 ^= first;
165 SIPROUND;
166 SIPROUND;
167 v0 ^= first;
168 v3 ^= second;
169 SIPROUND;
170 SIPROUND;
171 v0 ^= second;
172 v3 ^= third;
173 SIPROUND;
174 SIPROUND;
175 v0 ^= third;
176 POSTAMBLE
177}
178EXPORT_SYMBOL(siphash_3u64);
179
180/**
181 * siphash_4u64 - compute 64-bit siphash PRF value of 4 u64
182 * @first: first u64
183 * @second: second u64
184 * @third: third u64
185 * @forth: forth u64
186 * @key: the siphash key
187 */
188u64 siphash_4u64(const u64 first, const u64 second, const u64 third,
189 const u64 forth, const siphash_key_t *key)
190{
191 PREAMBLE(32)
192 v3 ^= first;
193 SIPROUND;
194 SIPROUND;
195 v0 ^= first;
196 v3 ^= second;
197 SIPROUND;
198 SIPROUND;
199 v0 ^= second;
200 v3 ^= third;
201 SIPROUND;
202 SIPROUND;
203 v0 ^= third;
204 v3 ^= forth;
205 SIPROUND;
206 SIPROUND;
207 v0 ^= forth;
208 POSTAMBLE
209}
210EXPORT_SYMBOL(siphash_4u64);
211
212u64 siphash_1u32(const u32 first, const siphash_key_t *key)
213{
214 PREAMBLE(4)
215 b |= first;
216 POSTAMBLE
217}
218EXPORT_SYMBOL(siphash_1u32);
219
220u64 siphash_3u32(const u32 first, const u32 second, const u32 third,
221 const siphash_key_t *key)
222{
223 u64 combined = (u64)second << 32 | first;
224 PREAMBLE(12)
225 v3 ^= combined;
226 SIPROUND;
227 SIPROUND;
228 v0 ^= combined;
229 b |= third;
230 POSTAMBLE
231}
232EXPORT_SYMBOL(siphash_3u32);