KCtrBlockCipher.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  5. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
  6. {
  7. /**
  8. * Implements a Gamming or Counter (CTR) mode on top of a DSTU 7624 block cipher.
  9. */
  10. public class KCtrBlockCipher : IStreamCipher, IBlockCipher
  11. {
  12. private byte[] IV;
  13. private byte[] ofbV;
  14. private byte[] ofbOutV;
  15. private bool initialised;
  16. private int byteCount;
  17. private readonly int blockSize;
  18. private readonly IBlockCipher cipher;
  19. /**
  20. * Basic constructor.
  21. *
  22. * @param cipher the block cipher to be used as the basis of the
  23. * feedback mode.
  24. */
  25. public KCtrBlockCipher(IBlockCipher cipher)
  26. {
  27. this.cipher = cipher;
  28. this.IV = new byte[cipher.GetBlockSize()];
  29. this.blockSize = cipher.GetBlockSize();
  30. this.ofbV = new byte[cipher.GetBlockSize()];
  31. this.ofbOutV = new byte[cipher.GetBlockSize()];
  32. }
  33. /**
  34. * return the underlying block cipher that we are wrapping.
  35. *
  36. * @return the underlying block cipher that we are wrapping.
  37. */
  38. public IBlockCipher GetUnderlyingCipher()
  39. {
  40. return cipher;
  41. }
  42. /**
  43. * Initialise the cipher and, possibly, the initialisation vector (IV).
  44. * If an IV isn't passed as part of the parameter, the IV will be all zeros.
  45. * An IV which is too short is handled in FIPS compliant fashion.
  46. *
  47. * @param forEncryption if true the cipher is initialised for
  48. * encryption, if false for decryption.
  49. * @param param the key and other data required by the cipher.
  50. * @exception ArgumentException if the parameters argument is
  51. * inappropriate.
  52. */
  53. public void Init(
  54. bool forEncryption,
  55. ICipherParameters parameters)
  56. {
  57. this.initialised = true;
  58. if (parameters is ParametersWithIV)
  59. {
  60. ParametersWithIV ivParam = (ParametersWithIV)parameters;
  61. byte[] iv = ivParam.GetIV();
  62. int diff = IV.Length - iv.Length;
  63. Array.Clear(IV, 0, IV.Length);
  64. Array.Copy(iv, 0, IV, diff, iv.Length);
  65. parameters = ivParam.Parameters;
  66. }
  67. else
  68. {
  69. throw new ArgumentException("Invalid parameter passed");
  70. }
  71. // if it's null, key is to be reused.
  72. if (parameters != null)
  73. {
  74. cipher.Init(true, parameters);
  75. }
  76. Reset();
  77. }
  78. /**
  79. * return the algorithm name and mode.
  80. *
  81. * @return the name of the underlying algorithm followed by "/KCTR"
  82. * and the block size in bits.
  83. */
  84. public string AlgorithmName
  85. {
  86. get { return cipher.AlgorithmName + "/KCTR"; }
  87. }
  88. public bool IsPartialBlockOkay
  89. {
  90. get { return true; }
  91. }
  92. /**
  93. * return the block size we are operating at.
  94. *
  95. * @return the block size we are operating at (in bytes).
  96. */
  97. public int GetBlockSize()
  98. {
  99. return cipher.GetBlockSize();
  100. }
  101. public byte ReturnByte(byte input)
  102. {
  103. return CalculateByte(input);
  104. }
  105. public void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
  106. {
  107. if (outOff + len > output.Length)
  108. {
  109. throw new DataLengthException("Output buffer too short");
  110. }
  111. if (inOff + len > input.Length)
  112. {
  113. throw new DataLengthException("Input buffer too small");
  114. }
  115. int inStart = inOff;
  116. int inEnd = inOff + len;
  117. int outStart = outOff;
  118. while (inStart<inEnd)
  119. {
  120. output[outStart++] = CalculateByte(input[inStart++]);
  121. }
  122. }
  123. protected byte CalculateByte(byte b)
  124. {
  125. if (byteCount == 0)
  126. {
  127. incrementCounterAt(0);
  128. checkCounter();
  129. cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
  130. return (byte)(ofbOutV[byteCount++] ^ b);
  131. }
  132. byte rv = (byte)(ofbOutV[byteCount++] ^ b);
  133. if (byteCount == ofbV.Length)
  134. {
  135. byteCount = 0;
  136. }
  137. return rv;
  138. }
  139. /**
  140. * Process one block of input from the array in and write it to
  141. * the out array.
  142. *
  143. * @param input the array containing the input data.
  144. * @param inOff offset into the in array the data starts at.
  145. * @param output the array the output data will be copied into.
  146. * @param outOff the offset into the out array the output will start at.
  147. * @exception DataLengthException if there isn't enough data in in, or
  148. * space in out.
  149. * @exception InvalidOperationException if the cipher isn't initialised.
  150. * @return the number of bytes processed and produced.
  151. */
  152. public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
  153. {
  154. if (input.Length - inOff< GetBlockSize())
  155. {
  156. throw new DataLengthException("Input buffer too short");
  157. }
  158. if (output.Length - outOff< GetBlockSize())
  159. {
  160. throw new DataLengthException("Output buffer too short");
  161. }
  162. ProcessBytes(input, inOff, GetBlockSize(), output, outOff);
  163. return GetBlockSize();
  164. }
  165. /**
  166. * reset the chaining vector back to the IV and reset the underlying
  167. * cipher.
  168. */
  169. public void Reset()
  170. {
  171. if (initialised)
  172. {
  173. cipher.ProcessBlock(IV, 0, ofbV, 0);
  174. }
  175. cipher.Reset();
  176. byteCount = 0;
  177. }
  178. private void incrementCounterAt(int pos)
  179. {
  180. int i = pos;
  181. while (i < ofbV.Length)
  182. {
  183. if (++ofbV[i++] != 0)
  184. {
  185. break;
  186. }
  187. }
  188. }
  189. private void checkCounter()
  190. {
  191. // TODO:
  192. // if the IV is the same as the blocksize we assume the user knows what they are doing
  193. // if (IV.length < ofbV.length)
  194. // {
  195. // for (int i = 0; i != IV.length; i++)
  196. // {
  197. // if (ofbV[i] != IV[i])
  198. // {
  199. // throw new IllegalStateException("Counter in KCTR mode out of range.");
  200. // }
  201. // }
  202. // }
  203. }
  204. }
  205. }
  206. #pragma warning restore
  207. #endif