summaryrefslogtreecommitdiff
path: root/board/cr50/dcrypto/hmacsha2.h
blob: 6d9c842c1ed8f02fe0c48a15ee724211e9858dc7 (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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
/* Copyright 2021 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#pragma once
#include "common.h"

#define SHA1_DIGEST_SIZE 20
#define SHA_DIGEST_SIZE	 SHA1_DIGEST_SIZE

#define SHA224_DIGEST_SIZE  28
#define SHA256_DIGEST_SIZE  32
#define SHA1_BLOCK_SIZE	    64
#define SHA1_BLOCK_WORDS    (SHA1_BLOCK_SIZE / sizeof(uint32_t))
#define SHA1_BLOCK_DWORDS   (SHA1_BLOCK_SIZE / sizeof(uint64_t))
#define SHA1_DIGEST_WORDS   (SHA1_DIGEST_SIZE / sizeof(uint32_t))
#define SHA224_BLOCK_SIZE   64
#define SHA224_BLOCK_WORDS  (SHA224_BLOCK_SIZE / sizeof(uint32_t))
#define SHA224_BLOCK_DWORDS (SHA224_BLOCK_SIZE / sizeof(uint64_t))
#define SHA224_DIGEST_WORDS (SHA224_DIGEST_SIZE / sizeof(uint32_t))
#define SHA256_BLOCK_SIZE   64
#define SHA256_BLOCK_WORDS  (SHA256_BLOCK_SIZE / sizeof(uint32_t))
#define SHA256_BLOCK_DWORDS (SHA256_BLOCK_SIZE / sizeof(uint64_t))
#define SHA256_DIGEST_WORDS (SHA256_DIGEST_SIZE / sizeof(uint32_t))

/**
 * Hash contexts. Each context starts with pointer to vtable containing
 * functions to perform implementation specific operations.
 * It is designed to support both software and hardware implementations.
 * Contexts for different digest types can overlap, but vtable stores
 * actual size of context which enables stack-efficient implementation of
 * HMAC - say HMAC SHA2-256 shouldn't reserve space as for HMAC SHA2-512.
 */
union hash_ctx; /* forward declaration of generic hash context type */
union hmac_ctx; /* forward declaration of generic HMAC context type */

union sha_digests; /* forward declaration of generic digest type */

/* Combined HASH & HMAC vtable to support SW & HW implementations. */
struct hash_vtable {
	/* SHA init function, used primarily by SW HMAC implementation. */
	void (*const init)(union hash_ctx *const);
	/* Update function for SHA & HMAC, assuming it's the same. */
	void (*const update)(union hash_ctx *const, const void *, size_t);
	/* SHA final function, digest specific. */
	const union sha_digests *(*const final)(union hash_ctx *const);

	/* HW HMAC support may require special ending. */
	const union sha_digests *(*const hmac_final)(union hmac_ctx *const);

	/* Digest size of in bytes. */
	size_t digest_size;

	/* Digest block size in bytes. */
	size_t block_size;

	/* Offset of first byte after context, used for HMAC */
	size_t context_size;
};

struct sha256_digest {
	union {
		uint8_t b8[SHA256_DIGEST_SIZE];
		uint32_t b32[SHA256_DIGEST_WORDS];
	};
};
BUILD_ASSERT(sizeof(struct sha256_digest) == SHA256_DIGEST_SIZE);

struct sha224_digest {
	union {
		uint8_t b8[SHA224_DIGEST_SIZE];
		uint32_t b32[SHA224_DIGEST_WORDS];
	};
};
BUILD_ASSERT(sizeof(struct sha224_digest) == SHA224_DIGEST_SIZE);

struct sha1_digest {
	union {
		uint8_t b8[SHA1_DIGEST_SIZE];
		uint32_t b32[SHA1_DIGEST_WORDS];
	};
};
BUILD_ASSERT(sizeof(struct sha1_digest) == SHA1_DIGEST_SIZE);


/* SHA256 specific type to allocate just enough memory. */
struct sha256_ctx {
	const struct hash_vtable *f; /* metadata & vtable */
	size_t count; /* number of bytes processed */
	uint32_t state[SHA256_DIGEST_WORDS]; /* up to SHA2-256 */
	union {
		uint8_t b8[SHA256_BLOCK_SIZE];
		uint32_t b32[SHA256_BLOCK_WORDS];
		uint64_t b64[SHA256_BLOCK_DWORDS];
		struct sha256_digest digest;
	};
};

#define sha224_ctx sha256_ctx

struct sha1_ctx {
	const struct hash_vtable *f; /* metadata & vtable. */
	size_t count; /* number of bytes processed. */
	uint32_t state[SHA1_DIGEST_WORDS];
	union {
		uint8_t b8[SHA1_BLOCK_SIZE];
		uint32_t b32[SHA1_BLOCK_WORDS];
		uint64_t b64[SHA1_BLOCK_DWORDS];
		struct sha1_digest digest;
	};
};

#ifdef CONFIG_UPTO_SHA512
#define SHA384_DIGEST_SIZE 48
#define SHA512_DIGEST_SIZE 64

#define SHA384_BLOCK_SIZE 128
#define SHA512_BLOCK_SIZE 128

#define SHA384_BLOCK_WORDS   (SHA384_BLOCK_SIZE / sizeof(uint32_t))
#define SHA384_BLOCK_DWORDS  (SHA384_BLOCK_SIZE / sizeof(uint64_t))
#define SHA384_DIGEST_WORDS  (SHA384_DIGEST_SIZE / sizeof(uint32_t))
#define SHA384_DIGEST_DWORDS (SHA384_DIGEST_SIZE / sizeof(uint64_t))

#define SHA512_BLOCK_WORDS   (SHA512_BLOCK_SIZE / sizeof(uint32_t))
#define SHA512_BLOCK_DWORDS  (SHA512_BLOCK_SIZE / sizeof(uint64_t))
#define SHA512_DIGEST_WORDS  (SHA512_DIGEST_SIZE / sizeof(uint32_t))
#define SHA512_DIGEST_DWORDS (SHA512_DIGEST_SIZE / sizeof(uint64_t))

struct sha384_digest {
	union {
		uint8_t b8[SHA384_DIGEST_SIZE];
		uint32_t b32[SHA384_DIGEST_WORDS];
	};
};
BUILD_ASSERT(sizeof(struct sha384_digest) == SHA384_DIGEST_SIZE);

struct sha512_digest {
	union {
		uint8_t b8[SHA512_DIGEST_SIZE];
		uint32_t b32[SHA512_DIGEST_WORDS];
	};
};
BUILD_ASSERT(sizeof(struct sha512_digest) == SHA512_DIGEST_SIZE);

struct sha512_ctx {
	const struct hash_vtable *f; /* metadata & vtable. */
	size_t count; /* number of bytes processed. */
	uint64_t state[SHA512_DIGEST_DWORDS]; /* up to SHA2-512. */
	union {
		uint8_t b8[SHA512_BLOCK_SIZE];
		uint32_t b32[SHA512_BLOCK_WORDS];
		uint64_t b64[SHA512_BLOCK_DWORDS];
		struct sha512_digest digest;
	};
};

#define sha384_ctx sha512_ctx
#endif

/**
 * Generic hash type, allocating memory for any supported hash context
 * Each context should have header at known location.
 */
union hash_ctx {
	const struct hash_vtable *f; /* common metadata & vtable */
	struct sha1_ctx sha1;
	struct sha256_ctx sha256;
	struct sha224_ctx sha224;
#ifdef CONFIG_UPTO_SHA512
	struct sha384_ctx sha384;
	struct sha512_ctx sha512;
#endif
};

union sha_digests {
	struct sha1_digest sha1;
	struct sha224_digest sha224;
	struct sha256_digest sha256;
#ifdef CONFIG_UPTO_SHA512
	struct sha384_digest sha384;
	struct sha512_digest sha512;
#endif
	/* Convenience accessor to bytes. */
	uint8_t b8[SHA256_DIGEST_SIZE];
};

/* Header should be at constant offset to safely cast types to smaller size */
BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha1_ctx, f));
BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha256_ctx, f));
BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha224_ctx, f));

