blob: cfdfd79fe74285732e904b83b00a2032b03950b7 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Gopichand Nakkala92f07d82013-01-08 21:16:34 -08002 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21/*
Jeff Johnson32d95a32012-09-10 13:15:23 -070022 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -070023 *
24 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
25 *
26 *
27 * Permission to use, copy, modify, and/or distribute this software for
28 * any purpose with or without fee is hereby granted, provided that the
29 * above copyright notice and this permission notice appear in all
30 * copies.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
33 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
34 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
35 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
36 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
37 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
38 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
39 * PERFORMANCE OF THIS SOFTWARE.
40 */
41
42/*
43 * Airgo Networks, Inc proprietary. All rights reserved.
44 * $File: //depot/software/projects/feature_branches/gen5_phase1/os/linux/classic/ap/apps/ssm/lib/aniSsmAesKeyWrap.c $
45 *
46 * Contains definitions for the AES Key Wrap algorithm from RFC 3394.
47 *
48 * Author: Mayank D. Upadhyay
49 * Date: 31-March-2003
50 * History:-
51 * Date Modified by Modification Information
52 * ------------------------------------------------------
53 *
54 */
55
56#include "vos_types.h"
57#include "bapRsnSsmServices.h"
58#include "bapRsnSsmEapol.h"
59#include "bapRsnErrors.h"
60#include "bapInternal.h"
61#include "bapRsn8021xFsm.h"
62#include "bapRsn8021xAuthFsm.h"
63#include "vos_utils.h"
64#include "vos_memory.h"
65#include "vos_timer.h"
66#include "bapRsnTxRx.h"
67#include "bapRsnSsmAesKeyWrap.h"
68
69#if 0
70
71#include <assert.h>
72#include <stdlib.h>
73#include <openssl/aes.h>
74
75#include <aniAsfHdr.h>
76#include <aniUtils.h>
77#include <aniErrors.h>
78#include <aniAsfLog.h>
79
80#include "aniSsmAesKeyWrap.h"
81#include "aniSsmUtils.h"
82#endif
83
84#define ANI_SSM_AES_KEY_WRAP_IC_SIZE ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE
85
86typedef struct tag_aes_key {
87 tANI_U32 eK[64], dK[64];
88 int Nr;
89} AES_KEY;
90
91static tANI_U8 gAniSsmAesKeyWrapIv[] = {
92 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6
93};
94
95static int
96aes(v_U32_t cryptHandle, tANI_U8 *keyBytes, tANI_U32 keyLen,
97 tANI_U8 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
98 tANI_U8 ri[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
99 tANI_U8 b[AES_BLOCK_SIZE]);
100
101static int
102aes_1(v_U32_t cryptHandle, tANI_U8 *keyBytes, tANI_U32 keyLen,
103 tANI_U8 at[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
104 tANI_U8 ri[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
105 tANI_U8 b[AES_BLOCK_SIZE]);
106
107static int
108xor(tANI_U8 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE], tANI_U32 t);
109
110/**
111 * Implements the AES Key Wrap algorithm described in RFC 3394.
112 * If n is the number of blocks in plainText, of size
113 * ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE, then the output value is (n+1)
114 * blocks. The first block is the IV from section 2.2.3 o the
115 * RFC. Note: It is the caller's responsibility to free the returned
116 * value.
117 *
118 * @param plainText the plaintext data to wrap
119 * @param len the length of the plaintext, which must be a multiple of
120 * ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE.
121 * @param keyEncKey the encryption key
122 * @param keyEncKeyLen the length of keyEncKey
123 * @param cipherTextPtr is set to a newly allocated array containing
124 * the result if the operation succeeds. It is the caller's
125 * responsibility to free this.
126 *
127 * @return ANI_OK if the operation succeeds
128 */
129int
130aniSsmAesKeyWrap(v_U32_t cryptHandle, tANI_U8 *plainText, tANI_U32 len,
131 tANI_U8 *keyEncKey, tANI_U32 keyEncKeyLen,
132 tANI_U8 **cipherTextPtr)
133{
134 int i, j, n;
135 int retVal;
136
137 tANI_U8 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE];
138 tANI_U8 *r = NULL;
139 tANI_U32 t;
140
141 tANI_U8 b[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE*2];
142
143 n = len / ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE;
144 if ((len % ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE) != 0) {
145 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
146 "Illegal number of input bytes to AES Key Wrap!");
147 return ANI_E_ILLEGAL_ARG;
148 }
149
150 // Allocate enough storage for 'A' as well as 'R'
151 r = vos_mem_malloc((n + 1) * ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
152 if (r == NULL) {
153 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
154 "Could not allocate space for R");
155 return ANI_E_MALLOC_FAILED;
156 }
157
158 vos_mem_copy(a, gAniSsmAesKeyWrapIv, sizeof(a));
159 vos_mem_copy(r + ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE, plainText, len);
160
161 for (j = 0; j <= 5; j++) {
162 for (i = 1; i <= n; i++) {
163
164 retVal = aes(cryptHandle, keyEncKey, keyEncKeyLen,
165 a,
166 r + i*ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
167 b);
168
169 if( !ANI_IS_STATUS_SUCCESS( retVal) ) goto error;
170
171 vos_mem_copy(a, b, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
172 t = n*j + i;
173 xor(a, t);
174 vos_mem_copy(r + i*ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
175 b + sizeof(b) - ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
176 ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
177 }
178 }
179
180 vos_mem_copy(r, a, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
181 *cipherTextPtr = r;
182
183 return ANI_OK;
184
185 error:
186 if (r != NULL)
187 vos_mem_free(r);
188
189 return retVal;
190
191}
192
193/**
194 * Implements the AES Key Unwrap algorithm described in RFC 3394.
195 * If (n+1) is the number of blocks in cipherText, of size
196 * ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE, then the output value is (n+1)
197 * blocks. The actual plaintext consists of n blocks that start at the
198 * second block. Note: It is the caller's responsibility to free the
199 * returned value.
200 *
201 * @param cipherText the cipertext data to unwrap
202 * @param len the length of the ciphertext, which must be a multiple of
203 * ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE.
204 * @param keyEncKey the encryption key
205 * @param keyEncKeyLen the length of keyEncKey
206 * @param plainTextPtr is set to a newly allocated array containing
207 * the result if the operation succeeds. It is the caller's
208 * responsibility to free this.
209 *
210 * @return ANI_OK if the operation succeeds
211 */
212int
213aniSsmAesKeyUnwrap(v_U32_t cryptHandle, tANI_U8 *cipherText, tANI_U32 len,
214 tANI_U8 *keyEncKey, tANI_U32 keyEncKeyLen,
215 tANI_U8 **plainTextPtr)
216{
217 int i, j;
218 int retVal;
219
220 tANI_U8 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE];
221 tANI_U8 *r = NULL;
222 tANI_U32 n;
223 tANI_U32 t;
224
225 tANI_U8 b[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE*2];
226
227 n = len / ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE - 1;
228 if ((len % ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE) != 0) {
229 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
230 "Illegal number of input bytes to AES Key Unwrap!");
231 return ANI_E_ILLEGAL_ARG;
232 }
233
234 // Allocate enough storage for 'A' as well as 'R'
235 r = vos_mem_malloc((n + 1) * ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
236 if (r == NULL) {
237 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
238 "Could not allocate space for R");
239 return ANI_E_MALLOC_FAILED;
240 }
241
242 vos_mem_copy(a, cipherText, sizeof(a));
243 vos_mem_copy(r + ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
244 cipherText + ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
245 len - ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
246
247 for (j = 5; j >= 0; j--) {
248 for (i = n; i >= 1; i--) {
249
250 t = n*j + i;
251 xor(a, t);
252 retVal = aes_1(cryptHandle, keyEncKey, keyEncKeyLen,
253 a,
254 r + i*ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
255 b);
256 if( !ANI_IS_STATUS_SUCCESS( retVal) ) goto error;
257
258 vos_mem_copy(a, b, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
259 vos_mem_copy(r + i*ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
260 b + sizeof(b) - ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
261 ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
262 }
263 }
264
265 if (vos_mem_compare2(a, gAniSsmAesKeyWrapIv, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE) != 0) {
266 retVal = ANI_E_MIC_FAILED;
267 goto error;
268 }
269
270 *plainTextPtr = r;
271
272 return ANI_OK;
273
274 error:
275 if (r != NULL)
276 vos_mem_free(r);
277
278 return retVal;
279}
280
281static int
282aes(v_U32_t cryptHandle, tANI_U8 *keyBytes, tANI_U32 keyLen,
283 tANI_U8 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
284 tANI_U8 ri[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
285 tANI_U8 b[AES_BLOCK_SIZE]) {
286
287 int retVal = 0;
288
289// AES_KEY aesKey;
290
291 tANI_U8 in[AES_BLOCK_SIZE];
292 tANI_U8 *out;
293
294 VOS_ASSERT (AES_BLOCK_SIZE == ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE*2);
295
296 // Concatenate A and R[i]
297 vos_mem_copy(in, a, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
298 vos_mem_copy(in + ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
299 ri, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
300 out = b;
301
302#if 0
303 retVal = AES_set_encrypt_key(keyBytes, keyLen*8, &aesKey);
304 if (retVal != 0) {
305 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
306 "AES_set_encrypt_key returned %d", retVal);
307 return ANI_E_FAILED;
308 }
309
310 AES_encrypt(in, out, &aesKey);
311#else // Enable to use VOS function
312 retVal = vos_encrypt_AES(cryptHandle, /* Handle */
313 in, /* input */
314 out, /* output */
315 keyBytes); /* key */
316 if (retVal != 0) {
317 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
318 "vos_encrypt_AES returned %d", retVal);
319 return ANI_E_FAILED;
320 }
321#endif
322 return ANI_OK;
323}
324
325static int
326aes_1(v_U32_t cryptHandle, tANI_U8 *keyBytes, tANI_U32 keyLen,
327 tANI_U8 at[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
328 tANI_U8 ri[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE],
329 tANI_U8 b[AES_BLOCK_SIZE]) {
330
331 int retVal;
332
333// AES_KEY aesKey;
334
335 tANI_U8 in[AES_BLOCK_SIZE];
336 tANI_U8 *out;
337
338 VOS_ASSERT (AES_BLOCK_SIZE == ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE*2);
339
340 // Concatenate A and R[i]
341 vos_mem_copy(in, at, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
342 vos_mem_copy(in + ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE,
343 ri, ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE);
344 out = b;
345
346#if 0
347 retVal = AES_set_decrypt_key(keyBytes, keyLen*8, &aesKey);
348 if (retVal != 0) {
349 ANI_SSM_LOG_E("AES_set_encrypt_key returned %d", retVal);
350 assert(0 && "AES_set_encrypt_key failed!");
351 return ANI_E_FAILED;
352 }
353
354 AES_decrypt(in, out, &aesKey);
355#else
356 retVal = vos_decrypt_AES(cryptHandle, /* Handle */
357 in, /* input */
358 out, /* output */
359 keyBytes); /* key */
360 if (retVal != 0) {
361 VOS_TRACE( VOS_MODULE_ID_BAP, VOS_TRACE_LEVEL_ERROR,
362 "vos_decrypt_AES returned %d", retVal);
363 }
364#endif
365 return ANI_OK;
366}
367
368// From File : aniAsfHdr.h
369
370
371
372/*
373 * Put a long in host order into a char array in network order.
374 *
375 */
376static inline char *aniAsfWr32(char *cp, tANI_U32 x)
377{
378 tAniU32ValAry r;
379 int i;
380
381 r.val = vos_cpu_to_be32(x);
382 i = sizeof(tANI_U32) - 1;
383 cp[3] = r.ary[i--];
384 cp[2] = r.ary[i--];
385 cp[1] = r.ary[i--];
386 cp[0] = r.ary[i];
387
388 return (cp + sizeof(tANI_U32));
389}
390
391// From file : aniAsfMisc.c
392
393/*
394 * Put a long in host order into a char array in network order.
395 *
396 */
397char *aniAsfPut32(char *cp, tANI_U32 x)
398{
399 return(aniAsfWr32(cp, x));
400}
401
402
403static int
404xor(tANI_U8 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE], tANI_U32 t)
405{
406 tANI_U8 tmp[4];
407 aniAsfPut32((char *)tmp, t);
408 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE-1] ^= tmp[3];
409 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE-2] ^= tmp[2];
410 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE-3] ^= tmp[1];
411 a[ANI_SSM_AES_KEY_WRAP_BLOCK_SIZE-4] ^= tmp[0];
412 return ANI_OK;
413}
414