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