summaryrefslogtreecommitdiff
path: root/firmware/2lib/include/2sha.h
blob: 32af9f742b4000b3ae56dd43a5e06dc425538481 (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
/* Copyright (c) 2014 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.
 *
 * These APIs may be called by external firmware as well as vboot.  External
 * firmware must NOT include this header file directly; instead, import
 * the external-facing vb2_sha.h.  This is permissible because the
 * SHA library routines below don't interact with the rest of vboot.
 */

#ifndef VBOOT_REFERENCE_2SHA_H_
#define VBOOT_REFERENCE_2SHA_H_

#include "2crypto.h"
#include "2return_codes.h"

/* Hash algorithms may be disabled individually to save code space */

#ifndef VB2_SUPPORT_SHA1
#define VB2_SUPPORT_SHA1 1
#endif

#ifndef VB2_SUPPORT_SHA256
#define VB2_SUPPORT_SHA256 1
#endif

#ifndef VB2_SUPPORT_SHA512
#define VB2_SUPPORT_SHA512 1
#endif

/* These are set to the biggest values among the supported hash algorithms.
 * They have to be updated as we add new hash algorithms */
#define VB2_MAX_DIGEST_SIZE	VB2_SHA512_DIGEST_SIZE
#define VB2_MAX_BLOCK_SIZE	VB2_SHA512_BLOCK_SIZE
#define VB2_INVALID_ALG_NAME	"INVALID"

#define VB2_SHA1_DIGEST_SIZE 20
#define VB2_SHA1_BLOCK_SIZE 64
#define VB2_SHA1_ALG_NAME	"SHA1"

/* Context structs for hash algorithms */

struct vb2_sha1_context {
	uint32_t count;
	uint32_t state[5];
#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
	union {
		uint8_t b[VB2_SHA1_BLOCK_SIZE];
		uint32_t w[VB2_SHA1_BLOCK_SIZE / sizeof(uint32_t)];
	} buf;
#else
	uint8_t buf[VB2_SHA1_BLOCK_SIZE];
#endif
};

#define VB2_SHA256_DIGEST_SIZE 32
#define VB2_SHA256_BLOCK_SIZE 64
#define VB2_SHA256_ALG_NAME	"SHA256"

struct vb2_sha256_context {
	uint32_t h[8];
	uint32_t total_size;
	uint32_t size;
	uint8_t block[2 * VB2_SHA256_BLOCK_SIZE];
};

#define VB2_SHA512_DIGEST_SIZE 64
#define VB2_SHA512_BLOCK_SIZE 128
#define VB2_SHA512_ALG_NAME	"SHA512"

struct vb2_sha512_context {
	uint64_t h[8];
	uint32_t total_size;
	uint32_t size;
	uint8_t block[2 * VB2_SHA512_BLOCK_SIZE];
};

/* Hash algorithm independent digest context; includes all of the above. */
struct vb2_digest_context {
	/* Context union for all algorithms */
	union {
#if VB2_SUPPORT_SHA1
		struct vb2_sha1_context sha1;
#endif
#if VB2_SUPPORT_SHA256
		struct vb2_sha256_context sha256;
#endif
#if VB2_SUPPORT_SHA512
		struct vb2_sha512_context sha512;
#endif
	};

	/* Current hash algorithm */
	enum vb2_hash_algorithm hash_alg;

	/* 1 if digest is computed with vb2ex_hwcrypto routines, else 0 */
	int using_hwcrypto;
};

/*
 * Serializable data structure that can store any vboot hash. Layout used in
 * CBFS attributes that need to be backwards-compatible -- do not change!
 * When serializing/deserizaling this, you should store/load (offsetof(bytes) +
 * vb2_digest_size(algo)), not the full size of this structure.
 */
struct vb2_hash {
	/* enum vb2_hash_algorithm. Fixed width for serialization.
	   Single byte to avoid endianness issues. */
	uint8_t algo;
	/* Padding to align and to match existing CBFS attribute. */
	uint8_t reserved[3];
	/* The actual digest. Can add new types here as required. */
	union {
		uint8_t raw[0];
#if VB2_SUPPORT_SHA1
		uint8_t sha1[VB2_SHA1_DIGEST_SIZE];
#endif
#if VB2_SUPPORT_SHA256
		uint8_t sha256[VB2_SHA256_DIGEST_SIZE];
#endif
#if VB2_SUPPORT_SHA512
		uint8_t sha512[VB2_SHA512_DIGEST_SIZE];
#endif
	} bytes;  /* This has a name so that it's easy to sizeof(). */
};
_Static_assert(sizeof(((struct vb2_hash *)0)->bytes) <= VB2_MAX_DIGEST_SIZE,
	       "Must update VB2_MAX_DIGEST_SIZE for new digests!");
_Static_assert(VB2_HASH_ALG_COUNT <= UINT8_MAX, "vb2_hash.algo overflow!");

/**
 * Initialize a hash context.
 *
 * @param ctx		Hash context
 */
void vb2_sha1_init(struct vb2_sha1_context *ctx);
void vb2_sha256_init(struct vb2_sha256_context *ctx);
void vb2_sha512_init(struct vb2_sha512_context *ctx);

/**
 * Update (extend) a hash.
 *
 * @param ctx		Hash context
 * @param data		Data to hash
 * @param size		Length of data in bytes
 */
void vb2_sha1_update(struct vb2_sha1_context *ctx,
		     const uint8_t *data,
		     uint32_t size);
void vb2_sha256_update(struct vb2_sha256_context *ctx,
		       const uint8_t *data,
		       uint32_t size);
void vb2_sha512_update(struct vb2_sha512_context *ctx,
		       const uint8_t *data,
		       uint32_t size);

/**
 * Finalize a hash digest.
 *
 * @param ctx		Hash context
 * @param digest	Destination for hash; must be VB_SHA*_DIGEST_SIZE bytes
 */
void vb2_sha1_finalize(struct vb2_sha1_context *ctx, uint8_t *digest);
void vb2_sha256_finalize(struct vb2_sha256_context *ctx, uint8_t *digest);
void vb2_sha512_finalize(struct vb2_sha512_context *ctx, uint8_t *digest);

/**
 * Hash-extend data
 *
 * @param from	Hash to be extended. It has to be the hash size.
 * @param by	Block to be extended by. It has to be the hash block size.
 * @param to	Destination for extended data
 */
void vb2_sha256_extend(const uint8_t *from, const uint8_t *by, uint8_t *to);

/**
 * Convert vb2_crypto_algorithm to vb2_hash_algorithm.
 *
 * @param algorithm	Crypto algorithm (vb2_crypto_algorithm)
 *
 * @return The hash algorithm for that crypto algorithm, or VB2_HASH_INVALID if
 * the crypto algorithm or its corresponding hash algorithm is invalid or not
 * supported.
 */
enum vb2_hash_algorithm vb2_crypto_to_hash(uint32_t algorithm);

/**
 * Return the size of the digest for a hash algorithm.
 *
 * @param hash_alg	Hash algorithm
 * @return The size of the digest, or 0 if error.
 */
size_t vb2_digest_size(enum vb2_hash_algorithm hash_alg);

/**
 * Return the block size of a hash algorithm.
 *
 * @param hash_alg	Hash algorithm
 * @return The block size of the algorithm, or 0 if error.
 */
size_t vb2_hash_block_size(enum vb2_hash_algorithm alg);

/**
 * Return the name of a hash algorithm
 *
 * @param alg	Hash algorithm ID
 * @return	String containing a hash name or VB2_INVALID_ALG_NAME
 * 		if <alg> is invalid.
 */
const char *vb2_get_hash_algorithm_name(enum vb2_hash_algorithm alg);

/**
 * Initialize a digest context for doing block-style digesting.
 *
 * @param dc		Digest context
 * @param hash_alg	Hash algorithm
 * @return VB2_SUCCESS, or non-zero on error.
 */
vb2_error_t vb2_digest_init(struct vb2_digest_context *dc,
			    enum vb2_hash_algorithm hash_alg);

/**
 * Extend a digest's hash with another block of data.
 *
 * @param dc		Digest context
 * @param buf		Data to hash
 * @param size		Length of data in bytes
 * @return VB2_SUCCESS, or non-zero on error.
 */
vb2_error_t vb2_digest_extend(struct vb2_digest_context *dc, const uint8_t *buf,
			      uint32_t size);

/**
 * Finalize a digest and store the result.
 *
 * The destination digest should be at least vb2_digest_size(algorithm).
 *
 * @param dc		Digest context
 * @param digest	Destination for digest
 * @param digest_size	Length of digest buffer in bytes.
 * @return VB2_SUCCESS, or non-zero on error.
 */
vb2_error_t vb2_digest_finalize(struct vb2_digest_context *dc,
				uint8_t *digest, uint32_t digest_size);

/**
 * Calculate the digest of a buffer and store the result.
 *
 * @param buf		Data to hash
 * @param size		Length of data in bytes
 * @param hash_alg	Hash algorithm
 * @param digest	Destination for digest
 * @param digest_size	Length of digest buffer in bytes.
 * @return VB2_SUCCESS, or non-zero on error.
 */
vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size,
			      enum vb2_hash_algorithm hash_alg, uint8_t *digest,
			      uint32_t digest_size);

/**
 * Fill a vb2_hash structure with the hash of a buffer.
 *
 * @param buf		Buffer to hash
 * @param size		Size of |buf| in bytes
 * @param algo		The hash algorithm to use (and store in |hash|)
 * @param hash		vb2_hash structure to fill with the hash of |buf|
 * @return VB2_SUCCESS, or non-zero on error.
 */
static inline vb2_error_t vb2_hash_calculate(const void *buf, uint32_t size,
					     enum vb2_hash_algorithm algo,
					     struct vb2_hash *hash)
{
	hash->algo = algo;
	return vb2_digest_buffer(buf, size, algo, hash->bytes.raw,
				 vb2_digest_size(algo));
}

/**
 * Verify that a vb2_hash matches a buffer.
 *
 * @param buf		Buffer to hash and match to |hash|
 * @param size		Size of |buf| in bytes
 * @param hash		Hash to compare to the buffer
 * @return VB2_SUCCESS if hash matches, VB2_ERROR_SHA_MISMATCH if hash doesn't
 *  match, or non-zero on other error.
 */
vb2_error_t vb2_hash_verify(const void *buf, uint32_t size,
			    const struct vb2_hash *hash);

#endif  /* VBOOT_REFERENCE_2SHA_H_ */