The next generation of the Teknik Services. Written in ASP.NET. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AesCounterMode.cs 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using System;
  2. using System.Security.Cryptography;
  3. namespace Teknik.Utilities.Cryptography
  4. {
  5. public class AesCounterMode : SymmetricAlgorithm
  6. {
  7. // Internal Variables
  8. private const int _BlockSize = 16;
  9. private readonly byte[] _Counter;
  10. private readonly AesManaged _Algo;
  11. public AesCounterMode() : this(new byte[_BlockSize]) { }
  12. public AesCounterMode(byte[] counter)
  13. {
  14. if (counter == null) throw new ArgumentNullException("counter");
  15. if (counter.Length != _BlockSize)
  16. throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})",
  17. counter.Length, _BlockSize));
  18. // Generate a new instance of the Aes Algorithm in ECB mode with no padding
  19. _Algo = new AesManaged
  20. {
  21. Mode = CipherMode.ECB,
  22. Padding = PaddingMode.None
  23. };
  24. // Set the internal variables
  25. _Counter = new byte[counter.Length];
  26. counter.CopyTo(_Counter, 0);
  27. }
  28. public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv)
  29. {
  30. return new CounterModeCryptoTransform(_Algo, key, iv, _Counter);
  31. }
  32. public override ICryptoTransform CreateDecryptor(byte[] key, byte[] iv)
  33. {
  34. return new CounterModeCryptoTransform(_Algo, key, iv, _Counter);
  35. }
  36. public override void GenerateKey()
  37. {
  38. _Algo.GenerateKey();
  39. }
  40. public override void GenerateIV()
  41. {
  42. _Algo.GenerateIV();
  43. }
  44. }
  45. public class CounterModeCryptoTransform : ICryptoTransform
  46. {
  47. private readonly byte[] _IV;
  48. private readonly byte[] _Counter;
  49. private readonly ICryptoTransform _CounterEncryptor;
  50. private readonly SymmetricAlgorithm _SymmetricAlgorithm;
  51. // Stateful Fields
  52. private byte[] _EncryptedCounter;
  53. private int _Iterations;
  54. public int Iterations
  55. {
  56. get
  57. {
  58. return _Iterations;
  59. }
  60. }
  61. private int _CounterPosition;
  62. public int CounterPosition
  63. {
  64. get
  65. {
  66. return _CounterPosition;
  67. }
  68. set
  69. {
  70. if (value >= 0 && value < _EncryptedCounter.Length)
  71. {
  72. _CounterPosition = value;
  73. }
  74. }
  75. }
  76. public CounterModeCryptoTransform(SymmetricAlgorithm symmetricAlgorithm, byte[] key, byte[] iv, byte[] counter)
  77. {
  78. if (symmetricAlgorithm == null) throw new ArgumentNullException("symmetricAlgorithm");
  79. if (key == null) throw new ArgumentNullException("key");
  80. if (iv == null) throw new ArgumentNullException("iv");
  81. if (counter == null) throw new ArgumentNullException("counter");
  82. // Check lengths
  83. if (counter.Length != symmetricAlgorithm.BlockSize / 8)
  84. throw new ArgumentException(String.Format("Counter size must be same as block size (actual: {0}, expected: {1})",
  85. counter.Length, symmetricAlgorithm.BlockSize / 8));
  86. _SymmetricAlgorithm = symmetricAlgorithm;
  87. _IV = new byte[iv.Length];
  88. iv.CopyTo(_IV, 0);
  89. _Counter = new byte[counter.Length];
  90. counter.CopyTo(_Counter, 0);
  91. _CounterEncryptor = symmetricAlgorithm.CreateEncryptor(key, iv);
  92. // Initialize State
  93. _CounterPosition = 0;
  94. _Iterations = 0;
  95. // Encrypt the counter
  96. EncryptCounter();
  97. // Initial Increment
  98. IncrementCounter();
  99. }
  100. public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
  101. {
  102. var output = new byte[inputCount];
  103. TransformBlock(inputBuffer, inputOffset, inputCount, output, 0);
  104. return output;
  105. }
  106. public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
  107. {
  108. for (var i = 0; i < inputCount; i++)
  109. {
  110. // Encrypt the counter if we have reached the end, or
  111. if (_CounterPosition >= _EncryptedCounter.Length)
  112. {
  113. //Reset current counter position
  114. _CounterPosition = 0;
  115. // Encrypt the counter
  116. EncryptCounter();
  117. // Increment the counter for the next batch
  118. IncrementCounter();
  119. }
  120. // XOR the encrypted counter with the input plain text
  121. outputBuffer[outputOffset + i] = (byte)(_EncryptedCounter[_CounterPosition] ^ inputBuffer[inputOffset + i]);
  122. // Move the counter position
  123. _CounterPosition++;
  124. }
  125. return inputCount;
  126. }
  127. public void EncryptCounter()
  128. {
  129. // Clear the encrypted counter
  130. _EncryptedCounter = new byte[_SymmetricAlgorithm.BlockSize / 8];
  131. // Encrypt the current counter to the encrypted counter
  132. _CounterEncryptor.TransformBlock(_Counter, 0, _Counter.Length, _EncryptedCounter, 0);
  133. }
  134. public void ResetCounter()
  135. {
  136. Array.Clear(_Counter, 0, _Counter.Length);
  137. _IV.CopyTo(_Counter, 0);
  138. _Iterations = 0;
  139. }
  140. public void IncrementCounter()
  141. {
  142. int j = _Counter.Length;
  143. while (--j >= 0 && ++_Counter[j] == 0)
  144. {
  145. }
  146. _Iterations++;
  147. }
  148. public int InputBlockSize { get { return _SymmetricAlgorithm.BlockSize / 8; } }
  149. public int OutputBlockSize { get { return _SymmetricAlgorithm.BlockSize / 8; } }
  150. public bool CanTransformMultipleBlocks { get { return true; } }
  151. public bool CanReuseTransform { get { return false; } }
  152. public void Dispose()
  153. {
  154. }
  155. }
  156. }