xref: /freebsd/sys/contrib/openzfs/tests/unit/test_sha2.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 
13 /*
14  * Copyright (c) 2026, Christos Longros.
15  */
16 
17 #include <string.h>
18 
19 #include <sys/types.h>
20 #include <sys/sha2.h>
21 #include <sys/zfs_impl.h>
22 
23 #include "unit.h"
24 
25 /* ========== */
26 
27 #define	DATA_SIZE	8192
28 
29 static uint8_t databuf[DATA_SIZE] __attribute__((aligned(64)));
30 
31 static void
fill_data(void)32 fill_data(void)
33 {
34 	for (size_t i = 0; i < DATA_SIZE; i++)
35 		databuf[i] = (uint8_t)i;
36 }
37 
38 static void
hash_buf(int algotype,const void * buf,size_t len,uint8_t * digest)39 hash_buf(int algotype, const void *buf, size_t len, uint8_t *digest)
40 {
41 	SHA2_CTX ctx;
42 
43 	SHA2Init(algotype, &ctx);
44 	SHA2Update(&ctx, buf, len);
45 	SHA2Final(digest, &ctx);
46 }
47 
48 /* ========== */
49 
50 /*
51  * Test messages and digests from:
52  * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
53  */
54 
55 static const char *test_msg0 = "abc";
56 static const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
57 	"nlmnomnopnopq";
58 static const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfgh"
59 	"ijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
60 
61 static const uint8_t	sha256_test_digests[][32] = {
62 	{
63 		/* for test_msg0 */
64 		0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
65 		0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
66 		0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
67 		0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
68 	},
69 	{
70 		/* for test_msg1 */
71 		0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
72 		0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
73 		0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
74 		0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1
75 	}
76 	/* no test vector for test_msg2 */
77 };
78 
79 static const uint8_t	sha512_test_digests[][64] = {
80 	{
81 		/* for test_msg0 */
82 		0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
83 		0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
84 		0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
85 		0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
86 		0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
87 		0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
88 		0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
89 		0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F
90 	},
91 	{
92 		/* no test vector for test_msg1 */
93 		0
94 	},
95 	{
96 		/* for test_msg2 */
97 		0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
98 		0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
99 		0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
100 		0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
101 		0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
102 		0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
103 		0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
104 		0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
105 	}
106 };
107 
108 static const uint8_t	sha512_256_test_digests[][32] = {
109 	{
110 		/* for test_msg0 */
111 		0x53, 0x04, 0x8E, 0x26, 0x81, 0x94, 0x1E, 0xF9,
112 		0x9B, 0x2E, 0x29, 0xB7, 0x6B, 0x4C, 0x7D, 0xAB,
113 		0xE4, 0xC2, 0xD0, 0xC6, 0x34, 0xFC, 0x6D, 0x46,
114 		0xE0, 0xE2, 0xF1, 0x31, 0x07, 0xE7, 0xAF, 0x23
115 	},
116 	{
117 		/* no test vector for test_msg1 */
118 		0
119 	},
120 	{
121 		/* for test_msg2 */
122 		0x39, 0x28, 0xE1, 0x84, 0xFB, 0x86, 0x90, 0xF8,
123 		0x40, 0xDA, 0x39, 0x88, 0x12, 0x1D, 0x31, 0xBE,
124 		0x65, 0xCB, 0x9D, 0x3E, 0xF8, 0x3E, 0xE6, 0x14,
125 		0x6F, 0xEA, 0xC8, 0x61, 0xE1, 0x9B, 0x56, 0x3A
126 	}
127 };
128 
129 /* one million repetitions of 'a' */
130 
131 static const uint8_t	sha256_million_digest[32] = {
132 	0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
133 	0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
134 	0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
135 	0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0
136 };
137 
138 static const uint8_t	sha512_million_digest[64] = {
139 	0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64,
140 	0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63,
141 	0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28,
142 	0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB,
143 	0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A,
144 	0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B,
145 	0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E,
146 	0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B
147 };
148 
149 /*
150  * Monte Carlo seeds and COUNT = 0 checkpoints from the NIST CAVP
151  * byte-oriented test vectors (shabytetestvectors).
152  */
153 
154 static const uint8_t	sha256_monte_carlo_seed[32] = {
155 	0x6D, 0x1E, 0x72, 0xAD, 0x03, 0xDD, 0xEB, 0x5D,
156 	0xE8, 0x91, 0xE5, 0x72, 0xE2, 0x39, 0x6F, 0x8D,
157 	0xA0, 0x15, 0xD8, 0x99, 0xEF, 0x0E, 0x79, 0x50,
158 	0x31, 0x52, 0xD6, 0x01, 0x0A, 0x3F, 0xE6, 0x91
159 };
160 
161 static const uint8_t	sha256_monte_carlo_digest[32] = {
162 	0xE9, 0x3C, 0x33, 0x0A, 0xE5, 0x44, 0x77, 0x38,
163 	0xC8, 0xAA, 0x85, 0xD7, 0x1A, 0x6C, 0x80, 0xF2,
164 	0xA5, 0x83, 0x81, 0xD0, 0x58, 0x72, 0xD2, 0x6B,
165 	0xDD, 0x39, 0xF1, 0xFC, 0xD4, 0xF2, 0xB7, 0x88
166 };
167 
168 static const uint8_t	sha512_monte_carlo_seed[64] = {
169 	0x5C, 0x33, 0x7D, 0xE5, 0xCA, 0xF3, 0x5D, 0x18,
170 	0xED, 0x90, 0xB5, 0xCD, 0xDF, 0xCE, 0x00, 0x1C,
171 	0xA1, 0xB8, 0xEE, 0x86, 0x02, 0xF3, 0x67, 0xE7,
172 	0xC2, 0x4C, 0xCC, 0xA6, 0xF8, 0x93, 0x80, 0x2F,
173 	0xB1, 0xAC, 0xA7, 0xA3, 0xDA, 0xE3, 0x2D, 0xCD,
174 	0x60, 0x80, 0x0A, 0x59, 0x95, 0x9B, 0xC5, 0x40,
175 	0xD6, 0x32, 0x37, 0x87, 0x6B, 0x79, 0x92, 0x29,
176 	0xAE, 0x71, 0xA2, 0x52, 0x6F, 0xBC, 0x52, 0xCD
177 };
178 
179 static const uint8_t	sha512_monte_carlo_digest[64] = {
180 	0xAD, 0xA6, 0x9A, 0xDD, 0x00, 0x71, 0xB7, 0x94,
181 	0x46, 0x3C, 0x88, 0x06, 0xA1, 0x77, 0x32, 0x67,
182 	0x35, 0xFA, 0x62, 0x4B, 0x68, 0xAB, 0x7B, 0xCA,
183 	0xB2, 0x38, 0x8B, 0x92, 0x76, 0xC0, 0x36, 0xE4,
184 	0xEA, 0xAF, 0xF8, 0x73, 0x33, 0xE8, 0x3C, 0x81,
185 	0xC0, 0xBC, 0xA0, 0x35, 0x9D, 0x4A, 0xEE, 0xBC,
186 	0xBC, 0xFD, 0x31, 0x4C, 0x06, 0x30, 0xE0, 0xC2,
187 	0xAF, 0x68, 0xC1, 0xFB, 0x19, 0xCC, 0x47, 0x0E
188 };
189 
190 static const uint8_t	sha512_256_monte_carlo_seed[32] = {
191 	0xF4, 0x1E, 0xCE, 0x26, 0x13, 0xE4, 0x57, 0x39,
192 	0x15, 0x69, 0x6B, 0x5A, 0xDC, 0xD5, 0x1C, 0xA3,
193 	0x28, 0xBE, 0x3B, 0xF5, 0x66, 0xA9, 0xCA, 0x99,
194 	0xC9, 0xCE, 0xB0, 0x27, 0x9C, 0x1C, 0xB0, 0xA7
195 };
196 
197 static const uint8_t	sha512_256_monte_carlo_digest[32] = {
198 	0xB1, 0xD9, 0x7A, 0x65, 0x36, 0x89, 0x6A, 0xA0,
199 	0x10, 0x98, 0xFB, 0x2B, 0x9E, 0x15, 0xD8, 0x69,
200 	0x26, 0x21, 0xC8, 0x40, 0x77, 0x05, 0x1F, 0xC1,
201 	0xF7, 0x0A, 0x8A, 0x48, 0xBA, 0xA6, 0xDF, 0xAF
202 };
203 
204 static MunitResult
test_sha256_known(const MunitParameter params[],void * data)205 test_sha256_known(const MunitParameter params[], void *data)
206 {
207 	(void) params, (void) data;
208 	uint8_t digest[SHA256_DIGEST_LENGTH];
209 
210 	hash_buf(SHA256, test_msg0, strlen(test_msg0), digest);
211 	munit_assert_memory_equal(sizeof (digest), digest,
212 	    sha256_test_digests[0]);
213 
214 	hash_buf(SHA256, test_msg1, strlen(test_msg1), digest);
215 	munit_assert_memory_equal(sizeof (digest), digest,
216 	    sha256_test_digests[1]);
217 
218 	return (MUNIT_OK);
219 }
220 
221 static MunitResult
test_sha512_known(const MunitParameter params[],void * data)222 test_sha512_known(const MunitParameter params[], void *data)
223 {
224 	(void) params, (void) data;
225 	uint8_t digest[SHA512_DIGEST_LENGTH];
226 
227 	hash_buf(SHA512, test_msg0, strlen(test_msg0), digest);
228 	munit_assert_memory_equal(sizeof (digest), digest,
229 	    sha512_test_digests[0]);
230 
231 	hash_buf(SHA512, test_msg2, strlen(test_msg2), digest);
232 	munit_assert_memory_equal(sizeof (digest), digest,
233 	    sha512_test_digests[2]);
234 
235 	return (MUNIT_OK);
236 }
237 
238 static MunitResult
test_sha512_256_known(const MunitParameter params[],void * data)239 test_sha512_256_known(const MunitParameter params[], void *data)
240 {
241 	(void) params, (void) data;
242 	uint8_t digest[SHA512_256_DIGEST_LENGTH];
243 
244 	hash_buf(SHA512_256, test_msg0, strlen(test_msg0), digest);
245 	munit_assert_memory_equal(sizeof (digest), digest,
246 	    sha512_256_test_digests[0]);
247 
248 	hash_buf(SHA512_256, test_msg2, strlen(test_msg2), digest);
249 	munit_assert_memory_equal(sizeof (digest), digest,
250 	    sha512_256_test_digests[2]);
251 
252 	return (MUNIT_OK);
253 }
254 
255 static MunitResult
test_million(const MunitParameter params[],void * data)256 test_million(const MunitParameter params[], void *data)
257 {
258 	(void) params, (void) data;
259 	static uint8_t buf[1000000];
260 	uint8_t digest[SHA512_DIGEST_LENGTH];
261 
262 	memset(buf, 'a', sizeof (buf));
263 
264 	hash_buf(SHA256, buf, sizeof (buf), digest);
265 	munit_assert_memory_equal(SHA256_DIGEST_LENGTH, digest,
266 	    sha256_million_digest);
267 
268 	hash_buf(SHA512, buf, sizeof (buf), digest);
269 	munit_assert_memory_equal(SHA512_DIGEST_LENGTH, digest,
270 	    sha512_million_digest);
271 
272 	return (MUNIT_OK);
273 }
274 
275 /* SHAVS chain MD[i] = SHA(MD[i-3] || MD[i-2] || MD[i-1]), 1000 rounds. */
276 static MunitResult
test_monte_carlo(const MunitParameter params[],void * data)277 test_monte_carlo(const MunitParameter params[], void *data)
278 {
279 	(void) params, (void) data;
280 
281 	static const int algos[] = { SHA256, SHA512, SHA512_256 };
282 	static const size_t diglens[] = { SHA256_DIGEST_LENGTH,
283 	    SHA512_DIGEST_LENGTH, SHA512_256_DIGEST_LENGTH };
284 	static const uint8_t *const seeds[] = { sha256_monte_carlo_seed,
285 	    sha512_monte_carlo_seed, sha512_256_monte_carlo_seed };
286 	static const uint8_t *const known[] = { sha256_monte_carlo_digest,
287 	    sha512_monte_carlo_digest, sha512_256_monte_carlo_digest };
288 
289 	for (size_t a = 0; a < ARRAY_SIZE(algos); a++) {
290 		uint8_t msg[3 * SHA512_DIGEST_LENGTH];
291 		uint8_t digest[SHA512_DIGEST_LENGTH];
292 		size_t diglen = diglens[a];
293 
294 		for (int m = 0; m < 3; m++)
295 			memcpy(msg + m * diglen, seeds[a], diglen);
296 
297 		for (int i = 0; i < 1000; i++) {
298 			hash_buf(algos[a], msg, 3 * diglen, digest);
299 			memmove(msg, msg + diglen, 2 * diglen);
300 			memcpy(msg + 2 * diglen, digest, diglen);
301 		}
302 
303 		munit_assert_memory_equal(diglen, digest, known[a]);
304 	}
305 
306 	return (MUNIT_OK);
307 }
308 
309 /*
310  * Split updates across the 64- and 128-byte message block boundaries
311  * must produce the same digest as a single update.
312  */
313 static MunitResult
test_incremental(const MunitParameter params[],void * data)314 test_incremental(const MunitParameter params[], void *data)
315 {
316 	(void) params, (void) data;
317 	fill_data();
318 
319 	static const int algos[] = { SHA256, SHA512, SHA512_256 };
320 	static const size_t diglens[] = { SHA256_DIGEST_LENGTH,
321 	    SHA512_DIGEST_LENGTH, SHA512_256_DIGEST_LENGTH };
322 	static const size_t chunks[] = { 1, 63, 64, 65, 127, 128, 129, 1000 };
323 
324 	for (size_t a = 0; a < ARRAY_SIZE(algos); a++) {
325 		uint8_t once[SHA512_DIGEST_LENGTH];
326 		uint8_t split[SHA512_DIGEST_LENGTH];
327 		SHA2_CTX ctx;
328 		size_t off = 0;
329 
330 		hash_buf(algos[a], databuf, DATA_SIZE, once);
331 
332 		SHA2Init(algos[a], &ctx);
333 		for (size_t c = 0; c < ARRAY_SIZE(chunks); c++) {
334 			SHA2Update(&ctx, databuf + off, chunks[c]);
335 			off += chunks[c];
336 		}
337 		SHA2Update(&ctx, databuf + off, DATA_SIZE - off);
338 		SHA2Final(split, &ctx);
339 
340 		munit_assert_memory_equal(diglens[a], once, split);
341 	}
342 
343 	return (MUNIT_OK);
344 }
345 
346 /*
347  * Every supported implementation must reproduce the known answer and
348  * compute the same digest for a multi-block message.
349  */
350 static MunitResult
test_impls(const MunitParameter params[],void * data)351 test_impls(const MunitParameter params[], void *data)
352 {
353 	(void) params, (void) data;
354 	fill_data();
355 
356 	static const char *const algos[] = { "sha256", "sha512" };
357 	static const int algotypes[] = { SHA256, SHA512 };
358 	static const uint8_t *const known[] = { sha256_test_digests[0],
359 	    sha512_test_digests[0] };
360 	static const size_t diglens[] = { SHA256_DIGEST_LENGTH,
361 	    SHA512_DIGEST_LENGTH };
362 
363 	for (size_t a = 0; a < ARRAY_SIZE(algos); a++) {
364 		const zfs_impl_t *ops = zfs_impl_get_ops(algos[a]);
365 		uint8_t ref[SHA512_DIGEST_LENGTH];
366 		uint8_t digest[SHA512_DIGEST_LENGTH];
367 		uint32_t saved;
368 
369 		unit_true(ops != NULL);
370 		saved = ops->getid();
371 
372 		for (uint32_t id = 0; id < ops->getcnt(); id++) {
373 			ops->setid(id);
374 
375 			hash_buf(algotypes[a], test_msg0, strlen(test_msg0),
376 			    digest);
377 			munit_assert_memory_equal(diglens[a], digest,
378 			    known[a]);
379 
380 			hash_buf(algotypes[a], databuf, DATA_SIZE, digest);
381 			if (id == 0)
382 				memcpy(ref, digest, diglens[a]);
383 			else
384 				munit_assert_memory_equal(diglens[a],
385 				    ref, digest);
386 		}
387 
388 		ops->setid(saved);
389 	}
390 
391 	return (MUNIT_OK);
392 }
393 
394 /* ========== */
395 
396 static const MunitTest sha2_tests[] = {
397 	UNIT_TEST("sha256_known",	test_sha256_known),
398 	UNIT_TEST("sha512_known",	test_sha512_known),
399 	UNIT_TEST("sha512_256_known",	test_sha512_256_known),
400 	UNIT_TEST("million",		test_million),
401 	UNIT_TEST("monte_carlo",	test_monte_carlo),
402 	UNIT_TEST("incremental",	test_incremental),
403 	UNIT_TEST("impls",		test_impls),
404 	{ 0 },
405 };
406 
407 static const MunitSuite sha2_test_suite = {
408 	"sha2.",
409 	sha2_tests,
410 	NULL,
411 	1,
412 	MUNIT_SUITE_OPTION_NONE,
413 };
414 
415 int
main(int argc,char ** argv)416 main(int argc, char **argv)
417 {
418 	return (munit_suite_main(&sha2_test_suite, NULL, argc, argv));
419 }
420