#ifdef CONFIG_UPTO_SHA512
BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha384_ctx, f));
BUILD_ASSERT(offsetof(union hash_ctx, f) == offsetof(struct sha512_ctx, f));
#endif

struct hmac_sha1_ctx {
	struct sha1_ctx hash;
	uint32_t opad[SHA1_BLOCK_WORDS];
};

struct hmac_sha224_ctx {
	struct sha224_ctx hash;
	uint32_t opad[SHA224_BLOCK_WORDS];
};

struct hmac_sha256_ctx {
	struct sha256_ctx hash;
	uint32_t opad[SHA256_BLOCK_WORDS];
};

#ifdef CONFIG_UPTO_SHA512
struct hmac_sha384_ctx {
	struct sha384_ctx hash;
	uint32_t opad[SHA384_BLOCK_WORDS];
};

struct hmac_sha512_ctx {
	struct sha512_ctx hash;
	uint32_t opad[SHA512_BLOCK_WORDS];
};
#endif

/**
 * HMAC context reserving memory for any supported hash type.
 * It's SHA context following storage for ipad/opad
 */
union hmac_ctx {
	const struct hash_vtable *f; /* common metadata & vtable */
	union hash_ctx hash; /* access as hash */
	/* hmac contexts */
	struct hmac_sha1_ctx hmac_sha1;
	struct hmac_sha256_ctx hmac_sha256;
	struct hmac_sha224_ctx hmac_sha224;
#ifdef CONFIG_UPTO_SHA512
	struct hmac_sha384_ctx hmac_sha384;
	struct hmac_sha512_ctx hmac_sha512;
#endif
};

