mirror of
https://github.com/oopuuu/zTC1.git
synced 2025-12-16 15:08:15 +08:00
872 lines
32 KiB
C
872 lines
32 KiB
C
/**
|
|
******************************************************************************
|
|
* @file AESUtils.c
|
|
* @author William Xu
|
|
* @version V1.0.0
|
|
* @date 05-May-2014
|
|
* @brief This file contains functiond 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.
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "AESUtils.h"
|
|
|
|
#include "common.h"
|
|
#include "debug.h"
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
#include <CommonCrypto/CommonCryptorSPI.h>
|
|
#endif
|
|
|
|
#if( !AES_UTILS_USE_COMMON_CRYPTO && !AES_UTILS_USE_GLADMAN_AES && TARGET_NO_OPENSSL )
|
|
static
|
|
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
|
const unsigned long length, const AES_KEY *key,
|
|
unsigned char *ivec, const int enc);
|
|
#endif
|
|
|
|
#define aes_log(M, ...) custom_log("AES", M, ##__VA_ARGS__)
|
|
|
|
//===========================================================================================================================
|
|
// AES_CTR_Init
|
|
//===========================================================================================================================
|
|
|
|
OSStatus
|
|
AES_CTR_Init(
|
|
AES_CTR_Context * inContext,
|
|
const uint8_t inKey[ kAES_CTR_Size ],
|
|
const uint8_t inNonce[ kAES_CTR_Size ] )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
OSStatus err;
|
|
|
|
inContext->cryptor = NULL;
|
|
err = CCCryptorCreate( kCCEncrypt, kCCAlgorithmAES128, kCCOptionECBMode, inKey, kAES_CTR_Size, NULL,
|
|
&inContext->cryptor );
|
|
check_noerr( err );
|
|
if( err ) return( err );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
aes_init();
|
|
aes_encrypt_key128( inKey, &inContext->ctx );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesSetKeyDirect(&inContext->ctx, (unsigned char *) inKey, AES_BLOCK_SIZE, inNonce, AES_ENCRYPTION);
|
|
#elif( AES_UTILS_USE_USSL )
|
|
aes_setkey_enc( &inContext->ctx, (unsigned char *) inKey, kAES_CTR_Size * 8 );
|
|
#else
|
|
AES_set_encrypt_key( inKey, kAES_CTR_Size * 8, &inContext->key );
|
|
#endif
|
|
memcpy( inContext->ctr, inNonce, kAES_CTR_Size );
|
|
inContext->used = 0;
|
|
inContext->legacy = false;
|
|
return( kNoErr );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_CTR_Increment
|
|
//===========================================================================================================================
|
|
|
|
static inline void AES_CTR_Increment( uint8_t *inCounter )
|
|
{
|
|
int i;
|
|
|
|
// Note: counter is always big endian so this adds from right to left.
|
|
|
|
for( i = kAES_CTR_Size - 1; i >= 0; --i )
|
|
{
|
|
if( ++( inCounter[ i ] ) != 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_CTR_Update
|
|
//===========================================================================================================================
|
|
|
|
OSStatus AES_CTR_Update( AES_CTR_Context *inContext, const void *inSrc, size_t inLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
const uint8_t * src;
|
|
uint8_t * dst;
|
|
uint8_t * buf;
|
|
size_t used;
|
|
size_t i;
|
|
|
|
// inSrc and inDst may be the same, but otherwise, the buffers must not overlap.
|
|
|
|
#if( DEBUG )
|
|
if( inSrc != inDst ) check_ptr_overlap( inSrc, inLen, inDst, inLen );
|
|
#endif
|
|
|
|
src = (const uint8_t *) inSrc;
|
|
dst = (uint8_t *) inDst;
|
|
|
|
// If there's any buffered key material from a previous block then use that first.
|
|
|
|
buf = inContext->buf;
|
|
used = inContext->used;
|
|
while( ( inLen > 0 ) && ( used != 0 ) )
|
|
{
|
|
*dst++ = *src++ ^ buf[ used++ ];
|
|
used %= kAES_CTR_Size;
|
|
inLen -= 1;
|
|
}
|
|
inContext->used = used;
|
|
|
|
// Process whole blocks.
|
|
|
|
while( inLen >= kAES_CTR_Size )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
err = CCCryptorUpdate( inContext->cryptor, inContext->ctr, kAES_CTR_Size, buf, kAES_CTR_Size, &i );
|
|
require_noerr( err, exit );
|
|
require_action( i == kAES_CTR_Size, exit, err = kSizeErr );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
aes_ecb_encrypt( inContext->ctr, buf, kAES_CTR_Size, &inContext->ctx );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesEncryptDirect( &inContext->ctx, buf, inContext->ctr );
|
|
#elif( AES_UTILS_USE_USSL )
|
|
aes_crypt_ecb( &inContext->ctx, AES_ENCRYPT, inContext->ctr, buf );
|
|
#else
|
|
AES_encrypt( inContext->ctr, buf, &inContext->key );
|
|
#endif
|
|
AES_CTR_Increment( inContext->ctr );
|
|
|
|
for( i = 0; i < kAES_CTR_Size; ++i )
|
|
{
|
|
dst[ i ] = src[ i ] ^ buf[ i ];
|
|
}
|
|
src += kAES_CTR_Size;
|
|
dst += kAES_CTR_Size;
|
|
inLen -= kAES_CTR_Size;
|
|
}
|
|
|
|
// Process any trailing sub-block bytes. Extra key material is buffered for next time.
|
|
|
|
if( inLen > 0 )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
err = CCCryptorUpdate( inContext->cryptor, inContext->ctr, kAES_CTR_Size, buf, kAES_CTR_Size, &i );
|
|
require_noerr( err, exit );
|
|
require_action( i == kAES_CTR_Size, exit, err = kSizeErr );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
aes_ecb_encrypt( inContext->ctr, buf, kAES_CTR_Size, &inContext->ctx );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesEncryptDirect( &inContext->ctx, buf, inContext->ctr );
|
|
#elif( AES_UTILS_USE_USSL )
|
|
aes_crypt_ecb( &inContext->ctx, AES_ENCRYPT, inContext->ctr, buf );
|
|
#else
|
|
AES_encrypt( inContext->ctr, buf, &inContext->key );
|
|
#endif
|
|
AES_CTR_Increment( inContext->ctr );
|
|
|
|
for( i = 0; i < inLen; ++i )
|
|
{
|
|
*dst++ = *src++ ^ buf[ used++ ];
|
|
}
|
|
|
|
// For legacy mode, always leave the used amount as 0 so we always increment the counter each time.
|
|
|
|
if( !inContext->legacy )
|
|
{
|
|
inContext->used = used;
|
|
}
|
|
}
|
|
err = kNoErr;
|
|
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
exit:
|
|
#endif
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_CTR_Final
|
|
//===========================================================================================================================
|
|
|
|
void AES_CTR_Final( AES_CTR_Context *inContext )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
if( inContext->cryptor ) CCCryptorRelease( inContext->cryptor );
|
|
#endif
|
|
memset( inContext, 0, sizeof( *inContext ) ); // Clear sensitive data.
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// AES_CBCFrame_Init
|
|
//===========================================================================================================================
|
|
|
|
OSStatus
|
|
AES_CBCFrame_Init(
|
|
AES_CBCFrame_Context * inContext,
|
|
const uint8_t inKey[ kAES_CBCFrame_Size ],
|
|
const uint8_t inIV[ kAES_CBCFrame_Size ],
|
|
Boolean inEncrypt )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
OSStatus err;
|
|
|
|
inContext->cryptor = NULL;
|
|
err = CCCryptorCreate( inEncrypt ? kCCEncrypt : kCCDecrypt, kCCAlgorithmAES128, 0, inKey, kAES_CTR_Size,
|
|
NULL, &inContext->cryptor );
|
|
check_noerr( err );
|
|
if( err ) return( err );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
aes_init();
|
|
if( inEncrypt ) aes_encrypt_key128( inKey, &inContext->ctx.encrypt );
|
|
else aes_decrypt_key128( inKey, &inContext->ctx.decrypt );
|
|
inContext->encrypt = inEncrypt;
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
if( inEncrypt ) AesSetKeyDirect(&inContext->ctx, (unsigned char *) inKey, AES_BLOCK_SIZE, inIV, AES_ENCRYPTION);
|
|
else AesSetKeyDirect(&inContext->ctx, (unsigned char *) inKey, AES_BLOCK_SIZE, inIV, AES_DECRYPTION);
|
|
#elif( AES_UTILS_USE_USSL )
|
|
if( inEncrypt ) aes_setkey_enc( &inContext->ctx, (unsigned char *) inKey, kAES_CBCFrame_Size * 8 );
|
|
else aes_setkey_dec( &inContext->ctx, (unsigned char *) inKey, kAES_CBCFrame_Size * 8 );
|
|
inContext->encrypt = inEncrypt;
|
|
#else
|
|
if( inEncrypt ) AES_set_encrypt_key( inKey, kAES_CBCFrame_Size * 8, &inContext->key );
|
|
else AES_set_decrypt_key( inKey, kAES_CBCFrame_Size * 8, &inContext->key );
|
|
inContext->mode = inEncrypt ? AES_ENCRYPT : AES_DECRYPT;
|
|
#endif
|
|
memcpy( inContext->iv, inIV, kAES_CBCFrame_Size );
|
|
return( kNoErr );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_CBCFrame_Update
|
|
//===========================================================================================================================
|
|
|
|
OSStatus AES_CBCFrame_Update( AES_CBCFrame_Context *inContext, const void *inSrc, size_t inSrcLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
const uint8_t * src;
|
|
const uint8_t * end;
|
|
uint8_t * dst;
|
|
size_t len;
|
|
|
|
src = (const uint8_t *) inSrc;
|
|
end = src + inSrcLen;
|
|
dst = (uint8_t *) inDst;
|
|
|
|
// Process whole blocks.
|
|
|
|
len = inSrcLen & ~( (size_t)( kAES_CBCFrame_Size - 1 ) );
|
|
if( len > 0 )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
err = CCCryptorReset( inContext->cryptor, inContext->iv );
|
|
require_noerr( err, exit );
|
|
|
|
err = CCCryptorUpdate( inContext->cryptor, src, len, dst, len, &len );
|
|
require_noerr( err, exit );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
uint8_t iv[ kAES_CBCFrame_Size ];
|
|
|
|
memcpy( iv, inContext->iv, kAES_CBCFrame_Size ); // Use local copy so original IV is not changed.
|
|
if( inContext->encrypt ) aes_cbc_encrypt( src, dst, (int) len, iv, &inContext->ctx.encrypt );
|
|
else aes_cbc_decrypt( src, dst, (int) len, iv, &inContext->ctx.decrypt );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesCbcEncrypt(&inContext->ctx, dst, src, len);
|
|
#elif( AES_UTILS_USE_USSL )
|
|
uint8_t iv[ kAES_CBCFrame_Size ];
|
|
|
|
memcpy( iv, inContext->iv, kAES_CBCFrame_Size ); // Use local copy so original IV is not changed.
|
|
if( inContext->encrypt ) aes_crypt_cbc( &inContext->ctx, AES_ENCRYPT, len, iv, (unsigned char *) src, dst );
|
|
else aes_crypt_cbc( &inContext->ctx, AES_DECRYPT, len, iv, (unsigned char *) src, dst );
|
|
#else
|
|
uint8_t iv[ kAES_CBCFrame_Size ];
|
|
|
|
memcpy( iv, inContext->iv, kAES_CBCFrame_Size ); // Use local copy so original IV is not changed.
|
|
AES_cbc_encrypt( src, dst, (unsigned long) len, &inContext->key, iv, inContext->mode );
|
|
#endif
|
|
src += len;
|
|
dst += len;
|
|
}
|
|
|
|
// The remaining bytes are just copied unencrypted.
|
|
|
|
while( src != end ) *dst++ = *src++;
|
|
err = kNoErr;
|
|
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
exit:
|
|
#endif
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_CBCFrame_Update2
|
|
//===========================================================================================================================
|
|
|
|
OSStatus
|
|
AES_CBCFrame_Update2(
|
|
AES_CBCFrame_Context * inContext,
|
|
const void * inSrc1,
|
|
size_t inLen1,
|
|
const void * inSrc2,
|
|
size_t inLen2,
|
|
void * inDst )
|
|
{
|
|
const uint8_t * src1 = (const uint8_t *) inSrc1;
|
|
const uint8_t * end1 = src1 + inLen1;
|
|
const uint8_t * src2 = (const uint8_t *) inSrc2;
|
|
const uint8_t * end2 = src2 + inLen2;
|
|
uint8_t * dst = (uint8_t *) inDst;
|
|
OSStatus err;
|
|
size_t len;
|
|
size_t i;
|
|
#if( !AES_UTILS_USE_COMMON_CRYPTO )
|
|
uint8_t iv[ kAES_CBCFrame_Size ];
|
|
#endif
|
|
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
if( ( inLen1 + inLen2 ) >= kAES_CBCFrame_Size )
|
|
{
|
|
err = CCCryptorReset( inContext->cryptor, inContext->iv );
|
|
require_noerr( err, exit );
|
|
}
|
|
#else
|
|
memcpy( iv, inContext->iv, kAES_CBCFrame_Size ); // Use local copy so original IV is not changed.
|
|
#endif
|
|
|
|
// Process all whole blocks from buffer 1.
|
|
|
|
len = inLen1 & ~( (size_t)( kAES_CBCFrame_Size - 1 ) );
|
|
if( len > 0 )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
err = CCCryptorUpdate( inContext->cryptor, src1, len, dst, len, &len );
|
|
require_noerr( err, exit );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
if( inContext->encrypt ) aes_cbc_encrypt( src1, dst, (int) len, iv, &inContext->ctx.encrypt );
|
|
else aes_cbc_decrypt( src1, dst, (int) len, iv, &inContext->ctx.decrypt );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesCbcEncrypt(&inContext->ctx, dst, src1, len);
|
|
#elif( AES_UTILS_USE_USSL )
|
|
if( inContext->encrypt ) aes_crypt_cbc( &inContext->ctx, AES_ENCRYPT, len, iv, (unsigned char *) src1, dst );
|
|
else aes_crypt_cbc( &inContext->ctx, AES_DECRYPT, len, iv, (unsigned char *) src1, dst );
|
|
#else
|
|
AES_cbc_encrypt( src1, dst, (unsigned long) len, &inContext->key, iv, inContext->mode );
|
|
#endif
|
|
src1 += len;
|
|
dst += len;
|
|
}
|
|
|
|
// If there are any partial block bytes in buffer 1 and enough bytes in buffer 2 to fill a
|
|
// block then combine them into a temporary buffer and encrypt it.
|
|
|
|
if( ( src1 != end1 ) && ( ( ( end1 - src1 ) + ( end2 - src2 ) ) >= kAES_CBCFrame_Size ) )
|
|
{
|
|
uint8_t buf[ kAES_CBCFrame_Size ];
|
|
|
|
for( i = 0; src1 != end1; ++i )
|
|
{
|
|
buf[ i ] = *src1++;
|
|
}
|
|
for( ; ( i < kAES_CBCFrame_Size ) && ( src2 != end2 ); ++i )
|
|
{
|
|
buf[ i ] = *src2++;
|
|
}
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
err = CCCryptorUpdate( inContext->cryptor, buf, i, dst, i, &i );
|
|
require_noerr( err, exit );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
if( inContext->encrypt ) aes_cbc_encrypt( buf, dst, (int) i, iv, &inContext->ctx.encrypt );
|
|
else aes_cbc_decrypt( buf, dst, (int) i, iv, &inContext->ctx.decrypt );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesCbcEncrypt(&inContext->ctx, dst, buf, i);
|
|
#elif( AES_UTILS_USE_USSL )
|
|
if( inContext->encrypt ) aes_crypt_cbc( &inContext->ctx, AES_ENCRYPT, i, iv, buf, dst );
|
|
else aes_crypt_cbc( &inContext->ctx, AES_DECRYPT, i, iv, buf, dst );
|
|
#else
|
|
AES_cbc_encrypt( buf, dst, (unsigned long) i, &inContext->key, iv, inContext->mode );
|
|
#endif
|
|
dst += i;
|
|
}
|
|
|
|
// Process any remaining whole blocks in buffer 2.
|
|
|
|
len = ( (size_t)( end2 - src2 ) ) & ~( (size_t)( kAES_CBCFrame_Size - 1 ) );
|
|
if( len > 0 )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
err = CCCryptorUpdate( inContext->cryptor, src2, len, dst, len, &len );
|
|
require_noerr( err, exit );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
if( inContext->encrypt ) aes_cbc_encrypt( src2, dst, (int) len, iv, &inContext->ctx.encrypt );
|
|
else aes_cbc_decrypt( src2, dst, (int) len, iv, &inContext->ctx.decrypt );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesCbcEncrypt(&inContext->ctx, dst, src2, len);
|
|
#elif( AES_UTILS_USE_USSL )
|
|
if( inContext->encrypt ) aes_crypt_cbc( &inContext->ctx, AES_ENCRYPT, len, iv, (unsigned char *) src2, dst );
|
|
else aes_crypt_cbc( &inContext->ctx, AES_DECRYPT, len, iv, (unsigned char *) src2, dst );
|
|
#else
|
|
AES_cbc_encrypt( src2, dst, (unsigned long) len, &inContext->key, iv, inContext->mode );
|
|
#endif
|
|
src2 += len;
|
|
dst += len;
|
|
}
|
|
|
|
// Any remaining bytes are just copied unencrypted.
|
|
|
|
while( src1 != end1 ) *dst++ = *src1++;
|
|
while( src2 != end2 ) *dst++ = *src2++;
|
|
err = kNoErr;
|
|
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
exit:
|
|
#endif
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_CBCFrame_Final
|
|
//===========================================================================================================================
|
|
|
|
void AES_CBCFrame_Final( AES_CBCFrame_Context *inContext )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
if( inContext->cryptor ) CCCryptorRelease( inContext->cryptor );
|
|
#endif
|
|
memset( inContext, 0, sizeof( *inContext ) ); // Clear sensitive data.
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_cbc_encrypt
|
|
//===========================================================================================================================
|
|
|
|
#if( !AES_UTILS_USE_COMMON_CRYPTO && !AES_UTILS_USE_GLADMAN_AES && !AES_UTILS_USE_MICO_AES && TARGET_NO_OPENSSL )
|
|
// From OpenSSL
|
|
static
|
|
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
|
const unsigned long length, const AES_KEY *key,
|
|
unsigned char *ivec, const int enc) {
|
|
|
|
unsigned long n;
|
|
unsigned long len = length;
|
|
unsigned char tmp[AES_BLOCK_SIZE];
|
|
const unsigned char *iv = ivec;
|
|
|
|
if (AES_ENCRYPT == enc) {
|
|
while (len >= AES_BLOCK_SIZE) {
|
|
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
|
out[n] = in[n] ^ iv[n];
|
|
AES_encrypt(out, out, key);
|
|
iv = out;
|
|
len -= AES_BLOCK_SIZE;
|
|
in += AES_BLOCK_SIZE;
|
|
out += AES_BLOCK_SIZE;
|
|
}
|
|
if (len) {
|
|
for(n=0; n < len; ++n)
|
|
out[n] = in[n] ^ iv[n];
|
|
for(n=len; n < AES_BLOCK_SIZE; ++n)
|
|
out[n] = iv[n];
|
|
AES_encrypt(out, out, key);
|
|
iv = out;
|
|
}
|
|
memcpy(ivec,iv,AES_BLOCK_SIZE);
|
|
} else if (in != out) {
|
|
while (len >= AES_BLOCK_SIZE) {
|
|
AES_decrypt(in, out, key);
|
|
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
|
out[n] ^= iv[n];
|
|
iv = in;
|
|
len -= AES_BLOCK_SIZE;
|
|
in += AES_BLOCK_SIZE;
|
|
out += AES_BLOCK_SIZE;
|
|
}
|
|
if (len) {
|
|
AES_decrypt(in,tmp,key);
|
|
for(n=0; n < len; ++n)
|
|
out[n] = tmp[n] ^ iv[n];
|
|
iv = in;
|
|
}
|
|
memcpy(ivec,iv,AES_BLOCK_SIZE);
|
|
} else {
|
|
while (len >= AES_BLOCK_SIZE) {
|
|
memcpy(tmp, in, AES_BLOCK_SIZE);
|
|
AES_decrypt(in, out, key);
|
|
for(n=0; n < AES_BLOCK_SIZE; ++n)
|
|
out[n] ^= ivec[n];
|
|
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
|
len -= AES_BLOCK_SIZE;
|
|
in += AES_BLOCK_SIZE;
|
|
out += AES_BLOCK_SIZE;
|
|
}
|
|
if (len) {
|
|
memcpy(tmp, in, AES_BLOCK_SIZE);
|
|
AES_decrypt(tmp, out, key);
|
|
for(n=0; n < len; ++n)
|
|
out[n] ^= ivec[n];
|
|
for(n=len; n < AES_BLOCK_SIZE; ++n)
|
|
out[n] = tmp[n];
|
|
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// AES_ECB_Init
|
|
//===========================================================================================================================
|
|
|
|
OSStatus AES_ECB_Init( AES_ECB_Context *inContext, uint32_t inMode, const uint8_t inKey[ kAES_ECB_Size ] )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
OSStatus err;
|
|
|
|
inContext->cryptor = NULL;
|
|
err = CCCryptorCreate( inMode, kCCAlgorithmAES128, kCCOptionECBMode, inKey, kAES_ECB_Size, NULL, &inContext->cryptor );
|
|
check_noerr( err );
|
|
if( err ) return( err );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
aes_init();
|
|
if( inMode == kAES_ECB_Mode_Encrypt ) aes_encrypt_key128( inKey, &inContext->ctx.encrypt );
|
|
else aes_decrypt_key128( inKey, &inContext->ctx.decrypt );
|
|
inContext->encrypt = inMode;
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
if( inMode == kAES_ECB_Mode_Encrypt ) AesSetKey( &inContext->ctx, inKey, kAES_ECB_Size, NULL, AES_ENCRYPTION );
|
|
else AesSetKey( &inContext->ctx, inKey, kAES_ECB_Size, NULL, AES_DECRYPTION );
|
|
#elif( AES_UTILS_USE_USSL )
|
|
if( inMode == kAES_ECB_Mode_Encrypt ) aes_setkey_enc( &inContext->ctx, (unsigned char *) inKey, kAES_ECB_Size * 8 );
|
|
else aes_setkey_dec( &inContext->ctx, (unsigned char *) inKey, kAES_ECB_Size * 8 );
|
|
inContext->mode = inMode;
|
|
#else
|
|
AES_set_encrypt_key( inKey, kAES_ECB_Size * 8, &inContext->key );
|
|
inContext->cryptFunc = ( inMode == kAES_ECB_Mode_Encrypt ) ? AES_encrypt : AES_decrypt;
|
|
#endif
|
|
return( kNoErr );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_ECB_Update
|
|
//===========================================================================================================================
|
|
|
|
OSStatus AES_ECB_Update( AES_ECB_Context *inContext, const void *inSrc, size_t inLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
const uint8_t * src;
|
|
uint8_t * dst;
|
|
size_t n;
|
|
|
|
// inSrc and inDst may be the same, but otherwise, the buffers must not overlap.
|
|
|
|
#if( DEBUG )
|
|
if( inSrc != inDst ) check_ptr_overlap( inSrc, inLen, inDst, inLen );
|
|
if( ( inLen % kAES_ECB_Size ) != 0 ) aes_log( "ECB doesn't support non-block-sized operations (%d bytes)", (int)inLen );
|
|
#endif
|
|
|
|
src = (const uint8_t *) inSrc;
|
|
dst = (uint8_t *) inDst;
|
|
for( n = inLen / kAES_ECB_Size; n > 0; --n )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
size_t len;
|
|
|
|
err = CCCryptorUpdate( inContext->cryptor, src, kAES_ECB_Size, dst, kAES_ECB_Size, &len );
|
|
require_noerr( err, exit );
|
|
check( len == kAES_ECB_Size );
|
|
#elif( AES_UTILS_USE_GLADMAN_AES )
|
|
if( inContext->encrypt ) aes_ecb_encrypt( src, dst, kAES_ECB_Size, &inContext->ctx.encrypt );
|
|
else aes_ecb_decrypt( src, dst, kAES_ECB_Size, &inContext->ctx.decrypt );
|
|
#elif( AES_UTILS_USE_MICO_AES )
|
|
AesEncryptDirect( &inContext->ctx, dst, src );
|
|
#elif( AES_UTILS_USE_USSL )
|
|
aes_crypt_ecb( &inContext->ctx, inContext->mode, (unsigned char *) src, dst );
|
|
#else
|
|
inContext->cryptFunc( src, dst, &inContext->key );
|
|
#endif
|
|
src += kAES_ECB_Size;
|
|
dst += kAES_ECB_Size;
|
|
}
|
|
err = kNoErr;
|
|
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
exit:
|
|
#endif
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_ECB_Final
|
|
//===========================================================================================================================
|
|
|
|
void AES_ECB_Final( AES_ECB_Context *inContext )
|
|
{
|
|
#if( AES_UTILS_USE_COMMON_CRYPTO )
|
|
if( inContext->cryptor ) CCCryptorRelease( inContext->cryptor );
|
|
#endif
|
|
memset( inContext, 0, sizeof( *inContext ) ); // Clear sensitive data.
|
|
}
|
|
|
|
#if 0
|
|
#pragma mark -
|
|
#endif
|
|
|
|
#if( AES_UTILS_HAS_GCM )
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_Init
|
|
//===========================================================================================================================
|
|
|
|
OSStatus
|
|
AES_GCM_Init(
|
|
AES_GCM_Context * inContext,
|
|
const uint8_t inKey[ kAES_CGM_Size ],
|
|
const uint8_t inNonce[ kAES_CGM_Size ] )
|
|
{
|
|
OSStatus err;
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
err = CCCryptorCreateWithMode( kCCEncrypt, kCCModeGCM, kCCAlgorithmAES128, ccNoPadding, NULL,
|
|
inKey, kAES_CGM_Size, NULL, 0, 0, 0, &inContext->cryptor );
|
|
require_noerr( err, exit );
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
err = gcm_init_and_key( inKey, kAES_CGM_Size, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
#else
|
|
#error "GCM enabled, but no implementation?"
|
|
#endif
|
|
|
|
if( inNonce ) memcpy( inContext->nonce, inNonce, kAES_CGM_Size );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_Final
|
|
//===========================================================================================================================
|
|
|
|
void AES_GCM_Final( AES_GCM_Context *inContext )
|
|
{
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
if( inContext->cryptor ) CCCryptorRelease( inContext->cryptor );
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
gcm_end( &inContext->ctx );
|
|
#else
|
|
#error "GCM enabled, but no implementation?"
|
|
#endif
|
|
memset( inContext, 0, sizeof( *inContext ) ); // Clear sensitive data.
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_InitMessage
|
|
//===========================================================================================================================
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
OSStatus AES_GCM_InitMessage( AES_GCM_Context *inContext, const uint8_t inNonce[ kAES_CGM_Size ] )
|
|
{
|
|
CCCryptorRef const cryptor = inContext->cryptor;
|
|
OSStatus err;
|
|
|
|
err = CCCryptorGCMReset( cryptor );
|
|
require_noerr( err, exit );
|
|
|
|
if( inNonce == kAES_CGM_Nonce_Auto )
|
|
{
|
|
AES_CTR_Increment( inContext->nonce );
|
|
inNonce = inContext->nonce;
|
|
}
|
|
err = CCCryptorGCMAddIV( cryptor, inNonce, kAES_CGM_Size );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
OSStatus AES_GCM_InitMessage( AES_GCM_Context *inContext, const uint8_t inNonce[ kAES_CGM_Size ] )
|
|
{
|
|
OSStatus err;
|
|
|
|
if( inNonce == kAES_CGM_Nonce_Auto )
|
|
{
|
|
AES_CTR_Increment( inContext->nonce );
|
|
inNonce = inContext->nonce;
|
|
}
|
|
err = gcm_init_message( inNonce, kAES_CGM_Size, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_FinalizeMessage
|
|
//===========================================================================================================================
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
OSStatus AES_GCM_FinalizeMessage( AES_GCM_Context *inContext, uint8_t outAuthTag[ kAES_CGM_Size ] )
|
|
{
|
|
OSStatus err;
|
|
size_t len;
|
|
|
|
len = kAES_CGM_Size;
|
|
err = CCCryptorGCMFinal( inContext->cryptor, outAuthTag, &len );
|
|
require_noerr( err, exit );
|
|
require_action( len == kAES_CGM_Size, exit, err = kSizeErr );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
OSStatus AES_GCM_FinalizeMessage( AES_GCM_Context *inContext, uint8_t outAuthTag[ kAES_CGM_Size ] )
|
|
{
|
|
OSStatus err;
|
|
|
|
err = gcm_compute_tag( outAuthTag, kAES_CGM_Size, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_VerifyMessage
|
|
//===========================================================================================================================
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
OSStatus AES_GCM_VerifyMessage( AES_GCM_Context *inContext, const uint8_t inAuthTag[ kAES_CGM_Size ] )
|
|
{
|
|
OSStatus err;
|
|
size_t len;
|
|
uint8_t authTag[ kAES_CGM_Size ];
|
|
|
|
len = kAES_CGM_Size;
|
|
err = CCCryptorGCMFinal( inContext->cryptor, authTag, &len );
|
|
require_noerr( err, exit );
|
|
require_action( len == kAES_CGM_Size, exit, err = kSizeErr );
|
|
require_action_quiet( memcmp_constant_time( authTag, inAuthTag, len ) == 0, exit, err = kAuthenticationErr );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
OSStatus AES_GCM_VerifyMessage( AES_GCM_Context *inContext, const uint8_t inAuthTag[ kAES_CGM_Size ] )
|
|
{
|
|
OSStatus err;
|
|
uint8_t authTag[ kAES_CGM_Size ];
|
|
|
|
err = gcm_compute_tag( authTag, kAES_CGM_Size, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
require_action_quiet( memcmp_constant_time( authTag, inAuthTag, kAES_CGM_Size ) == 0, exit, err = kAuthenticationErr );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_AddAAD
|
|
//===========================================================================================================================
|
|
|
|
OSStatus AES_GCM_AddAAD( AES_GCM_Context *inContext, const void *inPtr, size_t inLen )
|
|
{
|
|
OSStatus err;
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
err = CCCryptorGCMaddAAD( inContext->cryptor, inPtr, inLen );
|
|
require_noerr( err, exit );
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
err = gcm_auth_header( inPtr, inLen, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
#else
|
|
#error "GCM enabled, but no implementation?"
|
|
#endif
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_Encrypt
|
|
//===========================================================================================================================
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
OSStatus AES_GCM_Encrypt( AES_GCM_Context *inContext, const void *inSrc, size_t inLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
|
|
err = CCCryptorGCMEncrypt( inContext->cryptor, inSrc, inLen, inDst );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
OSStatus AES_GCM_Encrypt( AES_GCM_Context *inContext, const void *inSrc, size_t inLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
|
|
err = gcm_encrypt( inDst, inSrc, inLen, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#endif
|
|
|
|
//===========================================================================================================================
|
|
// AES_GCM_Decrypt
|
|
//===========================================================================================================================
|
|
|
|
#if( AES_UTILS_HAS_COMMON_CRYPTO_GCM )
|
|
OSStatus AES_GCM_Decrypt( AES_GCM_Context *inContext, const void *inSrc, size_t inLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
|
|
err = CCCryptorGCMDecrypt( inContext->cryptor, inSrc, inLen, inDst );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#elif( AES_UTILS_HAS_GLADMAN_GCM )
|
|
OSStatus AES_GCM_Decrypt( AES_GCM_Context *inContext, const void *inSrc, size_t inLen, void *inDst )
|
|
{
|
|
OSStatus err;
|
|
|
|
err = gcm_decrypt( inDst, inSrc, inLen, &inContext->ctx );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
return( err );
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|