blob: c4150766fded77ca0ba123a76067d695ad10a514 [file] [log] [blame]
Peer Chen8d782ee2011-01-18 21:34:18 -05001/*
2 * (C) Copyright 2011
3 * NVIDIA Corporation <www.nvidia.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * crypto.c - Cryptography support
26 */
27#include "crypto.h"
28#include "nvaes_ref.h"
29#include <stdio.h>
30
31/* Local function declarations */
32static void
33apply_cbc_chain_data(u_int8_t *cbc_chain_data,
34 u_int8_t *src,
35 u_int8_t *dst);
36
37static void
38generate_key_schedule(u_int8_t *key, u_int8_t *key_schedule);
39
40static void
41encrypt_object( u_int8_t *key_schedule,
42 u_int8_t *src,
43 u_int8_t *dst,
44 u_int32_t num_aes_blocks);
45
46static int
47encrypt_and_sign(u_int8_t *key,
48 u_int8_t *src,
49 u_int32_t length,
50 u_int8_t *sig_dst);
51
52u_int8_t enable_debug_crypto = 0;
53
54/* Implementation */
55static u_int8_t zero_key[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
56 0, 0, 0, 0, 0, 0, 0, 0 };
57
58static void
59print_vector(char *name, u_int32_t num_bytes, u_int8_t *data)
60{
61 u_int32_t i;
62
Anton Staaf9d467bf2011-01-28 11:19:05 -080063 printf("%s [%d] @%p", name, num_bytes, data);
Peer Chen8d782ee2011-01-18 21:34:18 -050064 for (i=0; i<num_bytes; i++) {
65 if ( i % 16 == 0 )
66 printf(" = ");
67 printf("%02x", data[i]);
68 if ( (i+1) % 16 != 0 )
69 printf(" ");
70 }
71 printf("\n");
72}
73
74
75static void
76apply_cbc_chain_data(u_int8_t *cbc_chain_data,
77 u_int8_t *src,
78 u_int8_t *dst)
79{
80 int i;
81
82 for (i = 0; i < 16; i++) {
83 *dst++ = *src++ ^ *cbc_chain_data++;
84 }
85}
86
87static void
88generate_key_schedule(u_int8_t *key, u_int8_t *key_schedule)
89{
90 /*
91 * The only need for a key is for signing/checksum purposes, so
92 * expand a key of 0's.
93 */
94 nv_aes_expand_key(zero_key, key_schedule);
95}
96
97static void
98encrypt_object(u_int8_t *key_schedule,
99 u_int8_t *src,
100 u_int8_t *dst,
101 u_int32_t num_aes_blocks)
102{
103 u_int32_t i;
104 u_int8_t *cbc_chain_data;
105 u_int8_t tmp_data[KEY_LENGTH];
106
107 cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
108
109 for (i = 0; i < num_aes_blocks; i++) {
110 if (enable_debug_crypto) {
111 printf("encrypt_object: block %d of %d\n", i,
112 num_aes_blocks);
113 print_vector("AES Src", KEY_LENGTH, src);
114 }
115
116 /* Apply the chain data */
117 apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
118
119 if (enable_debug_crypto)
120 print_vector("AES Xor", KEY_LENGTH,
121 tmp_data);
122
123 /* encrypt the AES block */
124 nv_aes_encrypt(tmp_data, key_schedule, dst);
125
126 if (enable_debug_crypto)
127 print_vector("AES Dst", KEY_LENGTH, dst);
128 /* Update pointers for next loop. */
129 cbc_chain_data = dst;
130 src += KEY_LENGTH;
131 dst += KEY_LENGTH;
132 }
133}
134
135static void
136left_shift_vector(u_int8_t *in,
137 u_int8_t *out,
138 u_int32_t size)
139{
140 u_int32_t i;
141 u_int8_t carry = 0;
142
143 for (i=0; i<size; i++) {
144 u_int32_t j = size-1-i;
145
146 out[j] = (in[j] << 1) | carry;
147 carry = in[j] >> 7; /* get most significant bit */
148 }
149}
150
151static void
152sign_objext(
153 u_int8_t *key,
154 u_int8_t *key_schedule,
155 u_int8_t *src,
156 u_int8_t *dst,
157 u_int32_t num_aes_blocks)
158{
159 u_int32_t i;
160 u_int8_t *cbc_chain_data;
161
162 u_int8_t l[KEY_LENGTH];
163 u_int8_t k1[KEY_LENGTH];
164 u_int8_t tmp_data[KEY_LENGTH];
165
166 cbc_chain_data = zero_key; /* Convenient array of 0's for IV */
167
168 /* compute k1 constant needed by AES-CMAC calculation */
169
170 for (i=0; i<KEY_LENGTH; i++)
171 tmp_data[i] = 0;
172
173 encrypt_object(key_schedule, tmp_data, l, 1);
174
175 if (enable_debug_crypto)
176 print_vector("AES(key, nonce)", KEY_LENGTH, l);
177
178 left_shift_vector(l, k1, sizeof(l));
179
180 if (enable_debug_crypto)
181 print_vector("L", KEY_LENGTH, l);
182
183 if ( (l[0] >> 7) != 0 ) /* get MSB of L */
184 k1[KEY_LENGTH-1] ^= AES_CMAC_CONST_RB;
185
186 if (enable_debug_crypto)
187 print_vector("K1", KEY_LENGTH, k1);
188
189 /* compute the AES-CMAC value */
190 for (i = 0; i < num_aes_blocks; i++) {
191 /* Apply the chain data */
192 apply_cbc_chain_data(cbc_chain_data, src, tmp_data);
193
194 /* for the final block, XOR k1 into the IV */
195 if ( i == num_aes_blocks-1 )
196 apply_cbc_chain_data(tmp_data, k1, tmp_data);
197
198 /* encrypt the AES block */
199 nv_aes_encrypt(tmp_data, key_schedule, (u_int8_t*)dst);
200
201 if (enable_debug_crypto) {
202 printf("sign_objext: block %d of %d\n", i,
203 num_aes_blocks);
204 print_vector("AES-CMAC Src", KEY_LENGTH, src);
205 print_vector("AES-CMAC Xor", KEY_LENGTH, tmp_data);
206 print_vector("AES-CMAC Dst",
207 KEY_LENGTH,
208 (u_int8_t*)dst);
209 }
210
211 /* Update pointers for next loop. */
212 cbc_chain_data = (u_int8_t*)dst;
213 src += KEY_LENGTH;
214 }
215
216 if (enable_debug_crypto)
217 print_vector("AES-CMAC Hash", KEY_LENGTH, (u_int8_t*)dst);
218}
219
220static int
221encrypt_and_sign(u_int8_t *key,
222 u_int8_t *src,
223 u_int32_t length,
224 u_int8_t *sig_dst)
225{
226 u_int32_t num_aes_blocks;
227 u_int8_t key_schedule[4*NVAES_STATECOLS*(NVAES_ROUNDS+1)];
228
229 if (enable_debug_crypto) {
230 printf("encrypt_and_sign: length = %d\n", length);
231 print_vector("AES key", KEY_LENGTH, key);
232 }
233
234 generate_key_schedule(key, key_schedule);
235
236 num_aes_blocks = ICEIL(length, KEY_LENGTH);
237
238 if (enable_debug_crypto)
239 printf("encrypt_and_sign: begin signing\n");
240
241 /* encrypt the data, overwriting the result in signature. */
242 sign_objext(key, key_schedule, src, sig_dst, num_aes_blocks);
243
244 if (enable_debug_crypto)
245 printf("encrypt_and_sign: end signing\n");
246
247 return 0;
248}
249
250int
251sign_data_block(u_int8_t *source,
252 u_int32_t length,
253 u_int8_t *signature)
254{
255 return encrypt_and_sign(zero_key,
256 source,
257 length,
258 signature);
259}
260
261int
262sign_bct(build_image_context *context,
263 u_int8_t *bct)
264{
265 u_int32_t Offset;
266 u_int32_t length;
267 u_int32_t hash_size;
268 u_int8_t *hash_buffer = NULL;
269 int e = 0;
270
271 assert(bct != NULL);
272
273 if (context->bctlib.get_value(nvbct_lib_id_hash_size,
274 &hash_size,
275 bct) != 0)
276 return -ENODATA;
277 if (context->bctlib.get_value(nvbct_lib_id_crypto_offset,
278 &Offset,
279 bct) != 0)
280 return -ENODATA;
281 if (context->bctlib.get_value(nvbct_lib_id_crypto_length,
282 &length,
283 bct) != 0)
284 return -ENODATA;
285
286 hash_buffer = malloc(hash_size);
287 if (hash_buffer == NULL)
288 return -ENOMEM;
289 e = sign_data_block(bct + Offset, length, hash_buffer);
290 if (e != 0)
291 goto fail;
292 e = context->bctlib.set_data(nvbct_lib_id_crypto_hash,
293 hash_buffer,
294 hash_size,
295 bct);
296 if (e != 0)
297 goto fail;
298
299 fail:
300 free(hash_buffer);
301 return e;
302}