summaryrefslogtreecommitdiff
path: root/include/crypto/gf128hash.h
blob: 41c557d559655471172c9bdb42149db5e698736c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * GF(2^128) polynomial hashing: GHASH and POLYVAL
 *
 * Copyright 2025 Google LLC
 */

#ifndef _CRYPTO_GF128HASH_H
#define _CRYPTO_GF128HASH_H

#include <crypto/ghash.h>
#include <linux/string.h>
#include <linux/types.h>

#define POLYVAL_BLOCK_SIZE	16
#define POLYVAL_DIGEST_SIZE	16

/**
 * struct polyval_elem - An element of the POLYVAL finite field
 * @bytes: View of the element as a byte array (unioned with @lo and @hi)
 * @lo: The low 64 terms of the element's polynomial
 * @hi: The high 64 terms of the element's polynomial
 *
 * This represents an element of the finite field GF(2^128), using the POLYVAL
 * convention: little-endian byte order and natural bit order.
 */
struct polyval_elem {
	union {
		u8 bytes[POLYVAL_BLOCK_SIZE];
		struct {
			__le64 lo;
			__le64 hi;
		};
	};
};

/**
 * struct ghash_key - Prepared key for GHASH
 *
 * Use ghash_preparekey() to initialize this.
 */
struct ghash_key {
#if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && defined(CONFIG_PPC64)
	/** @htable: GHASH key format used by the POWER8 assembly code */
	u64 htable[4][2];
#elif defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \
	(defined(CONFIG_RISCV) || defined(CONFIG_S390))
	/** @h_raw: The hash key H, in GHASH format */
	u8 h_raw[GHASH_BLOCK_SIZE];
#endif
	/** @h: The hash key H, in POLYVAL format */
	struct polyval_elem h;
};

/**
 * struct polyval_key - Prepared key for POLYVAL
 *
 * This may contain just the raw key H, or it may contain precomputed key
 * powers, depending on the platform's POLYVAL implementation.  Use
 * polyval_preparekey() to initialize this.
 *
 * By H^i we mean H^(i-1) * H * x^-128, with base case H^1 = H.  I.e. the
 * exponentiation repeats the POLYVAL dot operation, with its "extra" x^-128.
 */
struct polyval_key {
#if defined(CONFIG_CRYPTO_LIB_GF128HASH_ARCH) && \
	(defined(CONFIG_ARM64) || defined(CONFIG_X86))
	/** @h_powers: Powers of the hash key H^8 through H^1 */
	struct polyval_elem h_powers[8];
#else
	/** @h: The hash key H */
	struct polyval_elem h;
#endif
};

/**
 * struct ghash_ctx - Context for computing a GHASH value
 * @key: Pointer to the prepared GHASH key.  The user of the API is
 *	 responsible for ensuring that the key lives as long as the context.
 * @acc: The accumulator.  It is stored in POLYVAL format rather than GHASH
 *	 format, since most implementations want it in POLYVAL format.
 * @partial: Number of data bytes processed so far modulo GHASH_BLOCK_SIZE
 */
struct ghash_ctx {
	const struct ghash_key *key;
	struct polyval_elem acc;
	size_t partial;
};

/**
 * struct polyval_ctx - Context for computing a POLYVAL value
 * @key: Pointer to the prepared POLYVAL key.  The user of the API is
 *	 responsible for ensuring that the key lives as long as the context.
 * @acc: The accumulator
 * @partial: Number of data bytes processed so far modulo POLYVAL_BLOCK_SIZE
 */
struct polyval_ctx {
	const struct polyval_key *key;
	struct polyval_elem acc;
	size_t partial;
};

/**
 * ghash_preparekey() - Prepare a GHASH key
 * @key: (output) The key structure to initialize
 * @raw_key: The raw hash key
 *
 * Initialize a GHASH key structure from a raw key.
 *
 * Context: Any context.
 */
void ghash_preparekey(struct ghash_key *key,
		      const u8 raw_key[GHASH_BLOCK_SIZE]);

/**
 * polyval_preparekey() - Prepare a POLYVAL key
 * @key: (output) The key structure to initialize
 * @raw_key: The raw hash key
 *
 * Initialize a POLYVAL key structure from a raw key.  This may be a simple
 * copy, or it may involve precomputing powers of the key, depending on the
 * platform's POLYVAL implementation.
 *
 * Context: Any context.
 */
void polyval_preparekey(struct polyval_key *key,
			const u8 raw_key[POLYVAL_BLOCK_SIZE]);

/**
 * ghash_init() - Initialize a GHASH context for a new message
 * @ctx: The context to initialize
 * @key: The key to use.  Note that a pointer to the key is saved in the
 *	 context, so the key must live at least as long as the context.
 */
