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