Advertisement
waterjuice

CryptLib_AesCtr.c

Nov 28th, 2017
559
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.97 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement