waterjuice

CryptLib_AesCtr.c

Nov 28th, 2017
212
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. //  CryptLib_AesCtr
  3. //
  4. //  Implementation of AES CTR stream cipher.
  5. //
  6. //  Depends on: CryptoLib_Aes
  7. //
  8. //  AES CTR is a stream cipher using the AES block cipher in counter mode.
  9. //  This implementation works on both little and big endian architectures.
  10. //
  11. //  This is free and unencumbered software released into the public domain - November 2017 waterjuice.org
  12. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13.  
  14. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  15. //  IMPORTS
  16. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17.  
  18. #include "CryptLib_AesCtr.h"
  19. #include "CryptLib_Aes.h"
  20. #include <stdint.h>
  21. #include <memory.h>
  22.  
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. //  MACROS
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26.  
  27. #define MIN( x, y ) ( ((x)<(y))?(x):(y) )
  28.  
  29. #define STORE64H( x, y )                                                       \
  30.    { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255);     \
  31.      (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255);     \
  32.      (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255);     \
  33.      (y)[6] = (uint8_t)(((x)>>8)&255);  (y)[7] = (uint8_t)((x)&255); }
  34.  
  35. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36. //  INTERNAL FUNCTIONS
  37. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  38.  
  39. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  40. //  CreateCurrentCipherBlock
  41. //
  42. //  Takes the IV and the counter in the AesCtrContext and produces the cipher block (CurrentCipherBlock). The cipher
  43. //  block is produced by first creating a 128 bit block with the IV as first 64 bits and the CurrentCipherBlockIndex
  44. //  stored as the remaining 64bits in Network byte order (Big Endian)
  45. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  46. static
  47. void
  48.     CreateCurrentCipherBlock
  49.     (
  50.         AesCtrContext*      Context                 // [in out]
  51.     )
  52. {
  53.     // Build block by first copying in the IV
  54.     memcpy( Context->CurrentCipherBlock, Context->IV, AES_CTR_IV_SIZE );
  55.  
  56.     // Now place in the counter in Big Endian form
  57.     STORE64H( Context->CurrentCipherBlockIndex, Context->CurrentCipherBlock + AES_CTR_IV_SIZE );
  58.  
  59.     // Perform AES encryption on the block
  60.     AesEncryptInPlace( &Context->Aes, Context->CurrentCipherBlock );
  61. }
  62.  
  63. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  64. //  XorBuffer
  65. //
  66. //  Takes two Source buffers and XORs them together and puts the result in DestinationBuffer
  67. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. static
  69. void
  70.     XorBuffers
  71.     (
  72.         uint8_t const*      SourceBuffer1,          // [in]
  73.         uint8_t const*      SourceBuffer2,          // [in]
  74.         uint8_t*            DestinationBuffer,      // [out]
  75.         uint32_t            Amount                  // [in]
  76.     )
  77. {
  78.     uint32_t    i;
  79.  
  80.     for( i=0; i<Amount; i++ )
  81.     {
  82.         DestinationBuffer[i] = SourceBuffer1[i] ^ SourceBuffer2[i];
  83.     }
  84. }
  85.  
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. //  PUBLIC FUNCTIONS
  88. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89.  
  90. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  91. //  AesCtrInitialise
  92. //
  93. //  Initialises an AesCtrContext with an already initialised AesContext and a IV. This function can quickly be used
  94. //  to change the IV without requiring the more length processes of reinitialising an AES key.
  95. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  96. void
  97.     AesCtrInitialise
  98.     (
  99.         AesContext const*   InitialisedAesContext,  // [in]
  100.         uint8_t const       IV [AES_CTR_IV_SIZE],   // [in]
  101.         AesCtrContext*      Context                 // [out]
  102.     )
  103. {
  104.     // Setup context values
  105.     Context->Aes = *InitialisedAesContext;
  106.     memcpy( Context->IV, IV, AES_CTR_IV_SIZE );
  107.     Context->StreamIndex = 0;
  108.     Context->CurrentCipherBlockIndex = 0;
  109.  
  110.     // Generate the first cipher block of the stream.
  111.     CreateCurrentCipherBlock( Context );
  112. }
  113.  
  114. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  115. //  AesCtrInitialiseWithKey
  116. //
  117. //  Initialises an AesCtrContext with an AES Key and an IV. This combines the initialising an AES Context and then
  118. //  running AesCtrInitialise. KeySize must be 16, 24, or 32 (for 128, 192, or 256 bit key size)
  119. //  Returns 0 if successful, or -1 if invalid KeySize provided
  120. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  121. int
  122.     AesCtrInitialiseWithKey
  123.     (
  124.         uint8_t const*      Key,                    // [in]
  125.         uint32_t            KeySize,                // [in]
  126.         uint8_t const       IV [AES_CTR_IV_SIZE],   // [in]
  127.         AesCtrContext*      Context                 // [out]
  128.     )
  129. {
  130.     AesContext aes;
  131.  
  132.     // Initialise AES Context
  133.     switch( KeySize )
  134.     {
  135.     case AES_KEY_SIZE_128: AesInitialise128( Key, &aes ); break;
  136.     case AES_KEY_SIZE_192: AesInitialise192( Key, &aes ); break;
  137.     case AES_KEY_SIZE_256: AesInitialise256( Key, &aes ); break;
  138.     default:
  139.         // Invalid key size
  140.         return -1;
  141.     }
  142.  
  143.     // Now set-up AesCtrContext
  144.     AesCtrInitialise( &aes, IV, Context );
  145.     return 0;
  146. }
  147.  
  148. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. //  AesCtrSetStreamIndex
  150. //
  151. //  Sets the current stream index to any arbitrary position. Setting to 0 sets it to the beginning of the stream. Any
  152. //  subsequent output will start from this position
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. void
  155.     AesCtrSetStreamIndex
  156.     (
  157.         AesCtrContext*      Context,                // [in out]
  158.         uint64_t            StreamIndex             // [in]
  159.     )
  160. {
  161.     uint64_t    blockIndex = StreamIndex / AES_BLOCK_SIZE;
  162.  
  163.     Context->StreamIndex = StreamIndex;
  164.     if( blockIndex != Context->CurrentCipherBlockIndex )
  165.     {
  166.         // Update block index and generate new cipher block as the new StreamIndex is inside a different block to the
  167.         // one we currently had.
  168.         Context->CurrentCipherBlockIndex = blockIndex;
  169.         CreateCurrentCipherBlock( Context );
  170.     }
  171. }
  172.  
  173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. //  AesCtrXor
  175. //
  176. //  XORs the stream of byte of the AesCtrContext from its current stream position onto the specified buffer. This will
  177. //  advance the stream index by that number of bytes.
  178. //  Use once over data to encrypt it. Use it a second time over the same data from the same stream position and the
  179. //  data will be decrypted.
  180. //  InBuffer and OutBuffer can point to the same location for inplace encrypting/decrypting
  181. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  182. void
  183.     AesCtrXor
  184.     (
  185.         AesCtrContext*      Context,                // [in out]
  186.         void const*         InBuffer,               // [in]
  187.         void*               OutBuffer,              // [out]
  188.         uint32_t            Size                    // [in]
  189.     )
  190. {
  191.     uint32_t    amountLeft = Size;
  192.     uint32_t    outputOffset = 0;
  193.     uint32_t    chunkSize;
  194.     uint32_t    amountAvailableInBlock;
  195.  
  196.     // First determine how much is available in the current block.
  197.     amountAvailableInBlock = AES_BLOCK_SIZE - (Context->StreamIndex % AES_BLOCK_SIZE);
  198.  
  199.     // Determine how much of the current block we will take, either all that is available, or less
  200.     // if the amount requested is smaller.
  201.     chunkSize = MIN( amountAvailableInBlock, amountLeft );
  202.  
  203.     // XOR the bytes from the cipher block
  204.     XorBuffers( InBuffer, Context->CurrentCipherBlock + (AES_BLOCK_SIZE - amountAvailableInBlock), OutBuffer, chunkSize );
  205.  
  206.     amountLeft -= chunkSize;
  207.     outputOffset += chunkSize;
  208.  
  209.     // Now start generating new cipher blocks as required.
  210.     while( amountLeft > 0 )
  211.     {
  212.         // Increment block index and regenerate cipher block
  213.         Context->CurrentCipherBlockIndex += 1;
  214.         CreateCurrentCipherBlock( Context );
  215.  
  216.         // Determine how much of the current block we need and XOR it out onto the buffer
  217.         chunkSize = MIN( amountLeft, AES_BLOCK_SIZE );
  218.         XorBuffers( (uint8_t*)InBuffer + outputOffset, Context->CurrentCipherBlock, (uint8_t*)OutBuffer + outputOffset, chunkSize );
  219.  
  220.         amountLeft -= chunkSize;
  221.         outputOffset += chunkSize;
  222.     }
  223.  
  224.     // All data read out now, so update index in the context.
  225.     Context->StreamIndex += Size;
  226.  
  227.     // If we ended up completely reading the last cipher block we need to generate a new one for next time.
  228.     if( AES_BLOCK_SIZE == chunkSize )
  229.     {
  230.         Context->CurrentCipherBlockIndex += 1;
  231.         CreateCurrentCipherBlock( Context );
  232.     }
  233. }
  234.  
  235. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  236. //  AesCtrOutput
  237. //
  238. //  Outputs the stream of byte of the AesCtrContext from its current stream position. This will advance the stream
  239. //  index by that number of bytes.
  240. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  241. void
  242.     AesCtrOutput
  243.     (
  244.         AesCtrContext*      Context,                // [in out]
  245.         void*               Buffer,                 // [out]
  246.         uint32_t            Size                    // [in]
  247.     )
  248. {
  249.     memset( Buffer, 0, Size );
  250.     AesCtrXor( Context, Buffer, Buffer, Size );
  251. }
  252.  
  253. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  254. //  AesCtrXorWithKey
  255. //
  256. //  This function combines AesCtrInitialiseWithKey and AesCtrXor. This is suitable when encrypting/decypting data in
  257. //  one go with a key that is not going to be reused.
  258. //  This will used the provided Key and IV and generate a stream that is XORed over Buffer.
  259. //  InBuffer and OutBuffer can point to the same location for inplace encrypting/decrypting
  260. //  Returns 0 if successful, or -1 if invalid KeySize provided
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. int
  263.     AesCtrXorWithKey
  264.     (
  265.         uint8_t const*      Key,                    // [in]
  266.         uint32_t            KeySize,                // [in]
  267.         uint8_t const       IV [AES_CTR_IV_SIZE],   // [in]
  268.         void const*         InBuffer,               // [in]
  269.         void*               OutBuffer,              // [out]
  270.         uint32_t            BufferSize              // [in]
  271.     )
  272. {
  273.     int             error;
  274.     AesCtrContext   context;
  275.  
  276.     error = AesCtrInitialiseWithKey( Key, KeySize, IV, &context );
  277.     if( 0 == error )
  278.     {
  279.         AesCtrXor( &context, InBuffer, OutBuffer, BufferSize );
  280.     }
  281.  
  282.     return error;
  283. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×