Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 1 | /* |
Gopichand Nakkala | 92f07d8 | 2013-01-08 21:16:34 -0800 | [diff] [blame^] | 2 | * 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 Johnson | 32d95a3 | 2012-09-10 13:15:23 -0700 | [diff] [blame] | 22 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 23 | * |
| 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 | |
| 86 | typedef struct tag_aes_key { |
| 87 | tANI_U32 eK[64], dK[64]; |
| 88 | int Nr; |
| 89 | } AES_KEY; |
| 90 | |
| 91 | static tANI_U8 gAniSsmAesKeyWrapIv[] = { |
| 92 | 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 |
| 93 | }; |
| 94 | |
| 95 | static int |
| 96 | aes(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 | |
| 101 | static int |
| 102 | aes_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 | |
| 107 | static int |
| 108 | xor(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 | */ |
| 129 | int |
| 130 | aniSsmAesKeyWrap(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 | */ |
| 212 | int |
| 213 | aniSsmAesKeyUnwrap(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 | |
| 281 | static int |
| 282 | aes(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 | |
| 325 | static int |
| 326 | aes_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 | */ |
| 376 | static 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 | */ |
| 397 | char *aniAsfPut32(char *cp, tANI_U32 x) |
| 398 | { |
| 399 | return(aniAsfWr32(cp, x)); |
| 400 | } |
| 401 | |
| 402 | |
| 403 | static int |
| 404 | xor(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 | |