projects/linux·blob master · refs

189 lines · 5.6 KiB

1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2026 Google LLC
4 */
5#include <crypto/gf128hash.h>
6#include "ghash-testvecs.h"
7
8/*
9 * A fixed key used when presenting GHASH as an unkeyed hash function in order
10 * to reuse hash-test-template.h. At the beginning of the test suite, this is
11 * initialized to a key prepared from bytes generated from a fixed seed.
12 */
13static struct ghash_key test_key;
14
15static void ghash_init_withtestkey(struct ghash_ctx *ctx)
16{
17 ghash_init(ctx, &test_key);
18}
19
20static void ghash_withtestkey(const u8 *data, size_t len,
21 u8 out[GHASH_BLOCK_SIZE])
22{
23 ghash(&test_key, data, len, out);
24}
25
26/* Generate the HASH_KUNIT_CASES using hash-test-template.h. */
27#define HASH ghash_withtestkey
28#define HASH_CTX ghash_ctx
29#define HASH_SIZE GHASH_BLOCK_SIZE
30#define HASH_INIT ghash_init_withtestkey
31#define HASH_UPDATE ghash_update
32#define HASH_FINAL ghash_final
33#include "hash-test-template.h"
34
35/*
36 * Test a key and messages containing all one bits. This is useful to detect
37 * overflow bugs in implementations that emulate carryless multiplication using
38 * a series of standard multiplications with the bits spread out.
39 */
40static void test_ghash_allones_key_and_message(struct kunit *test)
41{
42 const size_t max_len = 4096;
43 u8 *data = alloc_buf(test, max_len);
44 struct ghash_key key;
45 struct ghash_ctx hashofhashes_ctx;
46 u8 hash[GHASH_BLOCK_SIZE];
47
48 memset(data, 0xff, max_len);
49
50 ghash_preparekey(&key, data);
51 ghash_init(&hashofhashes_ctx, &key);
52 for (size_t len = 0; len <= max_len; len += 16) {
53 ghash(&key, data, len, hash);
54 ghash_update(&hashofhashes_ctx, hash, sizeof(hash));
55 }
56 ghash_final(&hashofhashes_ctx, hash);
57 KUNIT_ASSERT_MEMEQ(test, hash, ghash_allones_hashofhashes,
58 sizeof(hash));
59}
60
61#define MAX_LEN_FOR_KEY_CHECK 1024
62
63/*
64 * Given two prepared keys which should be identical (but may differ in
65 * alignment and/or whether they are followed by a guard page or not), verify
66 * that they produce consistent results on various data lengths.
67 */
68static void check_key_consistency(struct kunit *test,
69 const struct ghash_key *key1,
70 const struct ghash_key *key2)
71{
72 u8 *data = alloc_buf(test, MAX_LEN_FOR_KEY_CHECK);
73 u8 hash1[GHASH_BLOCK_SIZE];
74 u8 hash2[GHASH_BLOCK_SIZE];
75
76 rand_bytes(data, MAX_LEN_FOR_KEY_CHECK);
77 KUNIT_ASSERT_MEMEQ(test, key1, key2, sizeof(*key1));
78
79 for (int i = 0; i < 100; i++) {
80 size_t len = rand_length(MAX_LEN_FOR_KEY_CHECK);
81
82 ghash(key1, data, len, hash1);
83 ghash(key2, data, len, hash2);
84 KUNIT_ASSERT_MEMEQ(test, hash1, hash2, sizeof(hash1));
85 }
86}
87
88/* Test that no buffer overreads occur on either raw_key or ghash_key. */
89static void test_ghash_with_guarded_key(struct kunit *test)
90{
91 u8 raw_key[GHASH_BLOCK_SIZE];
92 u8 *guarded_raw_key = alloc_guarded_buf(test, sizeof(raw_key));
93 struct ghash_key key1, key2;
94 struct ghash_key *guarded_key =
95 alloc_guarded_buf(test, sizeof(*guarded_key));
96
97 /* Prepare with regular buffers. */
98 rand_bytes(raw_key, sizeof(raw_key));
99 ghash_preparekey(&key1, raw_key);
100
101 /* Prepare with guarded raw_key, then check that it works. */
102 memcpy(guarded_raw_key, raw_key, sizeof(raw_key));
103 ghash_preparekey(&key2, guarded_raw_key);
104 check_key_consistency(test, &key1, &key2);
105
106 /* Prepare guarded ghash_key, then check that it works. */
107 ghash_preparekey(guarded_key, raw_key);
108 check_key_consistency(test, &key1, guarded_key);
109}
110
111/*
112 * Test that ghash_key only needs to be aligned to
113 * __alignof__(struct ghash_key), i.e. 8 bytes. The assembly code may prefer
114 * 16-byte or higher alignment, but it mustn't require it.
115 */
116static void test_ghash_with_minimally_aligned_key(struct kunit *test)
117{
118 u8 raw_key[GHASH_BLOCK_SIZE];
119 struct ghash_key key;
120 const size_t align = __alignof__(struct ghash_key);
121 u8 *key_buf = alloc_buf(test, sizeof(struct ghash_key) + 3 * align);
122 struct ghash_key *minaligned_key =
123 (struct ghash_key *)(PTR_ALIGN(key_buf, 2 * align) + align);
124
125 KUNIT_ASSERT_TRUE(test, IS_ALIGNED((uintptr_t)minaligned_key, align));
126 KUNIT_ASSERT_TRUE(test,
127 !IS_ALIGNED((uintptr_t)minaligned_key, 2 * align));
128
129 rand_bytes(raw_key, sizeof(raw_key));
130 ghash_preparekey(&key, raw_key);
131 ghash_preparekey(minaligned_key, raw_key);
132 check_key_consistency(test, &key, minaligned_key);
133}
134
135struct ghash_irq_test_state {
136 struct ghash_key expected_key;
137 u8 raw_key[GHASH_BLOCK_SIZE];
138};
139
140static bool ghash_irq_test_func(void *state_)
141{
142 struct ghash_irq_test_state *state = state_;
143 struct ghash_key key;
144
145 ghash_preparekey(&key, state->raw_key);
146 return memcmp(&key, &state->expected_key, sizeof(key)) == 0;
147}
148
149/*
150 * Test that ghash_preparekey() produces the same output regardless of whether
151 * FPU or vector registers are usable when it is called.
152 */
153static void test_ghash_preparekey_in_irqs(struct kunit *test)
154{
155 struct ghash_irq_test_state state;
156
157 rand_bytes(state.raw_key, sizeof(state.raw_key));
158 ghash_preparekey(&state.expected_key, state.raw_key);
159 kunit_run_irq_test(test, ghash_irq_test_func, 200000, &state);
160}
161
162static int ghash_suite_init(struct kunit_suite *suite)
163{
164 u8 raw_key[GHASH_BLOCK_SIZE];
165
166 rand_bytes_seeded_from_len(raw_key, sizeof(raw_key));
167 ghash_preparekey(&test_key, raw_key);
168 return 0;
169}
170
171static struct kunit_case ghash_test_cases[] = {
172 HASH_KUNIT_CASES,
173 KUNIT_CASE(test_ghash_allones_key_and_message),
174 KUNIT_CASE(test_ghash_with_guarded_key),
175 KUNIT_CASE(test_ghash_with_minimally_aligned_key),
176 KUNIT_CASE(test_ghash_preparekey_in_irqs),
177 KUNIT_CASE(benchmark_hash),
178 {},
179};
180
181static struct kunit_suite ghash_test_suite = {
182 .name = "ghash",
183 .test_cases = ghash_test_cases,
184 .suite_init = ghash_suite_init,
185};
186kunit_test_suite(ghash_test_suite);
187
188MODULE_DESCRIPTION("KUnit tests and benchmark for GHASH");
189MODULE_LICENSE("GPL");