From e39760a85015b88820d7a2de832155a7c8ff2c88 Mon Sep 17 00:00:00 2001 From: waterjuice Date: Fri, 16 Mar 2018 13:30:49 +1100 Subject: [PATCH] Version 2.3.0 * Added AES-CBC module. * Added functions Md5Calculate, Sha1Calculate, Sha256Calculate, and Sha512Calculate to calculate a hash in one call. * Added function Rc4XorWithKey to encrypt/decrypt a buffer with RC4 in one call. * Bugfix: AesInitialise now returns -1 if invalid key size is provided. Previously it would return 0 despite what was documented. --- CMakeLists.txt | 2 + ReadMe.md | 15 +- lib/WjCryptLib_Aes.c | 4 + lib/WjCryptLib_AesCbc.c | 265 ++++++++++++++++ lib/WjCryptLib_AesCbc.h | 148 +++++++++ lib/WjCryptLib_Md5.c | 20 ++ lib/WjCryptLib_Md5.h | 13 + lib/WjCryptLib_Rc4.c | 24 ++ lib/WjCryptLib_Rc4.h | 18 ++ lib/WjCryptLib_Sha1.c | 20 ++ lib/WjCryptLib_Sha1.h | 13 + lib/WjCryptLib_Sha256.c | 21 ++ lib/WjCryptLib_Sha256.h | 14 + lib/WjCryptLib_Sha512.c | 21 ++ projects/AesBlock/AesBlock.c | 10 +- projects/AesCtrOutput/AesCtrOutput.c | 2 +- projects/AesOfbOutput/AesOfbOutput.c | 2 +- projects/WjCryptLibTest/CMakeLists.txt | 2 + projects/WjCryptLibTest/WjCryptLibTest.c | 5 + .../WjCryptLibTest/WjCryptLibTest_AesCbc.c | 299 ++++++++++++++++++ .../WjCryptLibTest/WjCryptLibTest_AesCbc.h | 30 ++ .../WjCryptLibTest/WjCryptLibTest_AesCtr.c | 3 +- .../WjCryptLibTest/WjCryptLibTest_AesOfb.c | 1 - 23 files changed, 941 insertions(+), 11 deletions(-) create mode 100644 lib/WjCryptLib_AesCbc.c create mode 100644 lib/WjCryptLib_AesCbc.h create mode 100644 projects/WjCryptLibTest/WjCryptLibTest_AesCbc.c create mode 100644 projects/WjCryptLibTest/WjCryptLibTest_AesCbc.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eeecb17..096b03c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,8 @@ project( WjCryptLib ) add_library( WjCryptLib STATIC lib/WjCryptLib_Aes.h lib/WjCryptLib_Aes.c + lib/WjCryptLib_AesCbc.h + lib/WjCryptLib_AesCbc.c lib/WjCryptLib_AesCtr.h lib/WjCryptLib_AesCtr.c lib/WjCryptLib_AesOfb.h diff --git a/ReadMe.md b/ReadMe.md index 3e7a3bf..2267000 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -32,10 +32,23 @@ depending on what cryptographic functions are wanted. and WjCryptLib_Aes.c) * AES-OFB - (WjCryptLib_AesOfb.h, and WjCryptLib_AesOfb.c, WjCryptLib_Aes.h, and WjCryptLib_Aes.c) +* AES-CBC - (WjCryptLib_AesCbc.h, and WjCryptLib_AesCbc.c, WjCryptLib_Aes.h, + and WjCryptLib_Aes.c) +Version 2.3.0 - March 2018 +-------------------------- + +* Added AES-CBC module. +* Added functions Md5Calculate, Sha1Calculate, Sha256Calculate, and + Sha512Calculate to calculate a hash in one call. +* Added function Rc4XorWithKey to encrypt/decrypt a buffer with RC4 in + one call. +* Bugfix: AesInitialise now returns -1 if invalid key size is provided. + Previously it would return 0 despite what was documented. + Version 2.2.0 - January 2018 ------------- +---------------------------- * Added AES-OFB module. * File names have been changed to have the prefix `WjCryptLib_` rather diff --git a/lib/WjCryptLib_Aes.c b/lib/WjCryptLib_Aes.c index 0668654..612c7ee 100644 --- a/lib/WjCryptLib_Aes.c +++ b/lib/WjCryptLib_Aes.c @@ -789,6 +789,10 @@ int rk += 8; } } + else + { + return -1; + } // Setup the inverse key now rk = Context->dK; diff --git a/lib/WjCryptLib_AesCbc.c b/lib/WjCryptLib_AesCbc.c new file mode 100644 index 0000000..f620012 --- /dev/null +++ b/lib/WjCryptLib_AesCbc.c @@ -0,0 +1,265 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WjCryptLib_AesCbc +// +// Implementation of AES CBC cipher. +// +// Depends on: CryptoLib_Aes +// +// AES CBC is a cipher using AES in Cipher Block Chaining mode. Encryption and decryption must be performed in +// multiples of the AES block size (128 bits). +// This implementation works on both little and big endian architectures. +// +// This is free and unencumbered software released into the public domain - March 2018 waterjuice.org +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "WjCryptLib_AesCbc.h" +#include "WjCryptLib_Aes.h" +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MACROS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define MIN( x, y ) ( ((x)<(y))?(x):(y) ) + +#define STORE64H( x, y ) \ + { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255); \ + (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255); \ + (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255); \ + (y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// INTERNAL FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// XorAesBlock +// +// Takes two source blocks (size AES_BLOCK_SIZE) and XORs them together and puts the result in first block +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static +void + XorAesBlock + ( + uint8_t* Block1, // [in out] + uint8_t const* Block2 // [in] + ) +{ + uint32_t i; + + for( i=0; iAes = *InitialisedAesContext; + memcpy( Context->PreviousCipherBlock, IV, sizeof(Context->PreviousCipherBlock) ); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcInitialiseWithKey +// +// Initialises an AesCbcContext with an AES Key and an IV. This combines the initialising an AES Context and then +// running AesCbcInitialise. 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 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcInitialiseWithKey + ( + AesCbcContext* Context, // [out] + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint8_t const IV [AES_CBC_IV_SIZE] // [in] + ) +{ + AesContext aes; + + // Initialise AES Context + if( 0 != AesInitialise( &aes, Key, KeySize ) ) + { + return -1; + } + + // Now set-up AesCbcContext + AesCbcInitialise( Context, &aes, IV ); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcEncrypt +// +// Encrypts a buffer of data using an AES CBC context. The data buffer must be a multiple of 16 bytes (128 bits) +// in size. The "position" of the context will be advanced by the buffer amount. A buffer can be encrypted in one +// go or in smaller chunks at a time. The result will be the same as long as data is fed into the function in the +// same order. +// InBuffer and OutBuffer can point to the same location for in-place encrypting. +// Returns 0 if successful, or -1 if Size is not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcEncrypt + ( + AesCbcContext* Context, // [in out] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t Size // [in] + ) +{ + uint32_t numBlocks = Size / AES_BLOCK_SIZE; + uint32_t offset = 0; + uint32_t i; + + if( 0 != Size % AES_BLOCK_SIZE ) + { + // Size not a multiple of AES block size (16 bytes). + return -1; + } + + for( i=0; iPreviousCipherBlock, (uint8_t*)InBuffer + offset ); + + // Encrypt to make new cipher block + AesEncryptInPlace( &Context->Aes, Context->PreviousCipherBlock ); + + // Output cipher block + memcpy( (uint8_t*)OutBuffer + offset, Context->PreviousCipherBlock, AES_BLOCK_SIZE ); + + offset += AES_BLOCK_SIZE; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcDecrypt +// +// Decrypts a buffer of data using an AES CBC context. The data buffer must be a multiple of 16 bytes (128 bits) +// in size. The "position" of the context will be advanced by the buffer amount. +// InBuffer and OutBuffer can point to the same location for in-place decrypting. +// Returns 0 if successful, or -1 if Size is not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcDecrypt + ( + AesCbcContext* Context, // [in out] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t Size // [in] + ) +{ + uint32_t numBlocks = Size / AES_BLOCK_SIZE; + uint32_t offset = 0; + uint32_t i; + uint8_t previousCipherBlock [AES_BLOCK_SIZE]; + + if( 0 != Size % AES_BLOCK_SIZE ) + { + // Size not a multiple of AES block size (16 bytes). + return -1; + } + + for( i=0; iPreviousCipherBlock, AES_BLOCK_SIZE ); + memcpy( Context->PreviousCipherBlock, (uint8_t*)InBuffer + offset, AES_BLOCK_SIZE ); + + // Decrypt cipher block + AesDecrypt( &Context->Aes, Context->PreviousCipherBlock, (uint8_t*)OutBuffer + offset ); + + // XOR on previous cipher block + XorAesBlock( (uint8_t*)OutBuffer + offset, previousCipherBlock ); + + offset += AES_BLOCK_SIZE; + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcEncryptWithKey +// +// This function combines AesCbcInitialiseWithKey and AesCbcEncrypt. This is suitable when encrypting data in one go +// with a key that is not going to be reused. +// InBuffer and OutBuffer can point to the same location for inplace encrypting. +// Returns 0 if successful, or -1 if invalid KeySize provided or BufferSize not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcEncryptWithKey + ( + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint8_t const IV [AES_CBC_IV_SIZE], // [in] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t BufferSize // [in] + ) +{ + int error; + AesCbcContext context; + + error = AesCbcInitialiseWithKey( &context, Key, KeySize, IV ); + if( 0 == error ) + { + error = AesCbcEncrypt( &context, InBuffer, OutBuffer, BufferSize ); + } + + return error; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcDecryptWithKey +// +// This function combines AesCbcInitialiseWithKey and AesCbcDecrypt. This is suitable when decrypting data in one go +// with a key that is not going to be reused. +// InBuffer and OutBuffer can point to the same location for inplace decrypting. +// Returns 0 if successful, or -1 if invalid KeySize provided or BufferSize not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcDecryptWithKey + ( + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint8_t const IV [AES_CBC_IV_SIZE], // [in] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t BufferSize // [in] + ) +{ + int error; + AesCbcContext context; + + error = AesCbcInitialiseWithKey( &context, Key, KeySize, IV ); + if( 0 == error ) + { + error = AesCbcDecrypt( &context, InBuffer, OutBuffer, BufferSize ); + } + + return error; +} diff --git a/lib/WjCryptLib_AesCbc.h b/lib/WjCryptLib_AesCbc.h new file mode 100644 index 0000000..7790605 --- /dev/null +++ b/lib/WjCryptLib_AesCbc.h @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WjCryptLib_AesCbc +// +// Implementation of AES CBC cipher. +// +// Depends on: CryptoLib_Aes +// +// AES CBC is a cipher using AES in Cipher Block Chaining mode. Encryption and decryption must be performed in +// multiples of the AES block size (128 bits). +// This implementation works on both little and big endian architectures. +// +// This is free and unencumbered software released into the public domain - March 2018 waterjuice.org +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include "WjCryptLib_Aes.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define AES_CBC_IV_SIZE AES_BLOCK_SIZE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// AesCbcContext +// Do not modify the contents of this structure directly. +typedef struct +{ + AesContext Aes; + uint8_t PreviousCipherBlock [AES_BLOCK_SIZE]; +} AesCbcContext; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcInitialise +// +// Initialises an AesCbcContext with an already initialised AesContext and a IV. This function can quickly be used +// to change the IV without requiring the more lengthy processes of reinitialising an AES key. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + AesCbcInitialise + ( + AesCbcContext* Context, // [out] + AesContext const* InitialisedAesContext, // [in] + uint8_t const IV [AES_CBC_IV_SIZE] // [in] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcInitialiseWithKey +// +// Initialises an AesCbcContext with an AES Key and an IV. This combines the initialising an AES Context and then +// running AesCbcInitialise. 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 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcInitialiseWithKey + ( + AesCbcContext* Context, // [out] + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint8_t const IV [AES_CBC_IV_SIZE] // [in] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcEncrypt +// +// Encrypts a buffer of data using an AES CBC context. The data buffer must be a multiple of 16 bytes (128 bits) +// in size. The "position" of the context will be advanced by the buffer amount. A buffer can be encrypted in one +// go or in smaller chunks at a time. The result will be the same as long as data is fed into the function in the +// same order. +// InBuffer and OutBuffer can point to the same location for in-place encrypting. +// Returns 0 if successful, or -1 if Size is not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcEncrypt + ( + AesCbcContext* Context, // [in out] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t Size // [in] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcDecrypt +// +// Decrypts a buffer of data using an AES CBC context. The data buffer must be a multiple of 16 bytes (128 bits) +// in size. The "position" of the context will be advanced by the buffer amount. +// InBuffer and OutBuffer can point to the same location for in-place decrypting. +// Returns 0 if successful, or -1 if Size is not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcDecrypt + ( + AesCbcContext* Context, // [in out] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t Size // [in] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcEncryptWithKey +// +// This function combines AesCbcInitialiseWithKey and AesCbcEncrypt. This is suitable when encrypting data in one go +// with a key that is not going to be reused. +// InBuffer and OutBuffer can point to the same location for inplace encrypting. +// Returns 0 if successful, or -1 if invalid KeySize provided or BufferSize not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcEncryptWithKey + ( + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint8_t const IV [AES_CBC_IV_SIZE], // [in] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t BufferSize // [in] + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// AesCbcDecryptWithKey +// +// This function combines AesCbcInitialiseWithKey and AesCbcDecrypt. This is suitable when decrypting data in one go +// with a key that is not going to be reused. +// InBuffer and OutBuffer can point to the same location for inplace decrypting. +// Returns 0 if successful, or -1 if invalid KeySize provided or BufferSize not a multiple of 16 bytes. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int + AesCbcDecryptWithKey + ( + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint8_t const IV [AES_CBC_IV_SIZE], // [in] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t BufferSize // [in] + ); diff --git a/lib/WjCryptLib_Md5.c b/lib/WjCryptLib_Md5.c index 5809b14..6fe9941 100644 --- a/lib/WjCryptLib_Md5.c +++ b/lib/WjCryptLib_Md5.c @@ -313,3 +313,23 @@ void Digest->bytes[14] = (uint8_t)( Context->d >> 16 ); Digest->bytes[15] = (uint8_t)( Context->d >> 24 ); } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Md5Calculate +// +// Combines Md5Initialise, Md5Update, and Md5Finalise into one function. Calculates the MD5 hash of the buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Md5Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + MD5_HASH* Digest // [in] + ) +{ + Md5Context context; + + Md5Initialise( &context ); + Md5Update( &context, Buffer, BufferSize ); + Md5Finalise( &context, Digest ); +} diff --git a/lib/WjCryptLib_Md5.h b/lib/WjCryptLib_Md5.h index fd860ca..02773af 100644 --- a/lib/WjCryptLib_Md5.h +++ b/lib/WjCryptLib_Md5.h @@ -81,3 +81,16 @@ void Md5Context* Context, // [in out] MD5_HASH* Digest // [in] ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Md5Calculate +// +// Combines Md5Initialise, Md5Update, and Md5Finalise into one function. Calculates the MD5 hash of the buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Md5Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + MD5_HASH* Digest // [in] + ); diff --git a/lib/WjCryptLib_Rc4.c b/lib/WjCryptLib_Rc4.c index 5c453cc..22828fa 100644 --- a/lib/WjCryptLib_Rc4.c +++ b/lib/WjCryptLib_Rc4.c @@ -126,3 +126,27 @@ void ^ ( Context->S[ (Context->S[Context->i] + Context->S[Context->j]) % 256 ] ); } } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Rc4XorWithKey +// +// This function combines Rc4Initialise and Rc4Xor. This is suitable when encrypting/decrypting data in one go with a +// key that is not going to be reused. +// InBuffer and OutBuffer can point to the same location for inplace encrypting/decrypting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Rc4XorWithKey + ( + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint32_t DropN, // [in] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t BufferSize // [in] + ) +{ + Rc4Context context; + + Rc4Initialise( &context, Key, KeySize, DropN ); + Rc4Xor( &context, InBuffer, OutBuffer, BufferSize ); +} diff --git a/lib/WjCryptLib_Rc4.h b/lib/WjCryptLib_Rc4.h index 95ebf36..94cb878 100644 --- a/lib/WjCryptLib_Rc4.h +++ b/lib/WjCryptLib_Rc4.h @@ -71,3 +71,21 @@ void void* OutBuffer, // [out] uint32_t Size // [in] ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Rc4XorWithKey +// +// This function combines Rc4Initialise and Rc4Xor. This is suitable when encrypting/decrypting data in one go with a +// key that is not going to be reused. +// InBuffer and OutBuffer can point to the same location for inplace encrypting/decrypting +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Rc4XorWithKey + ( + uint8_t const* Key, // [in] + uint32_t KeySize, // [in] + uint32_t DropN, // [in] + void const* InBuffer, // [in] + void* OutBuffer, // [out] + uint32_t BufferSize // [in] + ); diff --git a/lib/WjCryptLib_Sha1.c b/lib/WjCryptLib_Sha1.c index e3f1df3..be190fe 100644 --- a/lib/WjCryptLib_Sha1.c +++ b/lib/WjCryptLib_Sha1.c @@ -247,3 +247,23 @@ void Digest->bytes[i] = (uint8_t)((Context->State[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Calculate +// +// Combines Sha1Initialise, Sha1Update, and Sha1Finalise into one function. Calculates the SHA1 hash of the buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA1_HASH* Digest // [in] + ) +{ + Sha1Context context; + + Sha1Initialise( &context ); + Sha1Update( &context, Buffer, BufferSize ); + Sha1Finalise( &context, Digest ); +} diff --git a/lib/WjCryptLib_Sha1.h b/lib/WjCryptLib_Sha1.h index 2180788..81b3a85 100644 --- a/lib/WjCryptLib_Sha1.h +++ b/lib/WjCryptLib_Sha1.h @@ -79,3 +79,16 @@ void Sha1Context* Context, // [in out] SHA1_HASH* Digest // [in] ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha1Calculate +// +// Combines Sha1Initialise, Sha1Update, and Sha1Finalise into one function. Calculates the SHA1 hash of the buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha1Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA1_HASH* Digest // [in] + ); diff --git a/lib/WjCryptLib_Sha256.c b/lib/WjCryptLib_Sha256.c index af466d3..559865e 100644 --- a/lib/WjCryptLib_Sha256.c +++ b/lib/WjCryptLib_Sha256.c @@ -271,3 +271,24 @@ void STORE32H( Context->state[i], Digest->bytes+(4*i) ); } } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Calculate +// +// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the +// buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA256_HASH* Digest // [in] + ) +{ + Sha256Context context; + + Sha256Initialise( &context ); + Sha256Update( &context, Buffer, BufferSize ); + Sha256Finalise( &context, Digest ); +} diff --git a/lib/WjCryptLib_Sha256.h b/lib/WjCryptLib_Sha256.h index 06d3761..406ed86 100644 --- a/lib/WjCryptLib_Sha256.h +++ b/lib/WjCryptLib_Sha256.h @@ -73,3 +73,17 @@ void Sha256Context* Context, // [in out] SHA256_HASH* Digest // [out] ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha256Calculate +// +// Combines Sha256Initialise, Sha256Update, and Sha256Finalise into one function. Calculates the SHA256 hash of the +// buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha256Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA256_HASH* Digest // [in] + ); diff --git a/lib/WjCryptLib_Sha512.c b/lib/WjCryptLib_Sha512.c index 3d0aa23..a47365d 100644 --- a/lib/WjCryptLib_Sha512.c +++ b/lib/WjCryptLib_Sha512.c @@ -273,3 +273,24 @@ void STORE64H( Context->state[i], Digest->bytes+(8*i) ); } } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Sha512Calculate +// +// Combines Sha512Initialise, Sha512Update, and Sha512Finalise into one function. Calculates the SHA512 hash of the +// buffer. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void + Sha512Calculate + ( + void const* Buffer, // [in] + uint32_t BufferSize, // [in] + SHA512_HASH* Digest // [in] + ) +{ + Sha512Context context; + + Sha512Initialise( &context ); + Sha512Update( &context, Buffer, BufferSize ); + Sha512Finalise( &context, Digest ); +} diff --git a/projects/AesBlock/AesBlock.c b/projects/AesBlock/AesBlock.c index b8a6cfb..440a13b 100644 --- a/projects/AesBlock/AesBlock.c +++ b/projects/AesBlock/AesBlock.c @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // AesBlock // -// Encrypts or Decrypts a single 128 bit block specified on the command line as a hex string. Key is also on +// Encrypts or Decrypts a single 128 bit block specified on the command line as a hex string. Key is also on // command line and may be 128, 192, or 256 bits in size. // // This is free and unencumbered software released into the public domain - November 2017 waterjuice.org @@ -25,7 +25,7 @@ #ifdef _MSC_VER #define StringCaseInsensitiveCmp stricmp #else - #define StringCaseInsensitiveCmp strcasecmp + #define StringCaseInsensitiveCmp strcasecmp #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -40,7 +40,7 @@ // This function ignores any character that isn't a hex character. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static -void +void ReadHexData ( char const* HexString, @@ -116,7 +116,7 @@ int " AesBlock [-D] \n" ); return 1; } - + for( i=1; i<(uint32_t)ArgC; i++ ) { if( 0 == StringCaseInsensitiveCmp( ArgV[i], "-d" ) ) @@ -132,7 +132,7 @@ int printf( "Invalid syntax\n" ); exit( 1 ); } - + ReadHexData( ArgV[i], bufferPtr, bufferSizePtr ); paramIndex += 1; } diff --git a/projects/AesCtrOutput/AesCtrOutput.c b/projects/AesCtrOutput/AesCtrOutput.c index 9013a38..6f3b835 100644 --- a/projects/AesCtrOutput/AesCtrOutput.c +++ b/projects/AesCtrOutput/AesCtrOutput.c @@ -42,7 +42,7 @@ // This function ignores any character that isn't a hex character. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static -void +void ReadHexData ( char const* HexString, // [in] diff --git a/projects/AesOfbOutput/AesOfbOutput.c b/projects/AesOfbOutput/AesOfbOutput.c index efdd14d..d1082c9 100644 --- a/projects/AesOfbOutput/AesOfbOutput.c +++ b/projects/AesOfbOutput/AesOfbOutput.c @@ -42,7 +42,7 @@ // This function ignores any character that isn't a hex character. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static -void +void ReadHexData ( char const* HexString, // [in] diff --git a/projects/WjCryptLibTest/CMakeLists.txt b/projects/WjCryptLibTest/CMakeLists.txt index ca0ad70..39d8732 100644 --- a/projects/WjCryptLibTest/CMakeLists.txt +++ b/projects/WjCryptLibTest/CMakeLists.txt @@ -8,6 +8,8 @@ add_executable( ${MODULE_NAME} WjCryptLibTest_Rc4.h WjCryptLibTest_Aes.c WjCryptLibTest_Aes.h + WjCryptLibTest_AesCbc.c + WjCryptLibTest_AesCbc.h WjCryptLibTest_AesCtr.c WjCryptLibTest_AesCtr.h WjCryptLibTest_AesOfb.c diff --git a/projects/WjCryptLibTest/WjCryptLibTest.c b/projects/WjCryptLibTest/WjCryptLibTest.c index e2065d1..8124da6 100644 --- a/projects/WjCryptLibTest/WjCryptLibTest.c +++ b/projects/WjCryptLibTest/WjCryptLibTest.c @@ -16,6 +16,7 @@ #include #include #include "WjCryptLibTest_Aes.h" +#include "WjCryptLibTest_AesCbc.h" #include "WjCryptLibTest_AesCtr.h" #include "WjCryptLibTest_AesOfb.h" #include "WjCryptLibTest_Hashes.h" @@ -55,6 +56,10 @@ int if( !success ) { allSuccess = false; } printf( "Test AES - %s\n", success?"Pass":"Fail" ); + success = TestAesCbc( ); + if( !success ) { allSuccess = false; } + printf( "Test AES CBC - %s\n", success?"Pass":"Fail" ); + success = TestAesCtr( ); if( !success ) { allSuccess = false; } printf( "Test AES CTR - %s\n", success?"Pass":"Fail" ); diff --git a/projects/WjCryptLibTest/WjCryptLibTest_AesCbc.c b/projects/WjCryptLibTest/WjCryptLibTest_AesCbc.c new file mode 100644 index 0000000..5cd0ef1 --- /dev/null +++ b/projects/WjCryptLibTest/WjCryptLibTest_AesCbc.c @@ -0,0 +1,299 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WjCryptLibTest_AesCbc +// +// Tests the cryptography functions against known test vectors to verify algorithms are correct. +// Tests the following: +// AES CBC +// +// This is free and unencumbered software released into the public domain - March 2018 waterjuice.org +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include "WjCryptLib_AesCbc.h" +#include "WjCryptLib_Sha1.h" +#include "WjCryptLib_Rc4.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MACROS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define MIN( x, y ) ( ((x)<(y))?(x):(y) ) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TYPES +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define MAX_PLAINTEXT_SIZE 100 + +typedef struct +{ + char* KeyHex; + char* IvHex; + char* CipherTextHex; +} TestVector; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// GLOBALS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// These test vectors were created using openssl. Using the following commands: +// (Note: As CBC is not a stream cipher, the input is created using an RC4 stream generated from a key of 0) +// (Also note: openssl outputs an additional block of data due to some padding. We ignore this) +// > dd if=/dev/zero iflag=count_bytes count=64 status=none | openssl enc -rc4 -K 0 | openssl enc -aes-128-cbc -K 00000000000000000000000000000000 -iv 00000000000000000000000000000000 | head -c 64 | xxd -p -c 64 +// > dd if=/dev/zero iflag=count_bytes count=64 status=none | openssl enc -rc4 -K 0 | openssl enc -aes-128-cbc -K 0102030405060708a1a2a3a4a5a6a7a8 -iv 00000000000000000000000000000000 | head -c 64 | xxd -p -c 64 +// > dd if=/dev/zero iflag=count_bytes count=64 status=none | openssl enc -rc4 -K 0 | openssl enc -aes-128-cbc -K 00000000000000000000000000000000 -iv b1b2b3b4b5b6b7b8c1c2c3c4c5c6c7c8 | head -c 64 | xxd -p -c 64 +// > dd if=/dev/zero iflag=count_bytes count=64 status=none | openssl enc -rc4 -K 0 | openssl enc -aes-128-cbc -K 0102030405060708a1a2a3a4a5a6a7a8 -iv b1b2b3b4b5b6b7b8c1c2c3c4c5c6c7c8 | head -c 64 | xxd -p -c 64 +// > dd if=/dev/zero iflag=count_bytes count=64 status=none | openssl enc -rc4 -K 0 | openssl enc -aes-192-cbc -K 0102030405060708a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8 -iv c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8 | head -c 64 | xxd -p -c 64 +// > dd if=/dev/zero iflag=count_bytes count=64 status=none | openssl enc -rc4 -K 0 | openssl enc -aes-256-cbc -K 0102030405060708a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8c1c2c3c4c5c6c7c8 -iv d1d2d3d4d5d6d7d8e1e2e3e4e5e6e7e8 | head -c 64 | xxd -p -c 64 +static TestVector gTestVectors [] = +{ + { + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "c2af41ffe8b9f1b295d68038e3e8ed3f70b72b168cd3d402ccbf0bb4fa12561fc703951c91d8ce81c5643155b5db1d34eb7b36c2cc4715c03ea24944bb5c5625" + }, + { + "0102030405060708a1a2a3a4a5a6a7a8", + "00000000000000000000000000000000", + "638198794af111670d5d7a7e13851484f71831108a5a134a9329787ad73379eb449e5068150233c4f0ae8c08d86708bc09724efaad3e6936e03c58f83f2abf3f" + }, + { + "00000000000000000000000000000000", + "b1b2b3b4b5b6b7b8c1c2c3c4c5c6c7c8", + "c696d1b757d5b4ee2069d1c50b1e5569aa931d0ecc058a5adce099e2f844153db0cf0884102720e42ab58efe449faba054edd92c4006fffbd9b0aec297b852ae" + }, + { + "0102030405060708a1a2a3a4a5a6a7a8", + "b1b2b3b4b5b6b7b8c1c2c3c4c5c6c7c8", + "a3c80c1c5ee817ad5faf31c6610e7895f480bdc9055362f0a7148b47b1dc5f11d041d94026266625cd6b512451a539ee9f3820667a84ace6cfbbe7edf746a14d" + }, + { + "0102030405060708a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8", + "c1c2c3c4c5c6c7c8d1d2d3d4d5d6d7d8", + "93928e29c82e5536bc5942c35bbbd4d7a69f0a7daa35c77ecb13b3ac2c46c473cb608f403982d8401385fd7fe66a1e329aa0f90a50180fb73b36e98cb7214736" + }, + { + "0102030405060708a1a2a3a4a5a6a7a8b1b2b3b4b5b6b7b8c1c2c3c4c5c6c7c8", + "d1d2d3d4d5d6d7d8e1e2e3e4e5e6e7e8", + "2b559a644b62f1540c4ff9c50140fadedeefd49de9827dfbc8be8e4f7e2ac4ea746c8432d184059f62facaf765d90eadb7bdecac5e23bdc23f4026cd32d18ae2" + }, +}; + +#define NUM_TEST_VECTORS ( sizeof(gTestVectors) / sizeof(gTestVectors[0]) ) +#define TEST_VECTOR_OUTPUT_SIZE 48 + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// INTERNAL FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HexToBytes +// +// Reads a string as hex and places it in Data. This function will output as many bytes as represented in the input +// string, it will not check the output buffer length. On return *pDataSize will be number of bytes read. +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static +void + HexToBytes + ( + char const* HexString, // [in] + uint8_t* Data, // [out] + uint32_t* pDataSize // [out optional] + ) +{ + uint32_t i; + char holdingBuffer [3] = {0}; + unsigned hexToNumber; + uint32_t outputIndex = 0; + + for( i=0; i 0 ) + { + chunkSize = MIN( amountLeft, 10000 ); + AesCbcEncrypt( &aesCbcContext, buffer+offset, buffer+offset, chunkSize ); + Sha1Update( &sha1Context, buffer+offset, chunkSize ); + amountLeft -= chunkSize; + offset += chunkSize; + } + + Sha1Finalise( &sha1Context, &calcSha1 ); + + if( 0 != memcmp( &calcSha1, sha1Hash, SHA1_HASH_SIZE ) ) + { + printf( "Large test vector failed (2)\n" ); + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TestAesOfb +// +// Test AES CBC algorithm +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool + TestAesCbc + ( + void + ) +{ + bool totalSuccess = true; + bool success; + + success = TestVectors( ); + if( !success ) { totalSuccess = false; } + + success = TestLargeVector( ); + if( !success ) { totalSuccess = false; } + + return totalSuccess; +} diff --git a/projects/WjCryptLibTest/WjCryptLibTest_AesCbc.h b/projects/WjCryptLibTest/WjCryptLibTest_AesCbc.h new file mode 100644 index 0000000..a669808 --- /dev/null +++ b/projects/WjCryptLibTest/WjCryptLibTest_AesCbc.h @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// WjCryptLibTest_AesCbc +// +// Tests the cryptography functions against known test vectors to verify algorithms are correct. +// Tests the following: +// AES CBC +// +// This is free and unencumbered software released into the public domain - March 2018 waterjuice.org +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// IMPORTS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// EXPORTED FUNCTIONS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TestAesCbc +// +// Test AES CBC algorithm +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool + TestAesCbc + ( + void + ); \ No newline at end of file diff --git a/projects/WjCryptLibTest/WjCryptLibTest_AesCtr.c b/projects/WjCryptLibTest/WjCryptLibTest_AesCtr.c index 31089d4..7fd9acd 100644 --- a/projects/WjCryptLibTest/WjCryptLibTest_AesCtr.c +++ b/projects/WjCryptLibTest/WjCryptLibTest_AesCtr.c @@ -233,7 +233,6 @@ bool return true; } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TestStreamConsistency // @@ -327,7 +326,7 @@ bool uint8_t const iv [AES_CTR_IV_SIZE] = { 5,5,5,5,6,6,6,6 }; uint64_t const positionIndex = 0x1020304050607080ULL; uint8_t output [256 / 8] = {0}; - uint8_t const vector [256 / 8] = + uint8_t const vector [256 / 8] = { 0x17, 0x07, 0x27, 0x7b, 0x9e, 0x51, 0xdf, 0x5b, 0x23, 0xbe, 0xa1, 0xce, 0xc9, 0x40, 0x49, 0xfc, 0xf8, 0x8f, 0x45, 0xd1, 0xf6, 0x68, 0x28, 0x54, diff --git a/projects/WjCryptLibTest/WjCryptLibTest_AesOfb.c b/projects/WjCryptLibTest/WjCryptLibTest_AesOfb.c index ec9e08f..c367f6a 100644 --- a/projects/WjCryptLibTest/WjCryptLibTest_AesOfb.c +++ b/projects/WjCryptLibTest/WjCryptLibTest_AesOfb.c @@ -232,7 +232,6 @@ bool return true; } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TestStreamConsistency //