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