xref: /linux/lib/crypto/tests/hash-test-template.h (revision f4cdf7ca9a1fdcca413157df19753f388a5a224e)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * Test cases for hash functions, including a benchmark.  This is included by
4  * KUnit test suites that want to use it.  See sha512_kunit.c for an example.
5  *
6  * Copyright 2025 Google LLC
7  */
8 #include <kunit/run-in-irq-context.h>
9 #include <kunit/test.h>
10 #include "test-utils.h"
11 
12 /*
13  * Test the hash function against a list of test vectors.
14  *
15  * Note that it's only necessary to run each test vector in one way (e.g.,
16  * one-shot instead of incremental), since consistency between different ways of
17  * using the APIs is verified by other test cases.
18  */
19 static void test_hash_test_vectors(struct kunit *test)
20 {
21 	const size_t max_len = 16384;
22 	u8 *data = alloc_buf(test, max_len);
23 
24 	for (size_t i = 0; i < ARRAY_SIZE(hash_testvecs); i++) {
25 		size_t data_len = hash_testvecs[i].data_len;
26 		u8 actual_hash[HASH_SIZE];
27 
28 		KUNIT_ASSERT_LE(test, data_len, max_len);
29 		rand_bytes_seeded_from_len(data, data_len);
30 		HASH(data, data_len, actual_hash);
31 		KUNIT_ASSERT_MEMEQ_MSG(
32 			test, actual_hash, hash_testvecs[i].digest, HASH_SIZE,
33 			"Wrong result with test vector %zu; data_len=%zu", i,
34 			data_len);
35 	}
36 }
37 
38 /*
39  * Test that the hash function produces correct results for *every* length up to
40  * 4096 bytes.  To do this, generate seeded random data, then calculate a hash
41  * value for each length 0..4096, then hash the hash values.  Verify just the
42  * final hash value, which should match only when all hash values were correct.
43  */
44 static void test_hash_all_lens_up_to_4096(struct kunit *test)
45 {
46 	const size_t max_len = 4096;
47 	u8 *data = alloc_buf(test, max_len);
48 	struct HASH_CTX ctx;
49 	u8 hash[HASH_SIZE];
50 
51 	rand_bytes_seeded_from_len(data, max_len);
52 	HASH_INIT(&ctx);
53 	for (size_t len = 0; len <= max_len; len++) {
54 		HASH(data, len, hash);
55 		HASH_UPDATE(&ctx, hash, HASH_SIZE);
56 	}
57 	HASH_FINAL(&ctx, hash);
58 	KUNIT_ASSERT_MEMEQ(test, hash, hash_testvec_consolidated, HASH_SIZE);
59 }
60 
61 /*
62  * Test that the hash function produces the same result with a one-shot
63  * computation as it does with an incremental computation.
64  */
65 static void test_hash_incremental_updates(struct kunit *test)
66 {
67 	const size_t max_len = 16384;
68 	u8 *data = alloc_guarded_buf(test, max_len);
69 
70 	for (int i = 0; i < 1000; i++) {
71 		size_t total_len, offset;
72 		struct HASH_CTX ctx;
73 		u8 hash1[HASH_SIZE];
74 		u8 hash2[HASH_SIZE];
75 		size_t num_parts = 0;
76 		size_t remaining_len, cur_offset;
77 
78 		total_len = rand_length(max_len);
79 		offset = rand_offset(max_len - total_len);
80 		rand_bytes(&data[offset], total_len);
81 
82 		/* Compute the hash value in one shot. */
83 		HASH(&data[offset], total_len, hash1);
84 
85 		/*
86 		 * Compute the hash value incrementally, using a randomly
87 		 * selected sequence of update lengths that sum to total_len.
88 		 */
89 		HASH_INIT(&ctx);
90 		remaining_len = total_len;
91 		cur_offset = offset;
92 		while (rand_bool()) {
93 			size_t part_len = rand_length(remaining_len);
94 
95 			HASH_UPDATE(&ctx, &data[cur_offset], part_len);
96 			num_parts++;
97 			cur_offset += part_len;
98 			remaining_len -= part_len;
99 		}
100 		if (remaining_len != 0 || rand_bool()) {
101 			HASH_UPDATE(&ctx, &data[cur_offset], remaining_len);
102 			num_parts++;
103 		}
104 		HASH_FINAL(&ctx, hash2);
105 
106 		/* Verify that the two hash values are the same. */
107 		KUNIT_ASSERT_MEMEQ_MSG(
108 			test, hash1, hash2, HASH_SIZE,
109 			"Incremental test failed with total_len=%zu num_parts=%zu offset=%zu",
110 			total_len, num_parts, offset);
111 	}
112 }
113 
114 /*
115  * Test that the hash function does not overrun any buffers.  Uses a guard page
116  * to catch buffer overruns even if they occur in assembly code.
117  */
118 static void test_hash_buffer_overruns(struct kunit *test)
119 {
120 	const size_t buf_len = 16384;
121 	u8 *buf = alloc_guarded_buf(test, buf_len);
122 	void *const buf_end = &buf[buf_len];
123 	const size_t max_tested_len = buf_len - sizeof(struct HASH_CTX);
124 	struct HASH_CTX *guarded_ctx = buf_end - sizeof(*guarded_ctx);
125 
126 	rand_bytes(buf, buf_len);
127 
128 	for (int i = 0; i < 100; i++) {
129 		size_t len = rand_length(max_tested_len);
130 		struct HASH_CTX ctx;
131 		u8 hash[HASH_SIZE];
132 
133 		/* Check for overruns of the data buffer. */
134 		HASH(buf_end - len, len, hash);
135 		HASH_INIT(&ctx);
136 		HASH_UPDATE(&ctx, buf_end - len, len);
137 		HASH_FINAL(&ctx, hash);
138 
139 		/* Check for overruns of the hash value buffer. */
140 		HASH(buf, len, buf_end - HASH_SIZE);
141 		HASH_INIT(&ctx);
142 		HASH_UPDATE(&ctx, buf, len);
143 		HASH_FINAL(&ctx, buf_end - HASH_SIZE);
144 
145 		/* Check for overruns of the hash context. */
146 		HASH_INIT(guarded_ctx);
147 		HASH_UPDATE(guarded_ctx, buf, len);
148 		HASH_FINAL(guarded_ctx, hash);
149 	}
150 }
151 
152 /*
153  * Test that the caller is permitted to alias the output digest and source data
154  * buffer, and also modify the source data buffer after it has been used.
155  */
156 static void test_hash_overlaps(struct kunit *test)
157 {
158 	const size_t buf_len = 16384;
159 	u8 *buf = alloc_guarded_buf(test, buf_len);
160 	const size_t max_tested_len = buf_len - HASH_SIZE;
161 	struct HASH_CTX ctx;
162 	u8 hash[HASH_SIZE];
163 
164 	rand_bytes(buf, buf_len);
165 
166 	for (int i = 0; i < 100; i++) {
167 		size_t len = rand_length(max_tested_len);
168 		size_t offset = HASH_SIZE + rand_offset(max_tested_len - len);
169 		bool left_end = rand_bool();
170 		u8 *ovl_hash = left_end ? &buf[offset] :
171 					  &buf[offset + len - HASH_SIZE];
172 
173 		HASH(&buf[offset], len, hash);
174 		HASH(&buf[offset], len, ovl_hash);
175 		KUNIT_ASSERT_MEMEQ_MSG(
176 			test, hash, ovl_hash, HASH_SIZE,
177 			"Overlap test 1 failed with len=%zu offset=%zu left_end=%d",
178 			len, offset, left_end);
179 
180 		/* Repeat the above test, but this time use init+update+final */
181 		HASH(&buf[offset], len, hash);
182 		HASH_INIT(&ctx);
183 		HASH_UPDATE(&ctx, &buf[offset], len);
184 		HASH_FINAL(&ctx, ovl_hash);
185 		KUNIT_ASSERT_MEMEQ_MSG(
186 			test, hash, ovl_hash, HASH_SIZE,
187 			"Overlap test 2 failed with len=%zu offset=%zu left_end=%d",
188 			len, offset, left_end);
189 
190 		/* Test modifying the source data after it was used. */
191 		HASH(&buf[offset], len, hash);
192 		HASH_INIT(&ctx);
193 		HASH_UPDATE(&ctx, &buf[offset], len);
194 		rand_bytes(&buf[offset], len);
195 		HASH_FINAL(&ctx, ovl_hash);
196 		KUNIT_ASSERT_MEMEQ_MSG(
197 			test, hash, ovl_hash, HASH_SIZE,
198 			"Overlap test 3 failed with len=%zu offset=%zu left_end=%d",
199 			len, offset, left_end);
200 	}
201 }
202 
203 /*
204  * Test that if the same data is hashed at different alignments in memory, the
205  * results are the same.
206  */
207 static void test_hash_alignment_consistency(struct kunit *test)
208 {
209 	const size_t max_len = 16384;
210 	u8 *data = alloc_guarded_buf(test, max_len);
211 	u8 hash1[128 + HASH_SIZE];
212 	u8 hash2[128 + HASH_SIZE];
213 
214 	for (int i = 0; i < 100; i++) {
215 		size_t len = rand_length(max_len);
216 		size_t data_offs1 = rand_offset(max_len - len);
217 		size_t data_offs2 = rand_offset(max_len - len);
218 		size_t hash_offs1 = rand_offset(128);
219 		size_t hash_offs2 = rand_offset(128);
220 
221 		rand_bytes(&data[data_offs1], len);
222 		HASH(&data[data_offs1], len, &hash1[hash_offs1]);
223 		memmove(&data[data_offs2], &data[data_offs1], len);
224 		HASH(&data[data_offs2], len, &hash2[hash_offs2]);
225 		KUNIT_ASSERT_MEMEQ_MSG(
226 			test, &hash1[hash_offs1], &hash2[hash_offs2], HASH_SIZE,
227 			"Alignment consistency test failed with len=%zu data_offs=(%zu,%zu) hash_offs=(%zu,%zu)",
228 			len, data_offs1, data_offs2, hash_offs1, hash_offs2);
229 	}
230 }
231 
232 /* Test that HASH_FINAL zeroizes the context. */
233 static void test_hash_ctx_zeroization(struct kunit *test)
234 {
235 	static const u8 zeroes[sizeof(struct HASH_CTX)];
236 	struct HASH_CTX ctx;
237 	const size_t data_len = 128;
238 	u8 *data = alloc_buf(test, data_len);
239 	u8 hash[HASH_SIZE];
240 
241 	rand_bytes(data, data_len);
242 	HASH_INIT(&ctx);
243 	HASH_UPDATE(&ctx, data, data_len);
244 	HASH_FINAL(&ctx, hash);
245 	KUNIT_ASSERT_MEMEQ_MSG(test, &ctx, zeroes, sizeof(ctx),
246 			       "Hash context was not zeroized by finalization");
247 }
248 
249 #define IRQ_TEST_DATA_LEN 256
250 #define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */
251 
252 struct hash_irq_test1_state {
253 	u8 *data;
254 	u8 expected_hashes[IRQ_TEST_NUM_BUFFERS][HASH_SIZE];
255 	atomic_t seqno;
256 };
257 
258 /*
259  * Compute the hash of one of the test messages and verify that it matches the
260  * expected hash from @state->expected_hashes.  To increase the chance of
261  * detecting problems, cycle through multiple messages.
262  */
263 static bool hash_irq_test1_func(void *state_)
264 {
265 	struct hash_irq_test1_state *state = state_;
266 	u32 i = (u32)atomic_inc_return(&state->seqno) % IRQ_TEST_NUM_BUFFERS;
267 	u8 actual_hash[HASH_SIZE];
268 
269 	HASH(&state->data[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN,
270 	     actual_hash);
271 	return memcmp(actual_hash, state->expected_hashes[i], HASH_SIZE) == 0;
272 }
273 
274 /*
275  * Test that if hashes are computed in task, softirq, and hardirq context
276  * concurrently, then all results are as expected.
277  */
278 static void test_hash_interrupt_context_1(struct kunit *test)
279 {
280 	const size_t total_data_len = IRQ_TEST_NUM_BUFFERS * IRQ_TEST_DATA_LEN;
281 	struct hash_irq_test1_state state = {};
282 
283 	/* Prepare some test messages and compute the expected hash of each. */
284 	state.data = alloc_buf(test, total_data_len);
285 	rand_bytes(state.data, total_data_len);
286 	for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++)
287 		HASH(&state.data[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN,
288 		     state.expected_hashes[i]);
289 
290 	kunit_run_irq_test(test, hash_irq_test1_func, 100000, &state);
291 }
292 
293 struct hash_irq_test2_hash_ctx {
294 	struct HASH_CTX hash_ctx;
295 	atomic_t in_use;
296 	int offset;
297 	int step;
298 };
299 
300 struct hash_irq_test2_state {
301 	u8 *data;
302 	size_t data_len;
303 	struct hash_irq_test2_hash_ctx ctxs[IRQ_TEST_NUM_BUFFERS];
304 	u8 expected_hash[HASH_SIZE];
305 	u16 update_lens[32];
306 	int num_steps;
307 };
308 
309 static bool hash_irq_test2_func(void *state_)
310 {
311 	struct hash_irq_test2_state *state = state_;
312 	struct hash_irq_test2_hash_ctx *ctx;
313 	bool ret = true;
314 
315 	for (ctx = &state->ctxs[0]; ctx < &state->ctxs[ARRAY_SIZE(state->ctxs)];
316 	     ctx++) {
317 		if (atomic_cmpxchg(&ctx->in_use, 0, 1) == 0)
318 			break;
319 	}
320 	if (WARN_ON_ONCE(ctx == &state->ctxs[ARRAY_SIZE(state->ctxs)])) {
321 		/*
322 		 * This should never happen, as the number of contexts is equal
323 		 * to the maximum concurrency level of kunit_run_irq_test().
324 		 */
325 		return false;
326 	}
327 
328 	if (ctx->step == 0) {
329 		/* Init step */
330 		HASH_INIT(&ctx->hash_ctx);
331 		ctx->offset = 0;
332 		ctx->step++;
333 	} else if (ctx->step < state->num_steps - 1) {
334 		/* Update step */
335 		HASH_UPDATE(&ctx->hash_ctx, &state->data[ctx->offset],
336 			    state->update_lens[ctx->step - 1]);
337 		ctx->offset += state->update_lens[ctx->step - 1];
338 		ctx->step++;
339 	} else {
340 		/* Final step */
341 		u8 actual_hash[HASH_SIZE];
342 
343 		if (WARN_ON_ONCE(ctx->offset != state->data_len))
344 			ret = false;
345 		HASH_FINAL(&ctx->hash_ctx, actual_hash);
346 		if (memcmp(actual_hash, state->expected_hash, HASH_SIZE) != 0)
347 			ret = false;
348 		ctx->step = 0;
349 	}
350 	atomic_set_release(&ctx->in_use, 0);
351 	return ret;
352 }
353 
354 /*
355  * Test that if hashes are computed in task, softirq, and hardirq context
356  * concurrently, *including doing different parts of the same incremental
357  * computation in different contexts*, then all results are as expected.
358  * Besides detecting bugs similar to those that test_hash_interrupt_context_1
359  * can detect, this test case can also detect bugs where hash function
360  * implementations don't correctly handle these mixed incremental computations.
361  */
362 static void test_hash_interrupt_context_2(struct kunit *test)
363 {
364 	const size_t data_len = 16384;
365 	struct hash_irq_test2_state *state;
366 	size_t remaining = data_len;
367 
368 	state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL);
369 	KUNIT_ASSERT_NOT_NULL(test, state);
370 	state->data_len = data_len;
371 	state->data = alloc_buf(test, data_len);
372 
373 	rand_bytes(state->data, data_len);
374 	HASH(state->data, data_len, state->expected_hash);
375 
376 	/*
377 	 * Generate a list of update lengths to use.  Ensure that it contains
378 	 * multiple entries but is limited to a maximum length.
379 	 */
380 	KUNIT_ASSERT_GT(test, data_len / 4096, 1);
381 	for (state->num_steps = 0;
382 	     state->num_steps < ARRAY_SIZE(state->update_lens) - 1 && remaining;
383 	     state->num_steps++) {
384 		state->update_lens[state->num_steps] =
385 			rand_length(min(remaining, 4096));
386 		remaining -= state->update_lens[state->num_steps];
387 	}
388 	if (remaining)
389 		state->update_lens[state->num_steps++] = remaining;
390 	state->num_steps += 2; /* for init and final */
391 
392 	kunit_run_irq_test(test, hash_irq_test2_func, 250000, state);
393 }
394 
395 #define UNKEYED_HASH_KUNIT_CASES                     \
396 	KUNIT_CASE(test_hash_test_vectors),          \
397 	KUNIT_CASE(test_hash_all_lens_up_to_4096),   \
398 	KUNIT_CASE(test_hash_incremental_updates),   \
399 	KUNIT_CASE(test_hash_buffer_overruns),       \
400 	KUNIT_CASE(test_hash_overlaps),              \
401 	KUNIT_CASE(test_hash_alignment_consistency), \
402 	KUNIT_CASE(test_hash_ctx_zeroization),       \
403 	KUNIT_CASE(test_hash_interrupt_context_1),   \
404 	KUNIT_CASE(test_hash_interrupt_context_2)
405 /* benchmark_hash is omitted so that the suites can put it last. */
406 
407 #ifdef HMAC
408 /*
409  * Test the corresponding HMAC variant.
410  *
411  * This test case is fairly short, since HMAC is just a simple C wrapper around
412  * the underlying unkeyed hash function, which is already well-tested by the
413  * other test cases.  It's not useful to test things like data alignment or
414  * interrupt context again for HMAC, nor to have a long list of test vectors.
415  *
416  * Thus, just do a single consolidated test, which covers all data lengths up to
417  * 4096 bytes and all key lengths up to 292 bytes.  For each data length, select
418  * a key length, generate the inputs from a seed, and compute the HMAC value.
419  * Concatenate all these HMAC values together, and compute the HMAC of that.
420  * Verify that value.  If this fails, then the HMAC implementation is wrong.
421  * This won't show which specific input failed, but that should be fine.  Any
422  * failure would likely be non-input-specific or also show in the unkeyed tests.
423  */
424 static void test_hmac(struct kunit *test)
425 {
426 	const size_t max_data_len = 4096;
427 	const size_t max_key_len = 293;
428 	const size_t outer_key_len = 32;
429 	u8 *data = alloc_guarded_buf(test, max_data_len);
430 	u8 *raw_key = alloc_guarded_buf(test, max_key_len);
431 	static const u8 zeroes[sizeof(struct HMAC_CTX)];
432 	struct HMAC_KEY key;
433 	struct HMAC_CTX ctx;
434 	u8 mac[HASH_SIZE];
435 	u8 mac2[HASH_SIZE];
436 
437 	rand_bytes_seeded_from_len(data, max_data_len);
438 	rand_bytes_seeded_from_len(raw_key, outer_key_len);
439 
440 	HMAC_PREPAREKEY(&key, raw_key, outer_key_len);
441 	HMAC_INIT(&ctx, &key);
442 	for (size_t data_len = 0; data_len <= max_data_len; data_len++) {
443 		/*
444 		 * Cycle through key lengths as well.  Somewhat arbitrarily go
445 		 * up to 293, which is somewhat larger than the largest hash
446 		 * block size (which is the size at which the key starts being
447 		 * hashed down to one block); going higher would not be useful.
448 		 * To reduce correlation with data_len, use a prime number here.
449 		 */
450 		size_t key_len = data_len % max_key_len;
451 
452 		HMAC_UPDATE(&ctx, data, data_len);
453 
454 		rand_bytes_seeded_from_len(raw_key, key_len);
455 		HMAC_USINGRAWKEY(raw_key, key_len, data, data_len, mac);
456 		HMAC_UPDATE(&ctx, mac, HASH_SIZE);
457 
458 		/* Verify that HMAC() is consistent with HMAC_USINGRAWKEY(). */
459 		HMAC_PREPAREKEY(&key, raw_key, key_len);
460 		HMAC(&key, data, data_len, mac2);
461 		KUNIT_ASSERT_MEMEQ_MSG(
462 			test, mac, mac2, HASH_SIZE,
463 			"HMAC gave different results with raw and prepared keys");
464 	}
465 	HMAC_FINAL(&ctx, mac);
466 	KUNIT_EXPECT_MEMEQ_MSG(test, mac, hmac_testvec_consolidated, HASH_SIZE,
467 			       "HMAC gave wrong result");
468 	KUNIT_EXPECT_MEMEQ_MSG(test, &ctx, zeroes, sizeof(ctx),
469 			       "HMAC context was not zeroized by finalization");
470 }
471 #define HASH_KUNIT_CASES UNKEYED_HASH_KUNIT_CASES, KUNIT_CASE(test_hmac)
472 #else
473 #define HASH_KUNIT_CASES UNKEYED_HASH_KUNIT_CASES
474 #endif
475 
476 /* Benchmark the hash function on various data lengths. */
477 static void benchmark_hash(struct kunit *test)
478 {
479 	static const size_t lens_to_test[] = {
480 		1,   16,  64,	127,  128,  200,   256,
481 		511, 512, 1024, 3173, 4096, 16384,
482 	};
483 	const size_t max_len = 16384;
484 	u8 *data = alloc_buf(test, max_len);
485 	u8 hash[HASH_SIZE];
486 
487 	if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
488 		kunit_skip(test, "not enabled");
489 
490 	/* Warm-up */
491 	memset(data, 0, max_len);
492 	for (size_t i = 0; i < 10000000; i += max_len)
493 		HASH(data, max_len, hash);
494 
495 	for (size_t i = 0; i < ARRAY_SIZE(lens_to_test); i++) {
496 		size_t len = lens_to_test[i];
497 		/* The '+ 128' tries to account for per-message overhead. */
498 		size_t num_iters = 10000000 / (len + 128);
499 		u64 t;
500 
501 		KUNIT_ASSERT_LE(test, len, max_len);
502 		preempt_disable();
503 		t = ktime_get_ns();
504 		for (size_t j = 0; j < num_iters; j++)
505 			HASH(data, len, hash);
506 		t = ktime_get_ns() - t;
507 		preempt_enable();
508 		kunit_info(test, "len=%zu: %llu MB/s", len,
509 			   div64_u64((u64)len * num_iters * 1000, t ?: 1));
510 	}
511 }
512