425 lines
14 KiB
C
425 lines
14 KiB
C
/* 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 <vxWorks.h>
|
|
#include <stdio.h>
|
|
#include <openssl/aes.h>
|
|
#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;
|
|
}
|