File Index
Files and directories
Sign in
FILE

sha256_kunit.c

File preview with syntax highlighting.

linux-6.19.14/lib/crypto/tests/sha256_kunit.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright 2025 Google LLC
  4 */
  5#include <crypto/sha2.h>
  6#include "sha256-testvecs.h"
  7
  8/* Generate the HASH_KUNIT_CASES using hash-test-template.h. */
  9#define HASH sha256
 10#define HASH_CTX sha256_ctx
 11#define HASH_SIZE SHA256_DIGEST_SIZE
 12#define HASH_INIT sha256_init
 13#define HASH_UPDATE sha256_update
 14#define HASH_FINAL sha256_final
 15#define HMAC_KEY hmac_sha256_key
 16#define HMAC_CTX hmac_sha256_ctx
 17#define HMAC_PREPAREKEY hmac_sha256_preparekey
 18#define HMAC_INIT hmac_sha256_init
 19#define HMAC_UPDATE hmac_sha256_update
 20#define HMAC_FINAL hmac_sha256_final
 21#define HMAC hmac_sha256
 22#define HMAC_USINGRAWKEY hmac_sha256_usingrawkey
 23#include "hash-test-template.h"
 24
 25static void free_guarded_buf(void *buf)
 26{
 27	vfree(buf);
 28}
 29
 30/*
 31 * Allocate a KUnit-managed buffer that has length @len bytes immediately
 32 * followed by an unmapped page, and assert that the allocation succeeds.
 33 */
 34static void *alloc_guarded_buf(struct kunit *test, size_t len)
 35{
 36	size_t full_len = round_up(len, PAGE_SIZE);
 37	void *buf = vmalloc(full_len);
 38
 39	KUNIT_ASSERT_NOT_NULL(test, buf);
 40	KUNIT_ASSERT_EQ(test, 0,
 41			kunit_add_action_or_reset(test, free_guarded_buf, buf));
 42	return buf + full_len - len;
 43}
 44
 45/*
 46 * Test for sha256_finup_2x().  Specifically, choose various data lengths and
 47 * salt lengths, and for each one, verify that sha256_finup_2x() produces the
 48 * same results as sha256_update() and sha256_final().
 49 *
 50 * Use guarded buffers for all inputs and outputs to reliably detect any
 51 * out-of-bounds reads or writes, even if they occur in assembly code.
 52 */
 53static void test_sha256_finup_2x(struct kunit *test)
 54{
 55	const size_t max_data_len = 16384;
 56	u8 *data1_buf, *data2_buf, *hash1, *hash2;
 57	u8 expected_hash1[SHA256_DIGEST_SIZE];
 58	u8 expected_hash2[SHA256_DIGEST_SIZE];
 59	u8 salt[SHA256_BLOCK_SIZE];
 60	struct sha256_ctx *ctx;
 61
 62	data1_buf = alloc_guarded_buf(test, max_data_len);
 63	data2_buf = alloc_guarded_buf(test, max_data_len);
 64	hash1 = alloc_guarded_buf(test, SHA256_DIGEST_SIZE);
 65	hash2 = alloc_guarded_buf(test, SHA256_DIGEST_SIZE);
 66	ctx = alloc_guarded_buf(test, sizeof(*ctx));
 67
 68	rand_bytes(data1_buf, max_data_len);
 69	rand_bytes(data2_buf, max_data_len);
 70	rand_bytes(salt, sizeof(salt));
 71	memset(ctx, 0, sizeof(*ctx));
 72
 73	for (size_t i = 0; i < 500; i++) {
 74		size_t salt_len = rand_length(sizeof(salt));
 75		size_t data_len = rand_length(max_data_len);
 76		const u8 *data1 = data1_buf + max_data_len - data_len;
 77		const u8 *data2 = data2_buf + max_data_len - data_len;
 78		struct sha256_ctx orig_ctx;
 79
 80		sha256_init(ctx);
 81		sha256_update(ctx, salt, salt_len);
 82		orig_ctx = *ctx;
 83
 84		sha256_finup_2x(ctx, data1, data2, data_len, hash1, hash2);
 85		KUNIT_ASSERT_MEMEQ_MSG(
 86			test, ctx, &orig_ctx, sizeof(*ctx),
 87			"sha256_finup_2x() modified its ctx argument");
 88
 89		sha256_update(ctx, data1, data_len);
 90		sha256_final(ctx, expected_hash1);
 91		sha256_update(&orig_ctx, data2, data_len);
 92		sha256_final(&orig_ctx, expected_hash2);
 93		KUNIT_ASSERT_MEMEQ_MSG(
 94			test, hash1, expected_hash1, SHA256_DIGEST_SIZE,
 95			"Wrong hash1 with salt_len=%zu data_len=%zu", salt_len,
 96			data_len);
 97		KUNIT_ASSERT_MEMEQ_MSG(
 98			test, hash2, expected_hash2, SHA256_DIGEST_SIZE,
 99			"Wrong hash2 with salt_len=%zu data_len=%zu", salt_len,
100			data_len);
101	}
102}
103
104/* Test sha256_finup_2x() with ctx == NULL */
105static void test_sha256_finup_2x_defaultctx(struct kunit *test)
106{
107	const size_t data_len = 128;
108	struct sha256_ctx ctx;
109	u8 hash1_a[SHA256_DIGEST_SIZE];
110	u8 hash2_a[SHA256_DIGEST_SIZE];
111	u8 hash1_b[SHA256_DIGEST_SIZE];
112	u8 hash2_b[SHA256_DIGEST_SIZE];
113
114	rand_bytes(test_buf, 2 * data_len);
115
116	sha256_init(&ctx);
117	sha256_finup_2x(&ctx, test_buf, &test_buf[data_len], data_len, hash1_a,
118			hash2_a);
119
120	sha256_finup_2x(NULL, test_buf, &test_buf[data_len], data_len, hash1_b,
121			hash2_b);
122
123	KUNIT_ASSERT_MEMEQ(test, hash1_a, hash1_b, SHA256_DIGEST_SIZE);
124	KUNIT_ASSERT_MEMEQ(test, hash2_a, hash2_b, SHA256_DIGEST_SIZE);
125}
126
127/*
128 * Test that sha256_finup_2x() and sha256_update/final() produce consistent
129 * results with total message lengths that require more than 32 bits.
130 */
131static void test_sha256_finup_2x_hugelen(struct kunit *test)
132{
133	const size_t data_len = 4 * SHA256_BLOCK_SIZE;
134	struct sha256_ctx ctx = {};
135	u8 expected_hash[SHA256_DIGEST_SIZE];
136	u8 hash[SHA256_DIGEST_SIZE];
137
138	rand_bytes(test_buf, data_len);
139	for (size_t align = 0; align < SHA256_BLOCK_SIZE; align++) {
140		sha256_init(&ctx);
141		ctx.ctx.bytecount = 0x123456789abcd00 + align;
142
143		sha256_finup_2x(&ctx, test_buf, test_buf, data_len, hash, hash);
144
145		sha256_update(&ctx, test_buf, data_len);
146		sha256_final(&ctx, expected_hash);
147
148		KUNIT_ASSERT_MEMEQ(test, hash, expected_hash,
149				   SHA256_DIGEST_SIZE);
150	}
151}
152
153/* Benchmark for sha256_finup_2x() */
154static void benchmark_sha256_finup_2x(struct kunit *test)
155{
156	/*
157	 * Try a few different salt lengths, since sha256_finup_2x() performance
158	 * may vary slightly for the same data_len depending on how many bytes
159	 * were already processed in the initial context.
160	 */
161	static const size_t salt_lens_to_test[] = { 0, 32, 64 };
162	const size_t data_len = 4096;
163	const size_t num_iters = 4096;
164	struct sha256_ctx ctx;
165	u8 hash1[SHA256_DIGEST_SIZE];
166	u8 hash2[SHA256_DIGEST_SIZE];
167
168	if (!IS_ENABLED(CONFIG_CRYPTO_LIB_BENCHMARK))
169		kunit_skip(test, "not enabled");
170	if (!sha256_finup_2x_is_optimized())
171		kunit_skip(test, "not relevant");
172
173	rand_bytes(test_buf, data_len * 2);
174
175	/* Warm-up */
176	for (size_t i = 0; i < num_iters; i++)
177		sha256_finup_2x(NULL, &test_buf[0], &test_buf[data_len],
178				data_len, hash1, hash2);
179
180	for (size_t i = 0; i < ARRAY_SIZE(salt_lens_to_test); i++) {
181		size_t salt_len = salt_lens_to_test[i];
182		u64 t0, t1;
183
184		/*
185		 * Prepare the initial context.  The time to process the salt is
186		 * not measured; we're just interested in sha256_finup_2x().
187		 */
188		sha256_init(&ctx);
189		sha256_update(&ctx, test_buf, salt_len);
190
191		preempt_disable();
192		t0 = ktime_get_ns();
193		for (size_t j = 0; j < num_iters; j++)
194			sha256_finup_2x(&ctx, &test_buf[0], &test_buf[data_len],
195					data_len, hash1, hash2);
196		t1 = ktime_get_ns();
197		preempt_enable();
198		kunit_info(test, "data_len=%zu salt_len=%zu: %llu MB/s",
199			   data_len, salt_len,
200			   div64_u64((u64)data_len * 2 * num_iters * 1000,
201				     t1 - t0 ?: 1));
202	}
203}
204
205static struct kunit_case hash_test_cases[] = {
206	HASH_KUNIT_CASES,
207	KUNIT_CASE(test_sha256_finup_2x),
208	KUNIT_CASE(test_sha256_finup_2x_defaultctx),
209	KUNIT_CASE(test_sha256_finup_2x_hugelen),
210	KUNIT_CASE(benchmark_hash),
211	KUNIT_CASE(benchmark_sha256_finup_2x),
212	{},
213};
214
215static struct kunit_suite hash_test_suite = {
216	.name = "sha256",
217	.test_cases = hash_test_cases,
218	.suite_init = hash_suite_init,
219	.suite_exit = hash_suite_exit,
220};
221kunit_test_suite(hash_test_suite);
222
223MODULE_DESCRIPTION("KUnit tests and benchmark for SHA-256 and HMAC-SHA256");
224MODULE_LICENSE("GPL");
~/ Read-only file preview.