1*129a3690Sjmcneill /* $NetBSD: blake2s.c,v 1.2 2021/10/17 14:45:45 jmcneill Exp $ */
2faaca7c6Sriastradh
3faaca7c6Sriastradh /*-
4faaca7c6Sriastradh * Copyright (c) 2015 Taylor R. Campbell
5faaca7c6Sriastradh * All rights reserved.
6faaca7c6Sriastradh *
7faaca7c6Sriastradh * Redistribution and use in source and binary forms, with or without
8faaca7c6Sriastradh * modification, are permitted provided that the following conditions
9faaca7c6Sriastradh * are met:
10faaca7c6Sriastradh * 1. Redistributions of source code must retain the above copyright
11faaca7c6Sriastradh * notice, this list of conditions and the following disclaimer.
12faaca7c6Sriastradh * 2. Redistributions in binary form must reproduce the above copyright
13faaca7c6Sriastradh * notice, this list of conditions and the following disclaimer in the
14faaca7c6Sriastradh * documentation and/or other materials provided with the distribution.
15faaca7c6Sriastradh *
16faaca7c6Sriastradh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17faaca7c6Sriastradh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18faaca7c6Sriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19faaca7c6Sriastradh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20faaca7c6Sriastradh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21faaca7c6Sriastradh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22faaca7c6Sriastradh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23faaca7c6Sriastradh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24faaca7c6Sriastradh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25faaca7c6Sriastradh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26faaca7c6Sriastradh * SUCH DAMAGE.
27faaca7c6Sriastradh */
28faaca7c6Sriastradh
29faaca7c6Sriastradh #ifdef _KERNEL
30faaca7c6Sriastradh
31faaca7c6Sriastradh #include <sys/cdefs.h>
32*129a3690Sjmcneill __KERNEL_RCSID(0, "$NetBSD: blake2s.c,v 1.2 2021/10/17 14:45:45 jmcneill Exp $");
33faaca7c6Sriastradh
34faaca7c6Sriastradh #include <sys/types.h>
35faaca7c6Sriastradh #include <sys/module.h>
36faaca7c6Sriastradh
37faaca7c6Sriastradh #include <lib/libkern/libkern.h>
38faaca7c6Sriastradh
39faaca7c6Sriastradh #else
40faaca7c6Sriastradh
41faaca7c6Sriastradh #define _POSIX_C_SOURCE 200809L
42faaca7c6Sriastradh
43faaca7c6Sriastradh #include <assert.h>
44faaca7c6Sriastradh #include <stdint.h>
45faaca7c6Sriastradh #include <string.h>
46faaca7c6Sriastradh
47faaca7c6Sriastradh #endif
48faaca7c6Sriastradh
49faaca7c6Sriastradh #include "blake2s.h"
50faaca7c6Sriastradh
51faaca7c6Sriastradh #include <sys/endian.h>
52faaca7c6Sriastradh
53faaca7c6Sriastradh static inline uint32_t
rotr32(uint32_t x,unsigned c)54faaca7c6Sriastradh rotr32(uint32_t x, unsigned c)
55faaca7c6Sriastradh {
56faaca7c6Sriastradh
57faaca7c6Sriastradh return ((x >> c) | (x << (32 - c)));
58faaca7c6Sriastradh }
59faaca7c6Sriastradh
60faaca7c6Sriastradh #define BLAKE2S_G(VA, VB, VC, VD, X, Y) do \
61faaca7c6Sriastradh { \
62faaca7c6Sriastradh (VA) = (VA) + (VB) + (X); \
63faaca7c6Sriastradh (VD) = rotr32((VD) ^ (VA), 16); \
64faaca7c6Sriastradh (VC) = (VC) + (VD); \
65faaca7c6Sriastradh (VB) = rotr32((VB) ^ (VC), 12); \
66faaca7c6Sriastradh (VA) = (VA) + (VB) + (Y); \
67faaca7c6Sriastradh (VD) = rotr32((VD) ^ (VA), 8); \
68faaca7c6Sriastradh (VC) = (VC) + (VD); \
69faaca7c6Sriastradh (VB) = rotr32((VB) ^ (VC), 7); \
70faaca7c6Sriastradh } while (0)
71faaca7c6Sriastradh
72faaca7c6Sriastradh static const uint32_t blake2s_iv[8] = {
73faaca7c6Sriastradh 0x6a09e667U, 0xbb67ae85U, 0x3c6ef372U, 0xa54ff53aU,
74faaca7c6Sriastradh 0x510e527fU, 0x9b05688cU, 0x1f83d9abU, 0x5be0cd19U,
75faaca7c6Sriastradh };
76faaca7c6Sriastradh
77faaca7c6Sriastradh static const uint8_t blake2s_sigma[10][16] = {
78faaca7c6Sriastradh { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
79faaca7c6Sriastradh { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
80faaca7c6Sriastradh { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
81faaca7c6Sriastradh { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
82faaca7c6Sriastradh { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
83faaca7c6Sriastradh { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
84faaca7c6Sriastradh { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
85faaca7c6Sriastradh { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
86faaca7c6Sriastradh { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
87faaca7c6Sriastradh { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
88faaca7c6Sriastradh };
89faaca7c6Sriastradh
90faaca7c6Sriastradh static void
blake2s_compress(uint32_t h[8],uint64_t c,uint32_t last,const uint8_t in[64])91faaca7c6Sriastradh blake2s_compress(uint32_t h[8], uint64_t c, uint32_t last,
92faaca7c6Sriastradh const uint8_t in[64])
93faaca7c6Sriastradh {
94faaca7c6Sriastradh uint32_t v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15;
95faaca7c6Sriastradh uint32_t m[16];
96faaca7c6Sriastradh unsigned i;
97faaca7c6Sriastradh
98faaca7c6Sriastradh /* Load the variables: first 8 from state, next 8 from IV. */
99faaca7c6Sriastradh v0 = h[0];
100faaca7c6Sriastradh v1 = h[1];
101faaca7c6Sriastradh v2 = h[2];
102faaca7c6Sriastradh v3 = h[3];
103faaca7c6Sriastradh v4 = h[4];
104faaca7c6Sriastradh v5 = h[5];
105faaca7c6Sriastradh v6 = h[6];
106faaca7c6Sriastradh v7 = h[7];
107faaca7c6Sriastradh v8 = blake2s_iv[0];
108faaca7c6Sriastradh v9 = blake2s_iv[1];
109faaca7c6Sriastradh v10 = blake2s_iv[2];
110faaca7c6Sriastradh v11 = blake2s_iv[3];
111faaca7c6Sriastradh v12 = blake2s_iv[4];
112faaca7c6Sriastradh v13 = blake2s_iv[5];
113faaca7c6Sriastradh v14 = blake2s_iv[6];
114faaca7c6Sriastradh v15 = blake2s_iv[7];
115faaca7c6Sriastradh
116faaca7c6Sriastradh /* Incorporate the block counter and whether this is last. */
117faaca7c6Sriastradh v12 ^= c & 0xffffffffU;
118faaca7c6Sriastradh v13 ^= c >> 32;
119faaca7c6Sriastradh v14 ^= last;
120faaca7c6Sriastradh
121faaca7c6Sriastradh /* Load the message block. */
122faaca7c6Sriastradh for (i = 0; i < 16; i++)
123faaca7c6Sriastradh m[i] = le32dec(in + 4*i);
124faaca7c6Sriastradh
125faaca7c6Sriastradh /* Transform the variables. */
126faaca7c6Sriastradh for (i = 0; i < 10; i++) {
127faaca7c6Sriastradh const uint8_t *sigma = blake2s_sigma[i];
128faaca7c6Sriastradh
129faaca7c6Sriastradh BLAKE2S_G(v0, v4, v8, v12, m[sigma[ 0]], m[sigma[ 1]]);
130faaca7c6Sriastradh BLAKE2S_G(v1, v5, v9, v13, m[sigma[ 2]], m[sigma[ 3]]);
131faaca7c6Sriastradh BLAKE2S_G(v2, v6, v10, v14, m[sigma[ 4]], m[sigma[ 5]]);
132faaca7c6Sriastradh BLAKE2S_G(v3, v7, v11, v15, m[sigma[ 6]], m[sigma[ 7]]);
133faaca7c6Sriastradh BLAKE2S_G(v0, v5, v10, v15, m[sigma[ 8]], m[sigma[ 9]]);
134faaca7c6Sriastradh BLAKE2S_G(v1, v6, v11, v12, m[sigma[10]], m[sigma[11]]);
135faaca7c6Sriastradh BLAKE2S_G(v2, v7, v8, v13, m[sigma[12]], m[sigma[13]]);
136faaca7c6Sriastradh BLAKE2S_G(v3, v4, v9, v14, m[sigma[14]], m[sigma[15]]);
137faaca7c6Sriastradh }
138faaca7c6Sriastradh
139faaca7c6Sriastradh /* Update the state. */
140faaca7c6Sriastradh h[0] ^= v0 ^ v8;
141faaca7c6Sriastradh h[1] ^= v1 ^ v9;
142faaca7c6Sriastradh h[2] ^= v2 ^ v10;
143faaca7c6Sriastradh h[3] ^= v3 ^ v11;
144faaca7c6Sriastradh h[4] ^= v4 ^ v12;
145faaca7c6Sriastradh h[5] ^= v5 ^ v13;
146faaca7c6Sriastradh h[6] ^= v6 ^ v14;
147faaca7c6Sriastradh h[7] ^= v7 ^ v15;
148faaca7c6Sriastradh
149faaca7c6Sriastradh (void)explicit_memset(m, 0, sizeof m);
150faaca7c6Sriastradh }
151faaca7c6Sriastradh
152faaca7c6Sriastradh void
blake2s_init(struct blake2s * B,size_t dlen,const void * key,size_t keylen)153faaca7c6Sriastradh blake2s_init(struct blake2s *B, size_t dlen, const void *key, size_t keylen)
154faaca7c6Sriastradh {
155faaca7c6Sriastradh uint32_t param0;
156faaca7c6Sriastradh unsigned i;
157faaca7c6Sriastradh
158faaca7c6Sriastradh assert(0 < dlen);
159faaca7c6Sriastradh assert(dlen <= 32);
160faaca7c6Sriastradh assert(keylen <= 32);
161faaca7c6Sriastradh
162faaca7c6Sriastradh /* Record the digest length. */
163faaca7c6Sriastradh B->dlen = dlen;
164faaca7c6Sriastradh
165faaca7c6Sriastradh /* Initialize the buffer. */
166faaca7c6Sriastradh B->nb = 0;
167faaca7c6Sriastradh
168faaca7c6Sriastradh /* Initialize the state. */
169faaca7c6Sriastradh B->c = 0;
170faaca7c6Sriastradh for (i = 0; i < 8; i++)
171faaca7c6Sriastradh B->h[i] = blake2s_iv[i];
172faaca7c6Sriastradh
173faaca7c6Sriastradh /*
174faaca7c6Sriastradh * Set the parameters. We support only variable digest and key
175faaca7c6Sriastradh * lengths: no tree hashing, no salt, no personalization.
176faaca7c6Sriastradh */
177faaca7c6Sriastradh param0 = 0;
178faaca7c6Sriastradh param0 |= (uint32_t)dlen << 0;
179faaca7c6Sriastradh param0 |= (uint32_t)keylen << 8;
180faaca7c6Sriastradh param0 |= (uint32_t)1 << 16; /* tree fanout = 1 */
181faaca7c6Sriastradh param0 |= (uint32_t)1 << 24; /* tree depth = 1 */
182faaca7c6Sriastradh B->h[0] ^= param0;
183faaca7c6Sriastradh
184faaca7c6Sriastradh /* If there's a key, compress it as the first message block. */
185faaca7c6Sriastradh if (keylen) {
186faaca7c6Sriastradh static const uint8_t zero_block[64];
187faaca7c6Sriastradh
188faaca7c6Sriastradh blake2s_update(B, key, keylen);
189faaca7c6Sriastradh blake2s_update(B, zero_block, 64 - keylen);
190faaca7c6Sriastradh }
191faaca7c6Sriastradh }
192faaca7c6Sriastradh
193faaca7c6Sriastradh void
blake2s_update(struct blake2s * B,const void * buf,size_t len)194faaca7c6Sriastradh blake2s_update(struct blake2s *B, const void *buf, size_t len)
195faaca7c6Sriastradh {
196faaca7c6Sriastradh const uint8_t *p = buf;
197faaca7c6Sriastradh size_t n = len;
198faaca7c6Sriastradh
199faaca7c6Sriastradh /* Check the current state of the buffer. */
200faaca7c6Sriastradh if (n <= 64u - B->nb) {
201faaca7c6Sriastradh /* Can at most exactly fill the buffer. */
202faaca7c6Sriastradh (void)memcpy(&B->b[B->nb], p, n);
203faaca7c6Sriastradh B->nb += n;
204faaca7c6Sriastradh return;
205faaca7c6Sriastradh } else if (0 < B->nb) {
206faaca7c6Sriastradh /* Can fill the buffer and go on. */
207faaca7c6Sriastradh (void)memcpy(&B->b[B->nb], p, 64 - B->nb);
208faaca7c6Sriastradh B->c += 64;
209faaca7c6Sriastradh blake2s_compress(B->h, B->c, 0, B->b);
210faaca7c6Sriastradh p += 64 - B->nb;
211faaca7c6Sriastradh n -= 64 - B->nb;
212faaca7c6Sriastradh }
213faaca7c6Sriastradh
214faaca7c6Sriastradh /* At a block boundary. Compress straight from the input. */
215faaca7c6Sriastradh while (64 < n) {
216faaca7c6Sriastradh B->c += 64;
217faaca7c6Sriastradh blake2s_compress(B->h, B->c, 0, p);
218faaca7c6Sriastradh p += 64;
219faaca7c6Sriastradh n -= 64;
220faaca7c6Sriastradh }
221faaca7c6Sriastradh
222faaca7c6Sriastradh /*
223faaca7c6Sriastradh * Put whatever's left in the buffer. We may fill the buffer,
224faaca7c6Sriastradh * but we can't compress in that case until we know whether we
225faaca7c6Sriastradh * are compressing the last block or not.
226faaca7c6Sriastradh */
227faaca7c6Sriastradh (void)memcpy(B->b, p, n);
228faaca7c6Sriastradh B->nb = n;
229faaca7c6Sriastradh }
230faaca7c6Sriastradh
231faaca7c6Sriastradh void
blake2s_final(struct blake2s * B,void * digest)232faaca7c6Sriastradh blake2s_final(struct blake2s *B, void *digest)
233faaca7c6Sriastradh {
234faaca7c6Sriastradh uint8_t *d = digest;
235faaca7c6Sriastradh unsigned dlen = B->dlen;
236faaca7c6Sriastradh unsigned i;
237faaca7c6Sriastradh
238faaca7c6Sriastradh /* Pad with zeros, and do the last compression. */
239faaca7c6Sriastradh B->c += B->nb;
240faaca7c6Sriastradh for (i = B->nb; i < 64; i++)
241faaca7c6Sriastradh B->b[i] = 0;
242faaca7c6Sriastradh blake2s_compress(B->h, B->c, ~(uint32_t)0, B->b);
243faaca7c6Sriastradh
244faaca7c6Sriastradh /* Reveal the first dlen/4 words of the state. */
245faaca7c6Sriastradh for (i = 0; i < dlen/4; i++)
246faaca7c6Sriastradh le32enc(d + 4*i, B->h[i]);
247faaca7c6Sriastradh d += 4*i;
248faaca7c6Sriastradh dlen -= 4*i;
249faaca7c6Sriastradh
250faaca7c6Sriastradh /* If the caller wants a partial word, reveal that too. */
251faaca7c6Sriastradh if (dlen) {
252faaca7c6Sriastradh uint32_t hi = B->h[i];
253faaca7c6Sriastradh
254faaca7c6Sriastradh do {
255faaca7c6Sriastradh *d++ = hi;
256faaca7c6Sriastradh hi >>= 8;
257faaca7c6Sriastradh } while (--dlen);
258faaca7c6Sriastradh }
259faaca7c6Sriastradh
260faaca7c6Sriastradh /* Erase the state. */
261faaca7c6Sriastradh (void)explicit_memset(B, 0, sizeof B);
262faaca7c6Sriastradh }
263faaca7c6Sriastradh
264faaca7c6Sriastradh void
blake2s(void * digest,size_t dlen,const void * key,size_t keylen,const void * in,size_t inlen)265faaca7c6Sriastradh blake2s(void *digest, size_t dlen, const void *key, size_t keylen,
266faaca7c6Sriastradh const void *in, size_t inlen)
267faaca7c6Sriastradh {
268faaca7c6Sriastradh struct blake2s ctx;
269faaca7c6Sriastradh
270faaca7c6Sriastradh blake2s_init(&ctx, dlen, key, keylen);
271faaca7c6Sriastradh blake2s_update(&ctx, in, inlen);
272faaca7c6Sriastradh blake2s_final(&ctx, digest);
273faaca7c6Sriastradh }
274faaca7c6Sriastradh
275faaca7c6Sriastradh static void
blake2_selftest_prng(void * buf,size_t len,uint32_t seed)276faaca7c6Sriastradh blake2_selftest_prng(void *buf, size_t len, uint32_t seed)
277faaca7c6Sriastradh {
278faaca7c6Sriastradh uint8_t *p = buf;
279faaca7c6Sriastradh size_t n = len;
280faaca7c6Sriastradh uint32_t t, a, b;
281faaca7c6Sriastradh
282faaca7c6Sriastradh a = 0xdead4bad * seed;
283faaca7c6Sriastradh b = 1;
284faaca7c6Sriastradh
285faaca7c6Sriastradh while (n--) {
286faaca7c6Sriastradh t = a + b;
287faaca7c6Sriastradh *p++ = t >> 24;
288faaca7c6Sriastradh a = b;
289faaca7c6Sriastradh b = t;
290faaca7c6Sriastradh }
291faaca7c6Sriastradh }
292faaca7c6Sriastradh
293faaca7c6Sriastradh int
blake2s_selftest(void)294faaca7c6Sriastradh blake2s_selftest(void)
295faaca7c6Sriastradh {
296faaca7c6Sriastradh const uint8_t d0[32] = {
297faaca7c6Sriastradh 0x6a,0x41,0x1f,0x08,0xce,0x25,0xad,0xcd,
298faaca7c6Sriastradh 0xfb,0x02,0xab,0xa6,0x41,0x45,0x1c,0xec,
299faaca7c6Sriastradh 0x53,0xc5,0x98,0xb2,0x4f,0x4f,0xc7,0x87,
300faaca7c6Sriastradh 0xfb,0xdc,0x88,0x79,0x7f,0x4c,0x1d,0xfe,
301faaca7c6Sriastradh };
302faaca7c6Sriastradh const unsigned dlen[4] = { 16, 20, 28, 32 };
303faaca7c6Sriastradh const unsigned mlen[6] = { 0, 3, 64, 65, 255, 1024 };
304faaca7c6Sriastradh uint8_t m[1024], d[32], k[32];
305faaca7c6Sriastradh struct blake2s ctx;
306faaca7c6Sriastradh unsigned di, mi, i;
307faaca7c6Sriastradh
308faaca7c6Sriastradh blake2s_init(&ctx, 32, NULL, 0);
309faaca7c6Sriastradh for (di = 0; di < 4; di++) {
310faaca7c6Sriastradh for (mi = 0; mi < 6; mi++) {
311faaca7c6Sriastradh blake2_selftest_prng(m, mlen[mi], mlen[mi]);
312faaca7c6Sriastradh blake2s(d, dlen[di], NULL, 0, m, mlen[mi]);
313faaca7c6Sriastradh blake2s_update(&ctx, d, dlen[di]);
314faaca7c6Sriastradh
315faaca7c6Sriastradh blake2_selftest_prng(k, dlen[di], dlen[di]);
316faaca7c6Sriastradh blake2s(d, dlen[di], k, dlen[di], m, mlen[mi]);
317faaca7c6Sriastradh blake2s_update(&ctx, d, dlen[di]);
318faaca7c6Sriastradh }
319faaca7c6Sriastradh }
320faaca7c6Sriastradh blake2s_final(&ctx, d);
321faaca7c6Sriastradh for (i = 0; i < 32; i++) {
322faaca7c6Sriastradh if (d[i] != d0[i])
323faaca7c6Sriastradh return -1;
324faaca7c6Sriastradh }
325faaca7c6Sriastradh
326faaca7c6Sriastradh return 0;
327faaca7c6Sriastradh }
328faaca7c6Sriastradh
329faaca7c6Sriastradh #ifdef _KERNEL
330faaca7c6Sriastradh
331faaca7c6Sriastradh MODULE(MODULE_CLASS_MISC, blake2s, NULL);
332faaca7c6Sriastradh
333faaca7c6Sriastradh static int
blake2s_modcmd(modcmd_t cmd,void * opaque)334faaca7c6Sriastradh blake2s_modcmd(modcmd_t cmd, void *opaque)
335faaca7c6Sriastradh {
336faaca7c6Sriastradh
337faaca7c6Sriastradh switch (cmd) {
338faaca7c6Sriastradh case MODULE_CMD_INIT:
339faaca7c6Sriastradh if (blake2s_selftest())
340faaca7c6Sriastradh panic("blake2s: self-test failed");
341*129a3690Sjmcneill aprint_debug("blake2s: self-test passed\n");
342faaca7c6Sriastradh return 0;
343faaca7c6Sriastradh case MODULE_CMD_FINI:
344faaca7c6Sriastradh return 0;
345faaca7c6Sriastradh default:
346faaca7c6Sriastradh return ENOTTY;
347faaca7c6Sriastradh }
348faaca7c6Sriastradh }
349faaca7c6Sriastradh
350faaca7c6Sriastradh #endif
351