Files
zTC1/mico-os/libraries/utilities/AESUtils.h

367 lines
14 KiB
C

/**
******************************************************************************
* @file AESUtils.h
* @author William Xu
* @version V1.0.0
* @date 05-May-2014
* @brief This header contains function prototypes called by the MICO
* project. These functions abstract the interaction with AES libraries.
******************************************************************************
*
* The MIT License
* Copyright (c) 2014 MXCHIP Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************
*/
#ifndef __AESUtils_h__
#define __AESUtils_h__
#include "common.h"
#include "debug.h"
#include "SecurityUtils.h"
#define AES_UTILS_USE_MICO_AES 1
#if( !defined( AES_UTILS_HAS_GLADMAN_GCM ) )
// #if( __has_include( "gcm.h" ) )
#ifdef _GCM_H
#define AES_UTILS_HAS_GLADMAN_GCM 1
#else
#define AES_UTILS_HAS_GLADMAN_GCM 0
#endif
#endif
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM || AES_UTILS_HAS_GLADMAN_GCM )
#define AES_UTILS_HAS_GCM 1
#endif
#if( !AES_UTILS_HAS_COMMON_CRYPTO_GCM && AES_UTILS_HAS_GLADMAN_GCM )
#include "gcm.h"
#endif
// Compatibility.
#if( AES_UTILS_USE_COMMON_CRYPTO )
#include <CommonCrypto/CommonCryptor.h>
#elif( AES_UTILS_USE_GLADMAN_AES )
#include "External/GladmanAES/aes.h"
#elif( AES_UTILS_USE_MICO_AES )
#include "mico_security.h"
#elif( !TARGET_NO_OPENSSL )
#include <openssl/aes.h>
#else
// Emulate the OpenSSL API with the rijndael-alg-fst.c API.
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
#define AES_BLOCK_SIZE 16
typedef struct
{
uint32_t key[ 4 * ( 14 + 1 ) ]; // Up to 14 rounds.
} AES_KEY;
extern void rijndaelKeySetupEnc(uint32_t rk[/*44*/], const uint8_t cipherKey[]);
extern void rijndaelKeySetupDec(uint32_t rk[/*44*/], const uint8_t cipherKey[]);
extern void rijndaelEncrypt(const uint32_t rk[/*44*/], const uint8_t pt[16], uint8_t ct[16]);
extern void rijndaelDecrypt(const uint32_t rk[/*44*/], const uint8_t ct[16], uint8_t pt[16]);
STATIC_INLINE int AES_set_encrypt_key( const unsigned char *inUserKey, const int inBits, AES_KEY *inKey )
{
(void) inBits; // Assumes 128-bit.
rijndaelKeySetupEnc( inKey->key, inUserKey );
return( 0 );
}
STATIC_INLINE int AES_set_decrypt_key( const unsigned char *inUserKey, const int inBits, AES_KEY *inKey )
{
(void) inBits; // Assumes 128-bit.
rijndaelKeySetupDec( inKey->key, inUserKey );
return( 0 );
}
STATIC_INLINE void AES_encrypt( const unsigned char *inPlain, unsigned char *outCrypt, const AES_KEY *inKey )
{
rijndaelEncrypt( inKey->key, inPlain, outCrypt );
}
STATIC_INLINE void AES_decrypt( const unsigned char *inCrypt, unsigned char *outPlain, const AES_KEY *inKey )
{
rijndaelDecrypt( inKey->key, inCrypt, outPlain );
}
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if 0
#pragma mark -
#pragma mark == AES-CTR ==
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @group AES 128-bit Counter Mode API
@abstract API to encrypt or decrypt using AES-128 in counter mode.
@discussion
Call AES_CTR_Init to initialize the context. Don't use the context until it has been initialized.
Call AES_CTR_Update to encrypt or decrypt N bytes of input and generate N bytes of output.
Call AES_CTR_Final to finalize the context. After finalizing, you must call AES_CTR_Init to use it again.
*/
#define kAES_CTR_Size 16
typedef struct
{
#if( AES_UTILS_USE_COMMON_CRYPTO )
CCCryptorRef cryptor; //! PRIVATE: Internal CommonCrypto ref.
#elif( AES_UTILS_USE_GLADMAN_AES )
aes_encrypt_ctx ctx; //! PRIVATE: Gladman AES context.
#elif (AES_UTILS_USE_MICO_AES )
Aes ctx;
#elif( AES_UTILS_USE_USSL )
aes_context ctx; //! PRIVATE: uSSL AES context.
#else
AES_KEY key; //! PRIVATE: Internal AES key.
#endif
uint8_t ctr[ kAES_CTR_Size ]; //! PRIVATE: Big endian counter.
uint8_t buf[ kAES_CTR_Size ]; //! PRIVATE: Keystream buffer.
size_t used; //! PRIVATE: Number of bytes of the keystream buffer that we've used.
Boolean legacy; //! true=do legacy, chunked encrypting/decrypting.
} AES_CTR_Context;
OSStatus
AES_CTR_Init(
AES_CTR_Context * inContext,
const uint8_t inKey[ kAES_CTR_Size ],
const uint8_t inNonce[ kAES_CTR_Size ] );
OSStatus AES_CTR_Update( AES_CTR_Context *inContext, const void *inSrc, size_t inSrcLen, void *inDst );
void AES_CTR_Final( AES_CTR_Context *inContext );
#if 0
#pragma mark -
#pragma mark == AES-CBC Frame ==
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @group AES 128-bit CBC Frame Mode API
@abstract API to encrypt or decrypt using AES-128 in CBC frame mode.
@discussion
Call AES_CBCFrame_Init to initialize the context. Don't use the context until it has been initialized.
Call AES_CBCFrame_Update to encrypt or decrypt N bytes of input and generate N bytes of output.
Call AES_CBCFrame_Final to finalize the context. After finalizing, you must call AES_CBCFrame_Init to use it again.
*/
#define kAES_CBCFrame_Size 16
typedef struct
{
// PRIVATE: don't touch any of these fields. Do everything with the API.
#if( AES_UTILS_USE_COMMON_CRYPTO )
CCCryptorRef cryptor; //! PRIVATE: Internal CommonCrypto ref.
#elif( AES_UTILS_USE_GLADMAN_AES )
union
{
aes_encrypt_ctx encrypt; //! PRIVATE: Gladman AES context for encryption.
aes_decrypt_ctx decrypt; //! PRIVATE: Gladman AES context for decryption.
} ctx;
int encrypt;
#elif ( AES_UTILS_USE_MICO_AES )
Aes ctx;
int mode;
#elif( AES_UTILS_USE_USSL )
aes_context ctx; //! PRIVATE: uSSL AES context.
int encrypt;
#else
int mode; //! PRIVATE: AES_ENCRYPT or AES_DECRYPT.
AES_KEY key; //! PRIVATE: Internal AES key.
#endif
uint8_t iv[ kAES_CBCFrame_Size ]; //! PRIVATE: Initialization vector.
} AES_CBCFrame_Context;
OSStatus
AES_CBCFrame_Init(
AES_CBCFrame_Context * inContext,
const uint8_t inKey[ kAES_CBCFrame_Size ],
const uint8_t inIV[ kAES_CBCFrame_Size ],
Boolean inEncrypt );
OSStatus AES_CBCFrame_Update( AES_CBCFrame_Context *inContext, const void *inSrc, size_t inSrcLen, void *inDst );
OSStatus
AES_CBCFrame_Update2(
AES_CBCFrame_Context * inContext,
const void * inSrc1,
size_t inLen1,
const void * inSrc2,
size_t inLen2,
void * inDst );
void AES_CBCFrame_Final( AES_CBCFrame_Context *inContext );
#if 0
#pragma mark -
#pragma mark == AES-ECB ==
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @group AES 128-bit ECB API
@abstract API to encrypt or decrypt using AES-128 in ECB mode.
@discussion
Call AES_ECB_Init to initialize the context. Don't use the context until it has been initialized.
Call AES_ECB_Update to encrypt or decrypt N bytes of input and generate N bytes of output.
Call AES_ECB_Final to finalize the context. After finalizing, you must call AES_ECB_Init to use it again.
*/
#define kAES_ECB_Size 16
#if( AES_UTILS_USE_COMMON_CRYPTO )
#define kAES_ECB_Mode_Encrypt kCCEncrypt
#define kAES_ECB_Mode_Decrypt kCCDecrypt
#elif( AES_UTILS_USE_GLADMAN_AES )
#define kAES_ECB_Mode_Encrypt 1
#define kAES_ECB_Mode_Decrypt 0
#elif( AES_UTILS_USE_MICO_AES )
#define kAES_ECB_Mode_Encrypt AES_ENCRYPTION
#define kAES_ECB_Mode_Decrypt AES_DECRYPTION
#elif( AES_UTILS_USE_USSL )
#define kAES_ECB_Mode_Encrypt AES_ENCRYPT
#define kAES_ECB_Mode_Decrypt AES_DECRYPT
#else
#define kAES_ECB_Mode_Encrypt 1
#define kAES_ECB_Mode_Decrypt 0
typedef void ( *AESCryptFunc )( const unsigned char *in, unsigned char *out, const AES_KEY *key );
#endif
typedef struct
{
#if( AES_UTILS_USE_COMMON_CRYPTO )
CCCryptorRef cryptor; //! PRIVATE: Internal CommonCrypto ref.
#elif( AES_UTILS_USE_GLADMAN_AES )
union
{
aes_encrypt_ctx encrypt; //! PRIVATE: Gladman AES context for encryption.
aes_decrypt_ctx decrypt; //! PRIVATE: Gladman AES context for decryption.
} ctx;
uint32_t encrypt;
#elif( AES_UTILS_USE_MICO_AES )
Aes ctx;
uint32_t mode;
#elif( AES_UTILS_USE_USSL )
aes_context ctx; //! PRIVATE: uSSL AES context.
uint32_t mode;
#else
AES_KEY key; //! PRIVATE: Internal AES key.
AESCryptFunc cryptFunc; //! PRIVATE: Ptr AES_encrypt to AES_decrypt.
#endif
} AES_ECB_Context;
OSStatus AES_ECB_Init( AES_ECB_Context *inContext, uint32_t inMode, const uint8_t inKey[ kAES_ECB_Size ] );
OSStatus AES_ECB_Update( AES_ECB_Context *inContext, const void *inSrc, size_t inLen, void *inDst );
void AES_ECB_Final( AES_ECB_Context *inContext );
#if 0
#pragma mark -
#pragma mark == AES-GCM ==
#endif
//---------------------------------------------------------------------------------------------------------------------------
/*! @group AES_GCM 128-bit API
@abstract API to perform authenticated encryption and decryption using AES-128 in GCM mode.
@discussion
Call AES_GCM_Init to initialize the context. Don't use the context until it has been initialized.
Call AES_GCM_Final to finalize the context. After finalizing, you must call AES_GCM_Init to use it again.
The general flow for sending a message:
AES_GCM_InitMessage (provide per-message nonce or use kAES_CGM_Nonce_Auto to increment the nonce from AES_GCM_Init).
AES_GCM_AddAAD (may repeat as many times as necessary to add each chunk of AAD).
AES_GCM_Encrypt (may repeat as many times as necessary to add each chunk of data to encrypt).
AES_GCM_FinalizeMessage (outputs a auth tag to send along with the message so it can be verified by the receiver).
The general flow for receiving a message:
AES_GCM_InitMessage (provide per-message nonce or use kAES_CGM_Nonce_Auto to increment the nonce from AES_GCM_Init).
AES_GCM_AddAAD (may repeat as many times as necessary to add each chunk of AAD).
AES_GCM_Decrypt (may repeat as many times as necessary to add each chunk of data to encrypt).
AES_GCM_VerifyMessage (if this fails, reject the message).
See <http://en.wikipedia.org/wiki/Galois/Counter_Mode> for more information.
*/
#if( AES_UTILS_HAS_GCM )
#define kAES_CGM_Size 16
#define kAES_CGM_Nonce_None NULL // When passed to AES_GCM_Init it means the caller is using a per-message nonce.
#define kAES_CGM_Nonce_Auto NULL // When passed to AES_GCM_Encrypt, it means use the internal, auto-incremented nonce.
typedef struct
{
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
CCCryptorRef cryptor;
#elif( AES_UTILS_HAS_GLADMAN_GCM )
gcm_ctx ctx;
#else
#error "GCM enabled, but no implementation?"
#endif
uint8_t nonce[ kAES_CGM_Size ];
} AES_GCM_Context;
OSStatus
AES_GCM_Init(
AES_GCM_Context * inContext,
const uint8_t inKey[ kAES_CGM_Size ],
const uint8_t inNonce[ kAES_CGM_Size ] ); // May be kAES_CGM_Nonce_None for per-message nonces.
void AES_GCM_Final( AES_GCM_Context *inContext );
OSStatus AES_GCM_InitMessage( AES_GCM_Context *inContext, const uint8_t *inNonce );
OSStatus AES_GCM_FinalizeMessage( AES_GCM_Context *inContext, uint8_t outAuthTag[ kAES_CGM_Size ] );
OSStatus AES_GCM_VerifyMessage( AES_GCM_Context *inContext, const uint8_t inAuthTag[ kAES_CGM_Size ] );
OSStatus AES_GCM_AddAAD( AES_GCM_Context *inContext, const void *inPtr, size_t inLen );
OSStatus AES_GCM_Encrypt( AES_GCM_Context *inContext, const void *inSrc, size_t inLen, void *inDst );
OSStatus AES_GCM_Decrypt( AES_GCM_Context *inContext, const void *inSrc, size_t inLen, void *inDst );
#endif // AES_UTILS_HAS_GCM
#ifdef __cplusplus
}
#endif
#endif // __AESUtils_h__