]>
Commit | Line | Data |
---|---|---|
5fd54ace | 1 | // SPDX-License-Identifier: GPL-2.0 |
d59db761 IPG |
2 | /* |
3 | * Ultra Wide Band | |
4 | * AES-128 CCM Encryption | |
5 | * | |
6 | * Copyright (C) 2007 Intel Corporation | |
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | |
8 | * | |
d59db761 IPG |
9 | * We don't do any encryption here; we use the Linux Kernel's AES-128 |
10 | * crypto modules to construct keys and payload blocks in a way | |
11 | * defined by WUSB1.0[6]. Check the erratas, as typos are are patched | |
12 | * there. | |
13 | * | |
14 | * Thanks a zillion to John Keys for his help and clarifications over | |
15 | * the designed-by-a-committee text. | |
16 | * | |
17 | * So the idea is that there is this basic Pseudo-Random-Function | |
18 | * defined in WUSB1.0[6.5] which is the core of everything. It works | |
19 | * by tweaking some blocks, AES crypting them and then xoring | |
20 | * something else with them (this seems to be called CBC(AES) -- can | |
21 | * you tell I know jack about crypto?). So we just funnel it into the | |
22 | * Linux Crypto API. | |
23 | * | |
24 | * We leave a crypto test module so we can verify that vectors match, | |
25 | * every now and then. | |
26 | * | |
27 | * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I | |
28 | * am learning a lot... | |
29 | * | |
30 | * Conveniently, some data structures that need to be | |
31 | * funneled through AES are...16 bytes in size! | |
32 | */ | |
33 | ||
ab1e6fa4 | 34 | #include <crypto/skcipher.h> |
d59db761 IPG |
35 | #include <linux/crypto.h> |
36 | #include <linux/module.h> | |
37 | #include <linux/err.h> | |
38 | #include <linux/uwb.h> | |
5a0e3ad6 | 39 | #include <linux/slab.h> |
d59db761 IPG |
40 | #include <linux/usb/wusb.h> |
41 | #include <linux/scatterlist.h> | |
d59db761 | 42 | |
ef23db9c | 43 | static int debug_crypto_verify; |
d409f3bf DV |
44 | |
45 | module_param(debug_crypto_verify, int, 0); | |
46 | MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms"); | |
d59db761 | 47 | |
e43ace89 DV |
48 | static void wusb_key_dump(const void *buf, size_t len) |
49 | { | |
50 | print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_OFFSET, 16, 1, | |
51 | buf, len, 0); | |
52 | } | |
53 | ||
d59db761 IPG |
54 | /* |
55 | * Block of data, as understood by AES-CCM | |
56 | * | |
57 | * The code assumes this structure is nothing but a 16 byte array | |
58 | * (packed in a struct to avoid common mess ups that I usually do with | |
59 | * arrays and enforcing type checking). | |
60 | */ | |
61 | struct aes_ccm_block { | |
62 | u8 data[16]; | |
63 | } __attribute__((packed)); | |
64 | ||
65 | /* | |
66 | * Counter-mode Blocks (WUSB1.0[6.4]) | |
67 | * | |
68 | * According to CCM (or so it seems), for the purpose of calculating | |
69 | * the MIC, the message is broken in N counter-mode blocks, B0, B1, | |
70 | * ... BN. | |
71 | * | |
72 | * B0 contains flags, the CCM nonce and l(m). | |
73 | * | |
74 | * B1 contains l(a), the MAC header, the encryption offset and padding. | |
75 | * | |
76 | * If EO is nonzero, additional blocks are built from payload bytes | |
1076e7a4 | 77 | * until EO is exhausted (FIXME: padding to 16 bytes, I guess). The |
d59db761 IPG |
78 | * padding is not xmitted. |
79 | */ | |
80 | ||
81 | /* WUSB1.0[T6.4] */ | |
82 | struct aes_ccm_b0 { | |
83 | u8 flags; /* 0x59, per CCM spec */ | |
84 | struct aes_ccm_nonce ccm_nonce; | |
85 | __be16 lm; | |
86 | } __attribute__((packed)); | |
87 | ||
88 | /* WUSB1.0[T6.5] */ | |
89 | struct aes_ccm_b1 { | |
90 | __be16 la; | |
91 | u8 mac_header[10]; | |
92 | __le16 eo; | |
93 | u8 security_reserved; /* This is always zero */ | |
94 | u8 padding; /* 0 */ | |
95 | } __attribute__((packed)); | |
96 | ||
97 | /* | |
98 | * Encryption Blocks (WUSB1.0[6.4.4]) | |
99 | * | |
100 | * CCM uses Ax blocks to generate a keystream with which the MIC and | |
101 | * the message's payload are encoded. A0 always encrypts/decrypts the | |
af901ca1 | 102 | * MIC. Ax (x>0) are used for the successive payload blocks. |
d59db761 IPG |
103 | * |
104 | * The x is the counter, and is increased for each block. | |
105 | */ | |
106 | struct aes_ccm_a { | |
107 | u8 flags; /* 0x01, per CCM spec */ | |
108 | struct aes_ccm_nonce ccm_nonce; | |
109 | __be16 counter; /* Value of x */ | |
110 | } __attribute__((packed)); | |
111 | ||
112 | static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, | |
113 | size_t size) | |
114 | { | |
115 | u8 *bo = _bo; | |
116 | const u8 *bi1 = _bi1, *bi2 = _bi2; | |
117 | size_t itr; | |
118 | for (itr = 0; itr < size; itr++) | |
119 | bo[itr] = bi1[itr] ^ bi2[itr]; | |
120 | } | |
121 | ||
a19b882c AL |
122 | /* Scratch space for MAC calculations. */ |
123 | struct wusb_mac_scratch { | |
124 | struct aes_ccm_b0 b0; | |
125 | struct aes_ccm_b1 b1; | |
126 | struct aes_ccm_a ax; | |
127 | }; | |
128 | ||
d59db761 IPG |
129 | /* |
130 | * CC-MAC function WUSB1.0[6.5] | |
131 | * | |
132 | * Take a data string and produce the encrypted CBC Counter-mode MIC | |
133 | * | |
134 | * Note the names for most function arguments are made to (more or | |
135 | * less) match those used in the pseudo-function definition given in | |
136 | * WUSB1.0[6.5]. | |
137 | * | |
138 | * @tfm_cbc: CBC(AES) blkcipher handle (initialized) | |
139 | * | |
140 | * @tfm_aes: AES cipher handle (initialized) | |
141 | * | |
142 | * @mic: buffer for placing the computed MIC (Message Integrity | |
143 | * Code). This is exactly 8 bytes, and we expect the buffer to | |
144 | * be at least eight bytes in length. | |
145 | * | |
146 | * @key: 128 bit symmetric key | |
147 | * | |
148 | * @n: CCM nonce | |
149 | * | |
150 | * @a: ASCII string, 14 bytes long (I guess zero padded if needed; | |
151 | * we use exactly 14 bytes). | |
152 | * | |
153 | * @b: data stream to be processed; cannot be a global or const local | |
154 | * (will confuse the scatterlists) | |
155 | * | |
156 | * @blen: size of b... | |
157 | * | |
158 | * Still not very clear how this is done, but looks like this: we | |
159 | * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with | |
160 | * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we | |
161 | * take the payload and divide it in blocks (16 bytes), xor them with | |
162 | * the previous crypto result (16 bytes) and crypt it, repeat the next | |
163 | * block with the output of the previous one, rinse wash (I guess this | |
164 | * is what AES CBC mode means...but I truly have no idea). So we use | |
165 | * the CBC(AES) blkcipher, that does precisely that. The IV (Initial | |
166 | * Vector) is 16 bytes and is set to zero, so | |
167 | * | |
168 | * See rfc3610. Linux crypto has a CBC implementation, but the | |
169 | * documentation is scarce, to say the least, and the example code is | |
170 | * so intricated that is difficult to understand how things work. Most | |
171 | * of this is guess work -- bite me. | |
172 | * | |
173 | * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and | |
174 | * using the 14 bytes of @a to fill up | |
175 | * b1.{mac_header,e0,security_reserved,padding}. | |
176 | * | |
25985edc | 177 | * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of |
d59db761 IPG |
178 | * l(m) is orthogonal, they bear no relationship, so it is not |
179 | * in conflict with the parameter's relation that | |
180 | * WUSB1.0[6.4.2]) defines. | |
181 | * | |
182 | * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in | |
183 | * first errata released on 2005/07. | |
184 | * | |
185 | * NOTE: we need to clean IV to zero at each invocation to make sure | |
186 | * we start with a fresh empty Initial Vector, so that the CBC | |
187 | * works ok. | |
188 | * | |
189 | * NOTE: blen is not aligned to a block size, we'll pad zeros, that's | |
190 | * what sg[4] is for. Maybe there is a smarter way to do this. | |
191 | */ | |
ab1e6fa4 | 192 | static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, |
a19b882c AL |
193 | struct crypto_cipher *tfm_aes, |
194 | struct wusb_mac_scratch *scratch, | |
195 | void *mic, | |
d59db761 IPG |
196 | const struct aes_ccm_nonce *n, |
197 | const struct aes_ccm_label *a, const void *b, | |
198 | size_t blen) | |
199 | { | |
200 | int result = 0; | |
ab1e6fa4 | 201 | SKCIPHER_REQUEST_ON_STACK(req, tfm_cbc); |
d59db761 | 202 | struct scatterlist sg[4], sg_dst; |
ab1e6fa4 HX |
203 | void *dst_buf; |
204 | size_t dst_size; | |
ab1e6fa4 | 205 | u8 iv[crypto_skcipher_ivsize(tfm_cbc)]; |
d59db761 IPG |
206 | size_t zero_padding; |
207 | ||
d59db761 IPG |
208 | /* |
209 | * These checks should be compile time optimized out | |
210 | * ensure @a fills b1's mac_header and following fields | |
211 | */ | |
a19b882c AL |
212 | WARN_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la)); |
213 | WARN_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block)); | |
214 | WARN_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block)); | |
215 | WARN_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block)); | |
d59db761 IPG |
216 | |
217 | result = -ENOMEM; | |
d59db761 IPG |
218 | zero_padding = blen % sizeof(struct aes_ccm_block); |
219 | if (zero_padding) | |
220 | zero_padding = sizeof(struct aes_ccm_block) - zero_padding; | |
a19b882c AL |
221 | dst_size = blen + sizeof(scratch->b0) + sizeof(scratch->b1) + |
222 | zero_padding; | |
d59db761 | 223 | dst_buf = kzalloc(dst_size, GFP_KERNEL); |
90b61386 | 224 | if (!dst_buf) |
d59db761 | 225 | goto error_dst_buf; |
d59db761 | 226 | |
ab1e6fa4 | 227 | memset(iv, 0, sizeof(iv)); |
d59db761 IPG |
228 | |
229 | /* Setup B0 */ | |
a19b882c AL |
230 | scratch->b0.flags = 0x59; /* Format B0 */ |
231 | scratch->b0.ccm_nonce = *n; | |
232 | scratch->b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ | |
d59db761 IPG |
233 | |
234 | /* Setup B1 | |
235 | * | |
236 | * The WUSB spec is anything but clear! WUSB1.0[6.5] | |
237 | * says that to initialize B1 from A with 'l(a) = blen + | |
238 | * 14'--after clarification, it means to use A's contents | |
239 | * for MAC Header, EO, sec reserved and padding. | |
240 | */ | |
a19b882c AL |
241 | scratch->b1.la = cpu_to_be16(blen + 14); |
242 | memcpy(&scratch->b1.mac_header, a, sizeof(*a)); | |
d59db761 | 243 | |
d59db761 | 244 | sg_init_table(sg, ARRAY_SIZE(sg)); |
a19b882c AL |
245 | sg_set_buf(&sg[0], &scratch->b0, sizeof(scratch->b0)); |
246 | sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1)); | |
d59db761 IPG |
247 | sg_set_buf(&sg[2], b, blen); |
248 | /* 0 if well behaved :) */ | |
620f1a63 | 249 | sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0); |
d59db761 IPG |
250 | sg_init_one(&sg_dst, dst_buf, dst_size); |
251 | ||
ab1e6fa4 HX |
252 | skcipher_request_set_tfm(req, tfm_cbc); |
253 | skcipher_request_set_callback(req, 0, NULL, NULL); | |
254 | skcipher_request_set_crypt(req, sg, &sg_dst, dst_size, iv); | |
255 | result = crypto_skcipher_encrypt(req); | |
256 | skcipher_request_zero(req); | |
d59db761 IPG |
257 | if (result < 0) { |
258 | printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n", | |
259 | result); | |
260 | goto error_cbc_crypt; | |
261 | } | |
d59db761 IPG |
262 | |
263 | /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] | |
264 | * The procedure is to AES crypt the A0 block and XOR the MIC | |
25985edc | 265 | * Tag against it; we only do the first 8 bytes and place it |
d59db761 IPG |
266 | * directly in the destination buffer. |
267 | * | |
268 | * POS Crypto API: size is assumed to be AES's block size. | |
269 | * Thanks for documenting it -- tip taken from airo.c | |
270 | */ | |
a19b882c AL |
271 | scratch->ax.flags = 0x01; /* as per WUSB 1.0 spec */ |
272 | scratch->ax.ccm_nonce = *n; | |
273 | scratch->ax.counter = 0; | |
274 | crypto_cipher_encrypt_one(tfm_aes, (void *)&scratch->ax, | |
275 | (void *)&scratch->ax); | |
276 | bytewise_xor(mic, &scratch->ax, iv, 8); | |
d59db761 IPG |
277 | result = 8; |
278 | error_cbc_crypt: | |
279 | kfree(dst_buf); | |
280 | error_dst_buf: | |
d59db761 IPG |
281 | return result; |
282 | } | |
283 | ||
284 | /* | |
285 | * WUSB Pseudo Random Function (WUSB1.0[6.5]) | |
286 | * | |
287 | * @b: buffer to the source data; cannot be a global or const local | |
288 | * (will confuse the scatterlists) | |
289 | */ | |
290 | ssize_t wusb_prf(void *out, size_t out_size, | |
291 | const u8 key[16], const struct aes_ccm_nonce *_n, | |
292 | const struct aes_ccm_label *a, | |
293 | const void *b, size_t blen, size_t len) | |
294 | { | |
295 | ssize_t result, bytes = 0, bitr; | |
296 | struct aes_ccm_nonce n = *_n; | |
ab1e6fa4 | 297 | struct crypto_skcipher *tfm_cbc; |
d59db761 | 298 | struct crypto_cipher *tfm_aes; |
a19b882c | 299 | struct wusb_mac_scratch *scratch; |
d59db761 IPG |
300 | u64 sfn = 0; |
301 | __le64 sfn_le; | |
302 | ||
ab1e6fa4 | 303 | tfm_cbc = crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); |
d59db761 IPG |
304 | if (IS_ERR(tfm_cbc)) { |
305 | result = PTR_ERR(tfm_cbc); | |
306 | printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result); | |
307 | goto error_alloc_cbc; | |
308 | } | |
ab1e6fa4 | 309 | result = crypto_skcipher_setkey(tfm_cbc, key, 16); |
d59db761 IPG |
310 | if (result < 0) { |
311 | printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result); | |
312 | goto error_setkey_cbc; | |
313 | } | |
314 | ||
315 | tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | |
316 | if (IS_ERR(tfm_aes)) { | |
317 | result = PTR_ERR(tfm_aes); | |
318 | printk(KERN_ERR "E: can't load AES: %d\n", (int)result); | |
319 | goto error_alloc_aes; | |
320 | } | |
321 | result = crypto_cipher_setkey(tfm_aes, key, 16); | |
322 | if (result < 0) { | |
323 | printk(KERN_ERR "E: can't set AES key: %d\n", (int)result); | |
324 | goto error_setkey_aes; | |
325 | } | |
a19b882c | 326 | scratch = kmalloc(sizeof(*scratch), GFP_KERNEL); |
1ee1710c WY |
327 | if (!scratch) { |
328 | result = -ENOMEM; | |
a19b882c | 329 | goto error_alloc_scratch; |
1ee1710c | 330 | } |
d59db761 IPG |
331 | |
332 | for (bitr = 0; bitr < (len + 63) / 64; bitr++) { | |
333 | sfn_le = cpu_to_le64(sfn++); | |
334 | memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */ | |
a19b882c | 335 | result = wusb_ccm_mac(tfm_cbc, tfm_aes, scratch, out + bytes, |
d59db761 IPG |
336 | &n, a, b, blen); |
337 | if (result < 0) | |
338 | goto error_ccm_mac; | |
339 | bytes += result; | |
340 | } | |
341 | result = bytes; | |
a19b882c AL |
342 | |
343 | kfree(scratch); | |
344 | error_alloc_scratch: | |
d59db761 IPG |
345 | error_ccm_mac: |
346 | error_setkey_aes: | |
347 | crypto_free_cipher(tfm_aes); | |
348 | error_alloc_aes: | |
349 | error_setkey_cbc: | |
ab1e6fa4 | 350 | crypto_free_skcipher(tfm_cbc); |
d59db761 | 351 | error_alloc_cbc: |
d59db761 IPG |
352 | return result; |
353 | } | |
354 | ||
355 | /* WUSB1.0[A.2] test vectors */ | |
356 | static const u8 stv_hsmic_key[16] = { | |
357 | 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, | |
358 | 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f | |
359 | }; | |
360 | ||
361 | static const struct aes_ccm_nonce stv_hsmic_n = { | |
362 | .sfn = { 0 }, | |
363 | .tkid = { 0x76, 0x98, 0x01, }, | |
364 | .dest_addr = { .data = { 0xbe, 0x00 } }, | |
365 | .src_addr = { .data = { 0x76, 0x98 } }, | |
366 | }; | |
367 | ||
368 | /* | |
369 | * Out-of-band MIC Generation verification code | |
370 | * | |
371 | */ | |
372 | static int wusb_oob_mic_verify(void) | |
373 | { | |
374 | int result; | |
375 | u8 mic[8]; | |
376 | /* WUSB1.0[A.2] test vectors | |
377 | * | |
378 | * Need to keep it in the local stack as GCC 4.1.3something | |
379 | * messes up and generates noise. | |
380 | */ | |
381 | struct usb_handshake stv_hsmic_hs = { | |
382 | .bMessageNumber = 2, | |
383 | .bStatus = 00, | |
384 | .tTKID = { 0x76, 0x98, 0x01 }, | |
385 | .bReserved = 00, | |
386 | .CDID = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | |
387 | 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, | |
388 | 0x3c, 0x3d, 0x3e, 0x3f }, | |
389 | .nonce = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, | |
390 | 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, | |
391 | 0x2c, 0x2d, 0x2e, 0x2f }, | |
392 | .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c, | |
06acefde | 393 | 0x14, 0x7b }, |
d59db761 IPG |
394 | }; |
395 | size_t hs_size; | |
396 | ||
397 | result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs); | |
398 | if (result < 0) | |
399 | printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result); | |
400 | else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) { | |
401 | printk(KERN_ERR "E: OOB MIC test: " | |
402 | "mismatch between MIC result and WUSB1.0[A2]\n"); | |
403 | hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC); | |
404 | printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size); | |
e43ace89 | 405 | wusb_key_dump(&stv_hsmic_hs, hs_size); |
d59db761 IPG |
406 | printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n", |
407 | sizeof(stv_hsmic_n)); | |
e43ace89 | 408 | wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n)); |
d59db761 | 409 | printk(KERN_ERR "E: MIC out:\n"); |
e43ace89 | 410 | wusb_key_dump(mic, sizeof(mic)); |
d59db761 | 411 | printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n"); |
e43ace89 | 412 | wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC)); |
d59db761 IPG |
413 | result = -EINVAL; |
414 | } else | |
415 | result = 0; | |
416 | return result; | |
417 | } | |
418 | ||
419 | /* | |
420 | * Test vectors for Key derivation | |
421 | * | |
422 | * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1] | |
423 | * (errata corrected in 2005/07). | |
424 | */ | |
425 | static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = { | |
426 | 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, | |
427 | 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f | |
428 | }; | |
429 | ||
430 | static const struct aes_ccm_nonce stv_keydvt_n_a1 = { | |
431 | .sfn = { 0 }, | |
432 | .tkid = { 0x76, 0x98, 0x01, }, | |
433 | .dest_addr = { .data = { 0xbe, 0x00 } }, | |
434 | .src_addr = { .data = { 0x76, 0x98 } }, | |
435 | }; | |
436 | ||
437 | static const struct wusb_keydvt_out stv_keydvt_out_a1 = { | |
438 | .kck = { | |
439 | 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, | |
440 | 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f | |
441 | }, | |
442 | .ptk = { | |
443 | 0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06, | |
444 | 0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d | |
445 | } | |
446 | }; | |
447 | ||
448 | /* | |
449 | * Performa a test to make sure we match the vectors defined in | |
450 | * WUSB1.0[A.1](Errata2006/12) | |
451 | */ | |
452 | static int wusb_key_derive_verify(void) | |
453 | { | |
454 | int result = 0; | |
455 | struct wusb_keydvt_out keydvt_out; | |
456 | /* These come from WUSB1.0[A.1] + 2006/12 errata | |
457 | * NOTE: can't make this const or global -- somehow it seems | |
458 | * the scatterlists for crypto get confused and we get | |
459 | * bad data. There is no doc on this... */ | |
460 | struct wusb_keydvt_in stv_keydvt_in_a1 = { | |
461 | .hnonce = { | |
462 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | |
463 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f | |
464 | }, | |
465 | .dnonce = { | |
466 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | |
467 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f | |
468 | } | |
469 | }; | |
470 | ||
471 | result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1, | |
472 | &stv_keydvt_in_a1); | |
473 | if (result < 0) | |
474 | printk(KERN_ERR "E: WUSB key derivation test: " | |
475 | "derivation failed: %d\n", result); | |
476 | if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) { | |
477 | printk(KERN_ERR "E: WUSB key derivation test: " | |
478 | "mismatch between key derivation result " | |
479 | "and WUSB1.0[A1] Errata 2006/12\n"); | |
e43ace89 DV |
480 | printk(KERN_ERR "E: keydvt in: key\n"); |
481 | wusb_key_dump(stv_key_a1, sizeof(stv_key_a1)); | |
482 | printk(KERN_ERR "E: keydvt in: nonce\n"); | |
06acefde | 483 | wusb_key_dump(&stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); |
e43ace89 DV |
484 | printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n"); |
485 | wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); | |
d59db761 | 486 | printk(KERN_ERR "E: keydvt out: KCK\n"); |
e43ace89 | 487 | wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck)); |
d59db761 | 488 | printk(KERN_ERR "E: keydvt out: PTK\n"); |
e43ace89 | 489 | wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk)); |
d59db761 IPG |
490 | result = -EINVAL; |
491 | } else | |
492 | result = 0; | |
493 | return result; | |
494 | } | |
495 | ||
496 | /* | |
497 | * Initialize crypto system | |
498 | * | |
499 | * FIXME: we do nothing now, other than verifying. Later on we'll | |
500 | * cache the encryption stuff, so that's why we have a separate init. | |
501 | */ | |
502 | int wusb_crypto_init(void) | |
503 | { | |
504 | int result; | |
505 | ||
d409f3bf DV |
506 | if (debug_crypto_verify) { |
507 | result = wusb_key_derive_verify(); | |
508 | if (result < 0) | |
509 | return result; | |
510 | return wusb_oob_mic_verify(); | |
511 | } | |
512 | return 0; | |
d59db761 IPG |
513 | } |
514 | ||
515 | void wusb_crypto_exit(void) | |
516 | { | |
517 | /* FIXME: free cached crypto transforms */ | |
518 | } |