Version 2.1.0

* Changed implementation of AES to one which is almost 5 times as fast. The new implementation comes from LibTomCrypt. The newer implementation produces a larger binary size as a trade-off.
* AES-CTR module now supports OpenMP and when compiled with OpenMP will run in parallel giving a much greater speed.
* Changed interface for Initialisation functions for both AES and AES-CTR to be match RC4 (The context is first parameter not last)
This commit is contained in:
waterjuice
2017-12-11 11:22:29 +11:00
parent 33bf2dc97f
commit 3201fb4d83
25 changed files with 1144 additions and 624 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +1,22 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CryptLib_Aes
//
// Implementation of AES block cipher. Originally written by Kokke (https://github.com/kokke). Modified by WaterJuice
// retaining Public Domain license.
// Implementation of AES block cipher. This implementation was modified from LibTomCrypt written by Tom St Denis
// (https://github.com/libtom). Modified by WaterJuice retaining Public Domain license.
// Derived from Public Domain source by original authors:
// Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
// Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
// Paulo Barreto <paulo.barreto@terra.com.br>
//
// AES is a block cipher that operates on 128 bit blocks. Encryption an Decryption routines use an AesContext which
// must be initialised with the key. An AesContext can be initialised with a 128, 192, or 256 bit key. Use the
// AesInitialise[n] functions to initialise the context with the key. Once an AES context is initialised its contents
// are not changed by the encrypting and decrypting functions. A context only needs to be initialised once for any
// given key and the context may be used by the encrypt/decrypt functions in simultaneous threads.
// All operations are performed byte wise and this implementation works in both little and endian processors.
// All operations are performed BYTE wise and this implementation works in both little and endian processors.
// There are no alignment requirements with the keys and data blocks.
//
// This is free and unencumbered software released into the public domain - November 2017 waterjuice.org
// This is free and unencumbered software released into the public domain - December 2017 waterjuice.org
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
@@ -36,9 +40,9 @@
// Do not modify the contents of this structure directly.
typedef struct
{
uint32_t KeySizeInWords;
uint32_t NumberOfRounds;
uint8_t RoundKey[240];
uint32_t eK[60];
uint32_t dK[60];
uint_fast32_t Nr;
} AesContext;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -46,39 +50,17 @@ typedef struct
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AesInitialise128
// AesInitialise
//
// Initialises an AesContext with a 128 bit key.
// Initialises an AesContext with an AES Key. KeySize must be 16, 24, or 32 (for 128, 192, or 256 bit key size)
// Returns 0 if successful, or -1 if invalid KeySize provided
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
AesInitialise128
int
AesInitialise
(
uint8_t const Key [AES_KEY_SIZE_128], // [in]
AesContext* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AesInitialise192
//
// Initialises an AesContext with a 192 bit key.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
AesInitialise192
(
uint8_t const Key [AES_KEY_SIZE_192], // [in]
AesContext* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AesInitialise256
//
// Initialises an AesContext with a 256 bit key.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
AesInitialise256
(
uint8_t const Key [AES_KEY_SIZE_256], // [in]
AesContext* Context // [out]
AesContext* Context, // [out]
void const* Key, // [in]
uint32_t KeySize // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -96,9 +96,9 @@ void
void
AesCtrInitialise
(
AesCtrContext* Context, // [out]
AesContext const* InitialisedAesContext, // [in]
uint8_t const IV [AES_CTR_IV_SIZE], // [in]
AesCtrContext* Context // [out]
uint8_t const IV [AES_CTR_IV_SIZE] // [in]
)
{
// Setup context values
@@ -121,27 +121,22 @@ void
int
AesCtrInitialiseWithKey
(
AesCtrContext* Context, // [out]
uint8_t const* Key, // [in]
uint32_t KeySize, // [in]
uint8_t const IV [AES_CTR_IV_SIZE], // [in]
AesCtrContext* Context // [out]
uint8_t const IV [AES_CTR_IV_SIZE] // [in]
)
{
AesContext aes;
// Initialise AES Context
switch( KeySize )
if( 0 != AesInitialise( &aes, Key, KeySize ) )
{
case AES_KEY_SIZE_128: AesInitialise128( Key, &aes ); break;
case AES_KEY_SIZE_192: AesInitialise192( Key, &aes ); break;
case AES_KEY_SIZE_256: AesInitialise256( Key, &aes ); break;
default:
// Invalid key size
return -1;
}
// Now set-up AesCtrContext
AesCtrInitialise( &aes, IV, Context );
AesCtrInitialise( Context, &aes, IV );
return 0;
}
@@ -177,7 +172,7 @@ void
// advance the stream index by that number of bytes.
// Use once over data to encrypt it. Use it a second time over the same data from the same stream position and the
// data will be decrypted.
// InBuffer and OutBuffer can point to the same location for inplace encrypting/decrypting
// InBuffer and OutBuffer can point to the same location for in-place encrypting/decrypting
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
AesCtrXor
@@ -188,47 +183,68 @@ void
uint32_t Size // [in]
)
{
uint32_t amountLeft = Size;
uint32_t outputOffset = 0;
uint32_t chunkSize;
uint32_t amountAvailableInBlock;
uint32_t firstChunkSize;
uint32_t amountAvailableInBlock;
int numIterations;
int i;
uint64_t loopStartingCipherBlockIndex;
uint32_t loopStartingOutputOffset;
uint8_t preCipherBlock [AES_KEY_SIZE_128];
uint8_t encCipherBlock [AES_KEY_SIZE_128];
uint64_t cipherBlockIndex = 0;
// First determine how much is available in the current block.
amountAvailableInBlock = AES_BLOCK_SIZE - (Context->StreamIndex % AES_BLOCK_SIZE);
// Determine how much of the current block we will take, either all that is available, or less
// if the amount requested is smaller.
chunkSize = MIN( amountAvailableInBlock, amountLeft );
firstChunkSize = MIN( amountAvailableInBlock, Size );
// XOR the bytes from the cipher block
XorBuffers( InBuffer, Context->CurrentCipherBlock + (AES_BLOCK_SIZE - amountAvailableInBlock), OutBuffer, chunkSize );
XorBuffers( InBuffer, Context->CurrentCipherBlock + (AES_BLOCK_SIZE - amountAvailableInBlock), OutBuffer, firstChunkSize );
amountLeft -= chunkSize;
outputOffset += chunkSize;
// Determine how many iterations will be needed for generating cipher blocks.
// We always have to finish with a non-depleted cipher block.
// Also calculate the cipher block index and the output offset for when we start the loop.
// This function may be built with OpenMP and the loop will run in parallel. So we set-up variables that will
// be common at the start of the loop.
numIterations = ( (Size - firstChunkSize) + AES_BLOCK_SIZE ) / AES_BLOCK_SIZE;
loopStartingCipherBlockIndex = Context->CurrentCipherBlockIndex + 1;
loopStartingOutputOffset = firstChunkSize;
// Copy the IV into the first half of the preCipherBlock. When built for OpenMP preCipherBlock will be copied into
// a local version within the loop.
memcpy( preCipherBlock, Context->IV, AES_CTR_IV_SIZE );
// Now start generating new cipher blocks as required.
while( amountLeft > 0 )
#ifdef _OPENMP
#pragma omp parallel for firstprivate( preCipherBlock, cipherBlockIndex ) lastprivate( encCipherBlock, cipherBlockIndex )
#endif
for( i=0; i<numIterations; i++ )
{
uint32_t outputOffset = loopStartingOutputOffset + (AES_BLOCK_SIZE * i);
uint32_t amountLeft = Size - outputOffset;
uint32_t chunkSize = MIN( amountLeft, AES_BLOCK_SIZE );
// Increment block index and regenerate cipher block
Context->CurrentCipherBlockIndex += 1;
CreateCurrentCipherBlock( Context );
cipherBlockIndex = loopStartingCipherBlockIndex + i;
// Determine how much of the current block we need and XOR it out onto the buffer
chunkSize = MIN( amountLeft, AES_BLOCK_SIZE );
XorBuffers( (uint8_t*)InBuffer + outputOffset, Context->CurrentCipherBlock, (uint8_t*)OutBuffer + outputOffset, chunkSize );
// Now place in the counter in Big Endian form in second half of preCipherBlock
STORE64H( cipherBlockIndex, preCipherBlock + AES_CTR_IV_SIZE );
amountLeft -= chunkSize;
outputOffset += chunkSize;
// Perform AES encryption on the preCipherBlock and put result in encCipherBlock
AesEncrypt( &Context->Aes, preCipherBlock, encCipherBlock );
// XOR block out onto the buffer.
XorBuffers( (uint8_t*)InBuffer + outputOffset, encCipherBlock, (uint8_t*)OutBuffer + outputOffset, chunkSize );
}
// All data read out now, so update index in the context.
// Update context
Context->StreamIndex += Size;
// If we ended up completely reading the last cipher block we need to generate a new one for next time.
if( AES_BLOCK_SIZE == chunkSize )
if( numIterations > 0 )
{
Context->CurrentCipherBlockIndex += 1;
CreateCurrentCipherBlock( Context );
Context->CurrentCipherBlockIndex = cipherBlockIndex;
memcpy( Context->CurrentCipherBlock, encCipherBlock, AES_BLOCK_SIZE );
}
}
@@ -273,7 +289,7 @@ int
int error;
AesCtrContext context;
error = AesCtrInitialiseWithKey( Key, KeySize, IV, &context );
error = AesCtrInitialiseWithKey( &context, Key, KeySize, IV );
if( 0 == error )
{
AesCtrXor( &context, InBuffer, OutBuffer, BufferSize );

View File

@@ -54,9 +54,9 @@ typedef struct
void
AesCtrInitialise
(
AesCtrContext* Context, // [out]
AesContext const* InitialisedAesContext, // [in]
uint8_t const IV [AES_CTR_IV_SIZE], // [in]
AesCtrContext* Context // [out]
uint8_t const IV [AES_CTR_IV_SIZE] // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -69,10 +69,10 @@ void
int
AesCtrInitialiseWithKey
(
AesCtrContext* Context, // [out]
uint8_t const* Key, // [in]
uint32_t KeySize, // [in]
uint8_t const IV [AES_CTR_IV_SIZE], // [in]
AesCtrContext* Context // [out]
uint8_t const IV [AES_CTR_IV_SIZE] // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,7 +95,7 @@ void
// advance the stream index by that number of bytes.
// Use once over data to encrypt it. Use it a second time over the same data from the same stream position and the
// data will be decrypted.
// InBuffer and OutBuffer can point to the same location for inplace encrypting/decrypting
// InBuffer and OutBuffer can point to the same location for in-place encrypting/decrypting
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void
AesCtrXor

View File

@@ -66,10 +66,10 @@ void*
#define GET(n) (ctx->block[(n)])
#define SET(n) (ctx->block[(n)] = \
((uint32_t)ptr[(n)*4 + 0] << 0 ) \
| ((uint32_t)ptr[(n)*4 + 1] << 8 ) \
| ((uint32_t)ptr[(n)*4 + 2] << 16) \
| ((uint32_t)ptr[(n)*4 + 3] << 24) )
((uint32_t)ptr[(n)*4 + 0] << 0 ) \
| ((uint32_t)ptr[(n)*4 + 1] << 8 ) \
| ((uint32_t)ptr[(n)*4 + 2] << 16) \
| ((uint32_t)ptr[(n)*4 + 3] << 24) )
ptr = (uint8_t*)data;
@@ -188,7 +188,7 @@ void*
void
Md5Initialise
(
Md5Context* Context
Md5Context* Context // [out]
)
{
Context->a = 0x67452301;
@@ -209,9 +209,9 @@ void
void
Md5Update
(
Md5Context* Context,
void const* Buffer,
uint32_t BufferSize
Md5Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
)
{
uint32_t saved_lo;
@@ -261,8 +261,8 @@ void
void
Md5Finalise
(
Md5Context* Context,
MD5_HASH* Digest
Md5Context* Context, // [in out]
MD5_HASH* Digest // [in]
)
{
uint32_t used;

View File

@@ -52,7 +52,7 @@ typedef struct
void
Md5Initialise
(
Md5Context* Context
Md5Context* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -64,9 +64,9 @@ void
void
Md5Update
(
Md5Context* Context,
void const* Buffer,
uint32_t BufferSize
Md5Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -78,6 +78,6 @@ void
void
Md5Finalise
(
Md5Context* Context,
MD5_HASH* Digest
Md5Context* Context, // [in out]
MD5_HASH* Digest // [in]
);

View File

@@ -36,10 +36,10 @@
void
Rc4Initialise
(
Rc4Context* Context,
void const* Key,
uint32_t KeySize,
uint32_t DropN
Rc4Context* Context, // [out]
void const* Key, // [in]
uint32_t KeySize, // [in]
uint32_t DropN // [in]
)
{
uint32_t i;
@@ -82,9 +82,9 @@ void
void
Rc4Output
(
Rc4Context* Context,
void* Buffer,
uint32_t Size
Rc4Context* Context, // [in out]
void* Buffer, // [out]
uint32_t Size // [in]
)
{
uint32_t n;
@@ -108,10 +108,10 @@ void
void
Rc4Xor
(
Rc4Context* Context,
void const* InBuffer,
void* OutBuffer,
uint32_t Size
Rc4Context* Context, // [in out]
void const* InBuffer, // [in]
void* OutBuffer, // [out]
uint32_t Size // [in]
)
{
uint32_t n;

View File

@@ -38,10 +38,10 @@ typedef struct
void
Rc4Initialise
(
Rc4Context* Context,
void const* Key,
uint32_t KeySize,
uint32_t DropN
Rc4Context* Context, // [out]
void const* Key, // [in]
uint32_t KeySize, // [in]
uint32_t DropN // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -52,9 +52,9 @@ void
void
Rc4Output
(
Rc4Context* Context,
void* Buffer,
uint32_t Size
Rc4Context* Context, // [in out]
void* Buffer, // [out]
uint32_t Size // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -66,8 +66,8 @@ void
void
Rc4Xor
(
Rc4Context* Context,
void const* InBuffer,
void* OutBuffer,
uint32_t Size
Rc4Context* Context, // [in out]
void const* InBuffer, // [in]
void* OutBuffer, // [out]
uint32_t Size // [in]
);

View File

@@ -158,7 +158,7 @@ void
void
Sha1Initialise
(
Sha1Context* Context
Sha1Context* Context // [out]
)
{
// SHA1 initialisation constants
@@ -180,9 +180,9 @@ void
void
Sha1Update
(
Sha1Context* Context,
void const* Buffer,
uint32_t BufferSize
Sha1Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
)
{
uint32_t i;
@@ -223,8 +223,8 @@ void
void
Sha1Finalise
(
Sha1Context* Context,
SHA1_HASH* Digest
Sha1Context* Context, // [in out]
SHA1_HASH* Digest // [in]
)
{
uint32_t i;

View File

@@ -50,7 +50,7 @@ typedef struct
void
Sha1Initialise
(
Sha1Context* Context
Sha1Context* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -62,9 +62,9 @@ void
void
Sha1Update
(
Sha1Context* Context,
void const* Buffer,
uint32_t BufferSize
Sha1Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -76,6 +76,6 @@ void
void
Sha1Finalise
(
Sha1Context* Context,
SHA1_HASH* Digest
Sha1Context* Context, // [in out]
SHA1_HASH* Digest // [in]
);

View File

@@ -151,9 +151,10 @@ void
//
// Initialises a SHA256 Context. Use this to initialise/reset a context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Initialise
void
Sha256Initialise
(
Sha256Context* Context
Sha256Context* Context // [out]
)
{
Context->curlen = 0;
@@ -174,15 +175,16 @@ void Sha256Initialise
// Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
// calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Update
void
Sha256Update
(
Sha256Context* Context,
void const* Buffer,
uint32_t BufferSize
Sha256Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
)
{
uint32_t n
;
uint32_t n;
if( Context->curlen > sizeof(Context->buf) )
{
return;
@@ -223,8 +225,8 @@ void Sha256Update
void
Sha256Finalise
(
Sha256Context* Context,
SHA256_HASH* Digest
Sha256Context* Context, // [in out]
SHA256_HASH* Digest // [out]
)
{
int i;

View File

@@ -41,9 +41,10 @@ typedef struct
//
// Initialises a SHA256 Context. Use this to initialise/reset a context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Initialise
void
Sha256Initialise
(
Sha256Context* Context
Sha256Context* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -52,11 +53,12 @@ void Sha256Initialise
// Adds data to the SHA256 context. This will process the data and update the internal state of the context. Keep on
// calling this function until all the data has been added. Then call Sha256Finalise to calculate the hash.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha256Update
void
Sha256Update
(
Sha256Context* Context,
void const* Buffer,
uint32_t BufferSize
Sha256Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -68,6 +70,6 @@ void Sha256Update
void
Sha256Finalise
(
Sha256Context* Context,
SHA256_HASH* Digest
Sha256Context* Context, // [in out]
SHA256_HASH* Digest // [out]
);

View File

@@ -154,7 +154,7 @@ void
void
Sha512Initialise
(
Sha512Context* Context
Sha512Context* Context // [out]
)
{
Context->curlen = 0;
@@ -178,9 +178,9 @@ void
void
Sha512Update
(
Sha512Context* Context,
void const* Buffer,
uint32_t BufferSize
Sha512Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
)
{
uint32_t n;
@@ -225,8 +225,8 @@ void
void
Sha512Finalise
(
Sha512Context* Context,
SHA512_HASH* Digest
Sha512Context* Context, // [in out]
SHA512_HASH* Digest // [out]
)
{
int i;

View File

@@ -41,9 +41,10 @@ typedef struct
//
// Initialises a SHA512 Context. Use this to initialise/reset a context.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha512Initialise
void
Sha512Initialise
(
Sha512Context* Context
Sha512Context* Context // [out]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -52,11 +53,12 @@ void Sha512Initialise
// Adds data to the SHA512 context. This will process the data and update the internal state of the context. Keep on
// calling this function until all the data has been added. Then call Sha512Finalise to calculate the hash.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Sha512Update
void
Sha512Update
(
Sha512Context* Context,
void const* Buffer,
uint32_t BufferSize
Sha512Context* Context, // [in out]
void const* Buffer, // [in]
uint32_t BufferSize // [in]
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -68,6 +70,6 @@ void Sha512Update
void
Sha512Finalise
(
Sha512Context* Context,
SHA512_HASH* Digest
Sha512Context* Context, // [in out]
SHA512_HASH* Digest // [out]
);