/* Header should be at constant offset to safely cast types to smaller size */
BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha1_ctx, f));
BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha256_ctx, f));
BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha224_ctx, f));

#ifdef CONFIG_UPTO_SHA512
BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha384_ctx, f));
BUILD_ASSERT(offsetof(union hmac_ctx, f) == offsetof(struct sha512_ctx, f));
#endif

/**
 * Reset hash context with the same hash function as configured.
 * Will crash if previously not configured! Used for HMAC.
 */
static inline void HASH_reinit(union hash_ctx *const ctx)
{
	ctx->f->init(ctx);
}

#ifndef CONFIG_DCRYPTO_MOCK
/**
 * Add data to message, call configured transform function when block
 * is full.
 */
static inline void HASH_update(union hash_ctx *const ctx, const void *data,
			       size_t len)
{
	ctx->f->update(ctx, data, len);
}
#else
void HASH_update(union hash_ctx *const ctx, const void *data, size_t len);
#endif

static inline void SHA1_update(struct sha1_ctx *const ctx, const void *data,
			       size_t len)
{
	ctx->f->update((union hash_ctx *)ctx, data, len);
}

static inline void SHA256_update(struct sha256_ctx *const ctx, const void *data,
				 size_t len)
{
	ctx->f->update((union hash_ctx *)ctx, data, len);
}

/**
 * Finalize hash computation by adding padding, message length.
 * Returns pointer to computed digest stored inside provided context.
 */
#ifndef CONFIG_DCRYPTO_MOCK
static inline const union sha_digests *HASH_final(union hash_ctx *const ctx)
{
	return ctx->f->final(ctx);
}
#else
const union sha_digests *HASH_final(union hash_ctx *const ctx);
#endif

static inline const struct sha1_digest *SHA1_final(struct sha1_ctx *const ctx)
{
	return &ctx->f->final((union hash_ctx *)ctx)->sha1;
}

static inline const struct sha256_digest *
SHA256_final(struct sha256_ctx *const ctx)
{
	return &ctx->f->final((union hash_ctx *)ctx)->sha256;
}

/**
 * Returns digest size for configured hash.
 */
static inline size_t HASH_size(union hash_ctx *const ctx)
{
	return ctx->f->digest_size;
}

/**
 * Return block size for configured hash.
 */
static inline size_t HASH_block_size(union hash_ctx *const ctx)
{
	return ctx->f->block_size;
}

/* Software implementations of hash functions. */
void SHA1_sw_init(struct sha1_ctx *const ctx);
void SHA1_sw_update(struct sha1_ctx *const ctx, const void *data, size_t len);
const struct sha1_digest *SHA1_sw_final(struct sha1_ctx *const ctx);
const struct sha1_digest *SHA1_sw_hash(const void *data, size_t len,
				       struct sha1_digest *digest);
void SHA256_sw_init(struct sha256_ctx *const ctx);
void SHA256_sw_update(struct sha256_ctx *const ctx, const void *data,
		      size_t len);
const struct sha256_digest *SHA256_sw_final(struct sha256_ctx *const ctx);
const struct sha256_digest *SHA256_sw_hash(const void *data, size_t len,
					   struct sha256_digest *digest);
void SHA224_sw_init(struct sha224_ctx *const ctx);
void SHA224_sw_update(struct sha224_ctx *const ctx, const void *data,
		      size_t len);
const struct sha224_digest *SHA224_sw_final(struct sha224_ctx *const ctx);
const struct sha224_digest *SHA224_sw_hash(const void *data, size_t len,
					   struct sha224_digest *digest);

/**
 * Initialize HMAC for pre-configured hash.
 * This is generic function which can initialize HMAC with any supported
 * hash function.
 */
void HMAC_sw_init(union hmac_ctx *const ctx, const void *key, size_t len);
const union sha_digests *HMAC_sw_final(union hmac_ctx *const ctx);