static inline void ghash_init(struct ghash_ctx *ctx,
			      const struct ghash_key *key)
{
	*ctx = (struct ghash_ctx){ .key = key };
}

/**
 * polyval_init() - Initialize a POLYVAL context for a new message
 * @ctx: The context to initialize
 * @key: The key to use.  Note that a pointer to the key is saved in the
 *	 context, so the key must live at least as long as the context.
 */
static inline void polyval_init(struct polyval_ctx *ctx,
				const struct polyval_key *key)
{
	*ctx = (struct polyval_ctx){ .key = key };
}

/**
 * polyval_import_blkaligned() - Import a POLYVAL accumulator value
 * @ctx: The context to initialize
 * @key: The key to import.  Note that a pointer to the key is saved in the
 *	 context, so the key must live at least as long as the context.
 * @acc: The accumulator value to import.
 *
 * This imports an accumulator that was saved by polyval_export_blkaligned().
 * The same key must be used.
 */
static inline void
polyval_import_blkaligned(struct polyval_ctx *ctx,
			  const struct polyval_key *key,
			  const struct polyval_elem *acc)
{
	*ctx = (struct polyval_ctx){ .key = key, .acc = *acc };
}

/**
 * polyval_export_blkaligned() - Export a POLYVAL accumulator value
 * @ctx: The context to export the accumulator value from
 * @acc: (output) The exported accumulator value
 *
 * This exports the accumulator from a POLYVAL context.  The number of data
 * bytes processed so far must be a multiple of POLYVAL_BLOCK_SIZE.
 */
static inline void polyval_export_blkaligned(const struct polyval_ctx *ctx,
					     struct polyval_elem *acc)
{
	*acc = ctx->acc;
}

/**
 * ghash_update() - Update a GHASH context with message data
 * @ctx: The context to update; must have been initialized
 * @data: The message data
 * @len: The data length in bytes.  Doesn't need to be block-aligned.
 *
 * This can be called any number of times.
 *
 * Context: Any context.
 */
void ghash_update(struct ghash_ctx *ctx, const u8 *data, size_t len);

/**
 * polyval_update() - Update a POLYVAL context with message data
 * @ctx: The context to update; must have been initialized
 * @data: The message data
 * @len: The data length in bytes.  Doesn't need to be block-aligned.
 *
 * This can be called any number of times.
 *
 * Context: Any context.
 */
void polyval_update(struct polyval_ctx *ctx, const u8 *data, size_t len);

/**
 * ghash_final() - Finish computing a GHASH value
 * @ctx: The context to finalize
 * @out: The output value
 *
 * If the total data length isn't a multiple of GHASH_BLOCK_SIZE, then the
 * final block is automatically zero-padded.
 *
 * After finishing, this zeroizes @ctx.  So the caller does not need to do it.
 *
 * Context: Any context.
 */
void ghash_final(struct ghash_ctx *ctx, u8 out[GHASH_BLOCK_SIZE]);

/**
 * polyval_final() - Finish computing a POLYVAL value
 * @ctx: The context to finalize
 * @out: The output value
 *
 * If the total data length isn't a multiple of POLYVAL_BLOCK_SIZE, then the
 * final block is automatically zero-padded.
 *
 * After finishing, this zeroizes @ctx.  So the caller does not need to do it.
 *
 * Context: Any context.
 */
void polyval_final(struct polyval_ctx *ctx, u8 out[POLYVAL_BLOCK_SIZE]);

/**
 * ghash() - Compute a GHASH value
 * @key: The prepared key
 * @data: The message data
 * @len: The data length in bytes.  Doesn't need to be block-aligned.
 * @out: The output value
 *
 * Context: Any context.
 */
static inline void ghash(const struct ghash_key *key, const u8 *data,
			 size_t len, u8 out[GHASH_BLOCK_SIZE])
{
	struct ghash_ctx ctx;

	ghash_init(&ctx, key);
	ghash_update(&ctx, data, len);
	ghash_final(&ctx, out);
}

/**
 * polyval() - Compute a POLYVAL value
 * @key: The prepared key
 * @data: The message data
 * @len: The data length in bytes.  Doesn't need to be block-aligned.
 * @out: The output value
 *
 * Context: Any context.
 */
static inline void polyval(const struct polyval_key *key,
			   const u8 *data, size_t len,
			   u8 out[POLYVAL_BLOCK_SIZE])
{
	struct polyval_ctx ctx;

	polyval_init(&ctx, key);
	polyval_update(&ctx, data, len);
	polyval_final(&ctx, out);
}

#endif /* _CRYPTO_GF128HASH_H */