/* dot11CryptoLib.c - Encrypt/Decrypt functions for wireless framework */ /* * Copyright (c) 2010 Wind River Systems, Inc. * * The right to copy, distribute, modify or otherwise make use * of this software may be licensed only pursuant to the terms * of an applicable Wind River license agreement. */ /* Modification History -------------------- 02a,02mar10,kr Initial version */ /* DESCRIPTION This module contains functions for computing AES key wrap and unwrap: - depends on openssl for the AES encryption; - code adapted from the file ipcrypto_aeskeywrap.c. This module also contains functions for computing RC4-TKIP encryption/decryption: - does not depend on any library; - code adapted from the CCI library (cci_DefaultCipherRC4TKIP.c). \NOMANUAL */ #include #include #include #include "drv/wlan/dot11Lib.h" #include "drv/wlan/dot11RsnLib.h" #define LOGERROR(__s) DOT11_LOG(DOT11_DEBUG_ERROR, DOT11_AREA_RSN, \ (__s "\n", 0,0,0,0,0,0)) #define AESKW_BLOCKSIZE 8 #define AES_BLOCKSIZE 16 #define AES_KEY_128_BYTES 16 #define AES_KEY_192_BYTES 24 #define AES_KEY_256_BYTES 32 #define AES_CHECK_KEYLEN(len) ((len==AES_KEY_128_BYTES)||(len==AES_KEY_192_BYTES)||(len==AES_KEY_256_BYTES)) #define AESKW_WRAP_MIN_BLOCK 2 #define AESKW_UNWRAP_MIN_BLOCK (AESKW_WRAP_MIN_BLOCK+1) #define AESKW_XOR_BLOCK(out, in1, in2) {int ijk;for( ijk = 0; ijk < AESKW_BLOCKSIZE; ijk++ ) out[ijk] = in1[ijk] ^ in2[ijk];} #define AESKW_CVT(b,n) {memset(b,0,AESKW_BLOCKSIZE);b[AESKW_BLOCKSIZE-1] = ((n)&0xFF);b[AESKW_BLOCKSIZE-2] = (((n)&0xFF00)>>8);\ b[AESKW_BLOCKSIZE-3] = (((n)&0xFF0000)>>16);b[AESKW_BLOCKSIZE-4] = (((n)&0xFF000000)>>24);} /*************************************************************************** * * dot11CryptoAesKeyWrap * * Description: Encrypt (wrap) a key using AES-KEYWRAP * Parameters: key - pointer to key buffer * keyLength - length of key, must be 128 bit, 192 bit or 256 bit (in bytes) * iv - pointer to IV. * ivLength - length of IV. Must be AESKW_BLOCKSIZE * plainText - pointer to buffer to encrypt (wrap) * plainTextLength - length of buffer to encrypt. Must be multiple of AESKW_BLOCKSIZE * cipherText - pointer to buffer in which to copy output * cipherTextLength - pointer to the length of the cipherText buffer. On output, * this is updated to the length of data copied into the cipherText buffer * Returns: OK or ERROR * */ STATUS dot11CryptoAesKeyWrap(UINT8 *key, int keyLength, UINT8 *iv, int ivLength, UINT8 *plainText, int plainTextLength, UINT8 *cipherText, UINT32 *cipherTextLength ) { STATUS status = OK; AES_KEY aesKey; /* ** --- Check for proper key length */ if (AES_CHECK_KEYLEN(keyLength)) { /* ** --- Check for proper IV length */ if (ivLength == AESKW_BLOCKSIZE) { /* ** --- Make sure the input is aligned to 64-bit boundaries */ if ( !(plainTextLength % AESKW_BLOCKSIZE) ) { /* ** --- Make sure the output buffer is at least ** one block (64-bits) larger than the input. */ if (*cipherTextLength >= (plainTextLength+AESKW_BLOCKSIZE)) { int numBlocks = plainTextLength/AESKW_BLOCKSIZE; UINT8 *R; UINT8 A[AESKW_BLOCKSIZE]; UINT8 B[AES_BLOCKSIZE]; UINT8 T[AESKW_BLOCKSIZE]; int i,j; if (numBlocks >= AESKW_WRAP_MIN_BLOCK) { /* ** --- Set output buffer size */ *cipherTextLength = plainTextLength+AESKW_BLOCKSIZE; /* ** --- Initialize variables ** ** Set A = IV, an initial value (see 2.2.3) ** For i = 1 to n ** R[i] = P[i] */ memcpy(A, iv, AESKW_BLOCKSIZE); R = cipherText + AESKW_BLOCKSIZE; memcpy( R, plainText, plainTextLength ); if ( -1 == AES_set_encrypt_key(key, keyLength << 3,&aesKey)) { LOGERROR("AES_set_encrypt_key failed"); return ERROR; } for ( j = 0; j < 6; j++ ) { for ( i = 0; i < numBlocks; i++ ) { /* ** --- Do: B = AES(K, A | R[i]) ** --- Do: R[i] = LSB(64, B) */ memcpy( B + AESKW_BLOCKSIZE, R + (i * AESKW_BLOCKSIZE), AESKW_BLOCKSIZE); memcpy( B, A, AESKW_BLOCKSIZE); AES_ecb_encrypt(B,B, &aesKey,AES_ENCRYPT); /* ccip_aes_encrypt( CCI_MODE_ECB, key, keyLength, B, AES_BLOCKSIZE, B, NULL ); */ memcpy( A, B, AESKW_BLOCKSIZE); memcpy( R + (i * AESKW_BLOCKSIZE), B + AESKW_BLOCKSIZE, AESKW_BLOCKSIZE); /* ** --- Do: A = MSB(64, B) ^ t where t = (n*j)+i */ AESKW_CVT(T,(numBlocks*j)+(i+1)); AESKW_XOR_BLOCK(A,T,A); } } /* ** --- Do: Set C[0] = A */ memcpy( cipherText, A, AESKW_BLOCKSIZE); } else { status = ERROR; LOGERROR("Keywrap: outputBuffer too small\n"); } } else { status = ERROR; LOGERROR("Keywrap: message too short\n"); } } else { status = ERROR; LOGERROR("Keywrap: input buffer not a multiple of the blocksize"); } } else { status = ERROR; LOGERROR("Keywrap: invalid blocksize"); } } else { status = ERROR; LOGERROR("Keywrap: invalid keylength"); } return( status ); } /*************************************************************************** * * dot11CryptoAesKeyUnwrap * * Description: Decrypt (unwrap) a key using AES-KEYWRAP * Parameters: key - pointer to key buffer * keyLength - length of key, must be 128 bit, 192 bit or 256 bit (in bytes) * iv - pointer to IV. * ivLength - length of IV. Must be AESKW_BLOCKSIZE * cipherText - pointer to buffer to decrypt (unwrap) * cipherTextLength - length of buffer to decrypt. Must be multiple of AESKW_BLOCKSIZE * plainText - pointer to buffer in which to copy output * plainTextLength - pointer to the length of the plainText buffer. On output, * this is updated to the length of data copied into the plainText buffer * Returns: OK or ERROR * */ STATUS dot11CryptoAesKeyUnwrap(UINT8 *key, int keyLength, UINT8 *iv, int ivLength, UINT8 *cipherText, int cipherTextLength, UINT8 *plainText, UINT32 *plainTextLength) { STATUS status = OK; AES_KEY aesKey; /* ** --- Check for proper key length */ if (AES_CHECK_KEYLEN(keyLength)) { /* ** --- Check for proper IV length */ if (ivLength == AESKW_BLOCKSIZE) { /* ** --- Make sure the input is aligned to 64-bit boundaries */ if ( !(cipherTextLength % AESKW_BLOCKSIZE) ) { /* ** --- Make sure the output buffer is at least ** one block (64-bits) smaller than the input */ if (*plainTextLength >= (cipherTextLength-AESKW_BLOCKSIZE)) { int numBlocks = (cipherTextLength/AESKW_BLOCKSIZE)-1; UINT8 *R, *A; UINT8 B[AES_BLOCKSIZE]; UINT8 T[AESKW_BLOCKSIZE]; int i,j; if ((numBlocks+1) >= AESKW_UNWRAP_MIN_BLOCK) { /* ** --- Set output buffer size */ *plainTextLength = cipherTextLength-AESKW_BLOCKSIZE; /* ** --- Initialize variables ** ** Set A = C[0] ** For i = 1 to n ** R[i] = C[i] */ A = cipherText; R = plainText; memcpy( R, cipherText + AESKW_BLOCKSIZE, cipherTextLength-AESKW_BLOCKSIZE ); if ( -1 == AES_set_decrypt_key(key, keyLength << 3,&aesKey)) { LOGERROR("AES_set_decrypt_key failed"); return ERROR; } for ( j = 6; j > 0; j-- ) { for ( i = numBlocks; i > 0; i-- ) { /* ** --- Do: (A ^ t) */ AESKW_CVT(T,((numBlocks)*(j-1))+(i)); AESKW_XOR_BLOCK(A,T,A); /* ** --- Do: B = AES(K, A | R[i]) ** --- Do: R[i] = LSB(64, B) */ memcpy( B + AESKW_BLOCKSIZE, R + ((i-1) * AESKW_BLOCKSIZE), AESKW_BLOCKSIZE); memcpy( B, A, AESKW_BLOCKSIZE); AES_ecb_encrypt(B, B,&aesKey, AES_DECRYPT); memcpy( A, B, AESKW_BLOCKSIZE); memcpy( R + ((i-1) * AESKW_BLOCKSIZE), B + AESKW_BLOCKSIZE, AESKW_BLOCKSIZE); } } /* ** --- Make sure the first block is equal to the IV */ if (memcmp( A, iv, AESKW_BLOCKSIZE)) { status = ERROR; LOGERROR("Keyunwrap: decoding error"); } } else { LOGERROR("Keyunwrap:message too short"); status = ERROR; } } else { status = ERROR; LOGERROR("keyunwrap: output buffer too small"); } } else { LOGERROR("keyunwrap: input buffer not a multiple of the blocksize"); status = ERROR; } } else { LOGERROR("keyunwrap: invalid iv length"); status = ERROR; } } else { LOGERROR("invalid key length"); status = ERROR; } return( status ); } /*************************************************************************** * * dot11CryptoRc4 - Encrypts the given data using RC4 * * RETURNS: OK or ERROR * */ STATUS dot11CryptoRc4( UINT8* key, /* Key to encrypt data with */ int keyLen, /* Length (in bytes) of the key */ int keyStreamOffset, /* Number of bytes to discard from start of KS */ UINT8 *inputData, /* Pointer to data to be encrypted */ UINT32 inputLength, /* Length of the data */ UINT8 *outputData, /* Pointer to result buffer */ UINT32 *outputDataLen /* I/O arg: len of outputData, set to len of result */ ) { UINT8 swap; /* Temporary variable used to swap values in s-box*/ int loop, i, j; /* Counter variables */ int t; /* Temporary storage */ UINT8 K; /* Pseudo-random number to encrypt current byte */ UINT8 s[256]; /* Initial s-box for keystream */ UINT8 k[256]; /* Key array. */ if( *outputDataLen < inputLength ) { return ERROR; } /* Fill up the arrays to starting values. S-box is numbered 0 - 255 and the key array is filled with the key, repeated over and over */ for (i=0; i<256; i++) { s[i] = i; k[i] = key[i % keyLen]; } /* Set up the s-table */ j = 0; for (i=0; i<256; i++) { j = (j + s[i] + k[i]) & 0xff; swap = s[i]; s[i] = s[j]; s[j] = swap; } i = j = 0; /* Discard the first bytes of the keystream, if desired */ for (loop=0; loop < keyStreamOffset; loop++) { i = (i + 1) & 0xff; j = (j + s[i]) & 0xff; swap = s[i]; s[i] = s[j]; s[j] = swap; t = (s[i] + s[j]) & 0xff; K = s[t]; /* Do nothing with K */ } /* Stream through the data, getting a different pseudo-random number from the key-stream and XORing it with the data */ for (loop = 0; loop < inputLength; loop ++) { i = (i + 1) & 0xff; j = (j + s[i]) & 0xff; swap = s[i]; s[i] = s[j]; s[j] = swap; t = (s[i] + s[j]) & 0xff; K = s[t]; /*inputData[loop] ^= K;*/ outputData[loop] = inputData[loop] ^ K; } *outputDataLen = inputLength; return OK; }