1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/random.h>
34
35#include <errno.h>
36#include <stdint.h>
37#include <stdio.h>
38#include <stdbool.h>
39
40#include <crypto/chacha20/chacha.h>
41#include <crypto/rijndael/rijndael-api-fst.h>
42#include <crypto/sha2/sha256.h>
43
44#include <dev/random/hash.h>
45#include <dev/random/uint128.h>
46
47#include <atf-c.h>
48
49static void
50vec_u32_tole128(uint8_t dst[static 16], const uint32_t src[static 4])
51{
52	le32enc(dst, src[0]);
53	le32enc(&dst[4], src[1]);
54	le32enc(&dst[8], src[2]);
55	le32enc(&dst[12], src[3]);
56}
57
58static void
59le128_to_vec_u32(uint32_t dst[static 4], const uint8_t src[static 16])
60{
61	dst[0] = le32dec(src);
62	dst[1] = le32dec(&src[4]);
63	dst[2] = le32dec(&src[8]);
64	dst[3] = le32dec(&src[12]);
65}
66
67static void
68formatu128(char buf[static 52], uint128_t x)
69{
70	uint8_t le128x[16];
71	uint32_t vx[4];
72	size_t sz, i;
73	int rc;
74
75	le128enc(le128x, x);
76	le128_to_vec_u32(vx, le128x);
77
78	sz = 52;
79	for (i = 0; i < 4; i++) {
80		rc = snprintf(buf, sz, "0x%x ", vx[i]);
81		ATF_REQUIRE(rc > 0 && (size_t)rc < sz);
82
83		buf += rc;
84		sz -= rc;
85	}
86	/* Delete last trailing space */
87	buf[-1] = '\0';
88}
89
90static void
91u128_check_equality(uint128_t a, uint128_t b, const char *descr)
92{
93	char fmtbufa[52], fmtbufb[52];
94
95	formatu128(fmtbufa, a);
96	formatu128(fmtbufb, b);
97
98	ATF_CHECK_MSG(uint128_equals(a, b),
99	    "Expected: [%s] != Actual: [%s]: %s", fmtbufa, fmtbufb, descr);
100}
101
102ATF_TC_WITHOUT_HEAD(uint128_inc);
103ATF_TC_BODY(uint128_inc, tc)
104{
105	static const struct u128_inc_tc {
106		uint32_t input[4];
107		uint32_t expected[4];
108		const char *descr;
109	} tests[] = {
110		{
111			.input = { 0, 0, 0, 0 },
112			.expected = { 1, 0, 0, 0 },
113			.descr = "0 -> 1",
114		},
115		{
116			.input = { 1, 0, 0, 0 },
117			.expected = { 2, 0, 0, 0 },
118			.descr = "0 -> 2",
119		},
120		{
121			.input = { 0xff, 0, 0, 0 },
122			.expected = { 0x100, 0, 0, 0 },
123			.descr = "0xff -> 0x100 (byte carry)",
124		},
125		{
126			.input = { UINT32_MAX, 0, 0, 0 },
127			.expected = { 0, 1, 0, 0 },
128			.descr = "2^32 - 1 -> 2^32 (word carry)",
129		},
130		{
131			.input = { UINT32_MAX, UINT32_MAX, 0, 0 },
132			.expected = { 0, 0, 1, 0 },
133			.descr = "2^64 - 1 -> 2^64 (u128t_word0 carry)",
134		},
135		{
136			.input = { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 },
137			.expected = { 0, 0, 0, 1 },
138			.descr = "2^96 - 1 -> 2^96 (word carry)",
139		},
140	};
141	uint8_t inputle[16], expectedle[16];
142	uint128_t a;
143	size_t i;
144
145	for (i = 0; i < nitems(tests); i++) {
146		vec_u32_tole128(inputle, tests[i].input);
147		vec_u32_tole128(expectedle, tests[i].expected);
148
149		a = le128dec(inputle);
150		uint128_increment(&a);
151		u128_check_equality(le128dec(expectedle), a, tests[i].descr);
152	}
153}
154
155ATF_TC_WITHOUT_HEAD(uint128_add64);
156ATF_TC_BODY(uint128_add64, tc)
157{
158	static const struct u128_add64_tc {
159		uint32_t input[4];
160		uint64_t addend;
161		uint32_t expected[4];
162		const char *descr;
163	} tests[] = {
164		{
165			.input = { 0, 0, 0, 0 },
166			.addend = 1,
167			.expected = { 1, 0, 0, 0 },
168			.descr = "0 + 1 -> 1",
169		},
170		{
171			.input = { 1, 0, 0, 0 },
172			.addend = UINT32_MAX,
173			.expected = { 0, 1, 0, 0 },
174			.descr = "1 + (2^32 - 1) -> 2^32 (word carry)",
175		},
176		{
177			.input = { 1, 0, 0, 0 },
178			.addend = UINT64_MAX,
179			.expected = { 0, 0, 1, 0 },
180			.descr = "1 + (2^64 - 1) -> 2^64 (u128t_word0 carry)",
181		},
182		{
183			.input = { 0x11111111, 0x11111111, 0, 0 },
184			.addend = 0xf0123456789abcdeULL,
185			.expected = { 0x89abcdef, 0x01234567, 1, 0 },
186			.descr = "0x1111_1111_1111_1111 +"
187				 "0xf012_3456_789a_bcde ->"
188			       "0x1_0123_4567_89ab_cdef",
189		},
190		{
191			.input = { 1, 0, UINT32_MAX, 0 },
192			.addend = UINT64_MAX,
193			.expected = { 0, 0, 0, 1 },
194			.descr = "Carry ~2^96",
195		},
196	};
197	uint8_t inputle[16], expectedle[16];
198	uint128_t a;
199	size_t i;
200
201	for (i = 0; i < nitems(tests); i++) {
202		vec_u32_tole128(inputle, tests[i].input);
203		vec_u32_tole128(expectedle, tests[i].expected);
204
205		a = le128dec(inputle);
206		uint128_add64(&a, tests[i].addend);
207		u128_check_equality(le128dec(expectedle), a, tests[i].descr);
208	}
209}
210
211/*
212 * Test assumptions about Chacha incrementing counter in the same way as
213 * uint128.h
214 */
215ATF_TC_WITHOUT_HEAD(uint128_chacha_ctr);
216ATF_TC_BODY(uint128_chacha_ctr, tc)
217{
218	static const struct u128_chacha_tc {
219		uint32_t input[4];
220		uint32_t expected[4];
221		const char *descr;
222	} tests[] = {
223		{
224			.input = { 0, 0, 0, 0 },
225			.expected = { 1, 0, 0, 0 },
226			.descr = "Single block",
227		},
228		{
229			.input = { 1, 0, 0, 0 },
230			.expected = { 2, 0, 0, 0 },
231			.descr = "0 -> 2",
232		},
233		{
234			.input = { 0xff, 0, 0, 0 },
235			.expected = { 0x100, 0, 0, 0 },
236			.descr = "0xff -> 0x100 (byte carry)",
237		},
238		{
239			.input = { UINT32_MAX, 0, 0, 0 },
240			.expected = { 0, 1, 0, 0 },
241			.descr = "2^32 - 1 -> 2^32 (word carry)",
242		},
243		{
244			.input = { UINT32_MAX, UINT32_MAX, 0, 0 },
245			.expected = { 0, 0, 1, 0 },
246			.descr = "2^64 - 1 -> 2^64 (u128t_word0 carry)",
247		},
248		{
249			.input = { UINT32_MAX, UINT32_MAX, UINT32_MAX, 0 },
250			.expected = { 0, 0, 0, 1 },
251			.descr = "2^96 - 1 -> 2^96 (word carry)",
252		},
253	};
254	union randomdev_key context;
255	uint8_t inputle[16], expectedle[16], trash[CHACHA_BLOCKLEN];
256	uint8_t notrandomkey[RANDOM_KEYSIZE] = { 0 };
257	uint128_t a;
258	size_t i;
259
260	random_chachamode = true;
261	randomdev_encrypt_init(&context, notrandomkey);
262
263	for (i = 0; i < nitems(tests); i++) {
264		vec_u32_tole128(inputle, tests[i].input);
265		vec_u32_tole128(expectedle, tests[i].expected);
266
267		a = le128dec(inputle);
268		randomdev_keystream(&context, &a, trash, sizeof(trash));
269		u128_check_equality(le128dec(expectedle), a, tests[i].descr);
270	}
271
272}
273
274ATF_TP_ADD_TCS(tp)
275{
276
277	ATF_TP_ADD_TC(tp, uint128_inc);
278	ATF_TP_ADD_TC(tp, uint128_add64);
279	ATF_TP_ADD_TC(tp, uint128_chacha_ctr);
280	return (atf_no_error());
281}
282