/* HMAC update is same as SHA update. */
static inline void HMAC_update(union hmac_ctx *const ctx, const void *data,
			       size_t len)
{
	ctx->f->update(&ctx->hash, data, len);
}

static inline size_t HMAC_size(union hmac_ctx *const ctx)
{
	return ctx->f->digest_size;
}

static inline const union sha_digests *HMAC_final(union hmac_ctx *const ctx)
{
	return ctx->f->hmac_final(ctx);
}

/**
 * HMAC SHA1 initialization.
 */
static inline void HMAC_SHA1_sw_init(struct hmac_sha1_ctx *const ctx,
				     const void *key, size_t len)
{
	SHA1_sw_init(&ctx->hash);
	HMAC_sw_init((union hmac_ctx *)ctx, key, len);
}

static inline void HMAC_SHA1_update(struct hmac_sha1_ctx *const ctx,
				    const void *data, size_t len)
{
	ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
}

static inline const struct sha1_digest *
HMAC_SHA1_final(struct hmac_sha1_ctx *const ctx)
{
	return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha1;
}

/**
 * HMAC SHA2-224 initialization.
 */
static inline void HMAC_SHA224_sw_init(struct hmac_sha224_ctx *const ctx,
				       const void *key, size_t len)
{
	SHA224_sw_init(&ctx->hash);
	HMAC_sw_init((union hmac_ctx *)ctx, key, len);
}

static inline void HMAC_SHA224_update(struct hmac_sha224_ctx *const ctx,
				      const void *data, size_t len)
{
	ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
}

static inline const struct sha224_digest *
HMAC_SHA224_final(struct hmac_sha224_ctx *const ctx)
{
	return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha224;
}

/**
 * HMAC SHA2-256 initialization.
 */
static inline void HMAC_SHA256_sw_init(struct hmac_sha256_ctx *const ctx,
				       const void *key, size_t len)
{
	SHA256_sw_init(&ctx->hash);
	HMAC_sw_init((union hmac_ctx *)ctx, key, len);
}

static inline void HMAC_SHA256_update(struct hmac_sha256_ctx *const ctx,
				      const void *data, size_t len)
{
	ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
}

static inline const struct sha256_digest *
HMAC_SHA256_final(struct hmac_sha256_ctx *ctx)
{
	return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha256;
}

#ifdef CONFIG_UPTO_SHA512
void SHA384_sw_init(struct sha384_ctx *const ctx);
void SHA384_sw_update(struct sha384_ctx *const ctx, const void *data,
		      size_t len);
const struct sha384_digest *SHA384_sw_final(struct sha384_ctx *const ctx);
const struct sha384_digest *SHA384_sw_hash(const void *data, size_t len,
					   struct sha384_digest *digest);
void SHA512_sw_init(struct sha512_ctx *const ctx);
void SHA512_sw_update(struct sha512_ctx *const ctx, const void *data,
		      size_t len);
const struct sha512_digest *SHA512_sw_final(struct sha512_ctx *ctx);
const struct sha512_digest *SHA512_sw_hash(const void *data, size_t len,
					   struct sha512_digest *digest);

/**
 * HMAC SHA2-384 initialization.
 */
static inline void HMAC_SHA384_sw_init(struct hmac_sha384_ctx *ctx,
				       const void *key, size_t len)
{
	SHA384_sw_init(&ctx->hash);
	HMAC_sw_init((union hmac_ctx *)ctx, key, len);
}

static inline void HMAC_SHA384_update(struct hmac_sha384_ctx *ctx,
				      const void *data, size_t len)
{
	ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
}
static inline const struct sha384_digest *
HMAC_SHA384_final(struct hmac_sha384_ctx *ctx)
{
	return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha384;
}
/**
 * HMAC SHA2-512 initialization.
 */
static inline void HMAC_SHA512_sw_init(struct hmac_sha512_ctx *ctx,
				       const void *key, size_t len)
{
	SHA512_sw_init(&ctx->hash);
	HMAC_sw_init((union hmac_ctx *)ctx, key, len);
}
static inline void HMAC_SHA512_update(struct hmac_sha512_ctx *ctx,
				      const void *data, size_t len)
{
	ctx->hash.f->update((union hash_ctx *)&ctx->hash, data, len);
}
static inline const struct sha512_digest *
HMAC_SHA512_final(struct hmac_sha512_ctx *ctx)
{
	return &ctx->hash.f->hmac_final((union hmac_ctx *)ctx)->sha512;
}
#endif