FastCbcBlockCipher.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.Connections.TLS.Crypto.Impl;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  7. namespace BestHTTP.Connections.TLS.Crypto
  8. {
  9. /**
  10. * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
  11. */
  12. [BestHTTP.PlatformSupport.IL2CPP.Il2CppSetOption(BestHTTP.PlatformSupport.IL2CPP.Option.NullChecks, false)]
  13. [BestHTTP.PlatformSupport.IL2CPP.Il2CppSetOption(BestHTTP.PlatformSupport.IL2CPP.Option.ArrayBoundsChecks, false)]
  14. [BestHTTP.PlatformSupport.IL2CPP.Il2CppSetOption(BestHTTP.PlatformSupport.IL2CPP.Option.DivideByZeroChecks, false)]
  15. [BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
  16. public class FastCbcBlockCipher
  17. : IBlockCipher
  18. {
  19. private byte[] IV, cbcV, cbcNextV;
  20. private int blockSize;
  21. private IBlockCipher cipher;
  22. private bool encrypting;
  23. /**
  24. * Basic constructor.
  25. *
  26. * @param cipher the block cipher to be used as the basis of chaining.
  27. */
  28. public FastCbcBlockCipher(
  29. IBlockCipher cipher)
  30. {
  31. this.cipher = cipher;
  32. this.blockSize = cipher.GetBlockSize();
  33. this.IV = new byte[blockSize];
  34. this.cbcV = new byte[blockSize];
  35. this.cbcNextV = new byte[blockSize];
  36. }
  37. /**
  38. * return the underlying block cipher that we are wrapping.
  39. *
  40. * @return the underlying block cipher that we are wrapping.
  41. */
  42. public IBlockCipher GetUnderlyingCipher()
  43. {
  44. return cipher;
  45. }
  46. /**
  47. * Initialise the cipher and, possibly, the initialisation vector (IV).
  48. * If an IV isn't passed as part of the parameter, the IV will be all zeros.
  49. *
  50. * @param forEncryption if true the cipher is initialised for
  51. * encryption, if false for decryption.
  52. * @param param the key and other data required by the cipher.
  53. * @exception ArgumentException if the parameters argument is
  54. * inappropriate.
  55. */
  56. public void Init(
  57. bool forEncryption,
  58. ICipherParameters parameters)
  59. {
  60. bool oldEncrypting = this.encrypting;
  61. this.encrypting = forEncryption;
  62. if (parameters is FastParametersWithIV)
  63. {
  64. FastParametersWithIV ivParam = (FastParametersWithIV)parameters;
  65. byte[] iv = ivParam.GetIV();
  66. if (iv.Length != blockSize)
  67. {
  68. throw new ArgumentException("initialisation vector must be the same length as block size");
  69. }
  70. Array.Copy(iv, 0, IV, 0, iv.Length);
  71. parameters = ivParam.Parameters;
  72. }
  73. Reset();
  74. // if null it's an IV changed only.
  75. if (parameters != null)
  76. {
  77. cipher.Init(encrypting, parameters);
  78. }
  79. else if (oldEncrypting != encrypting)
  80. {
  81. throw new ArgumentException("cannot change encrypting state without providing key.");
  82. }
  83. }
  84. /**
  85. * return the algorithm name and mode.
  86. *
  87. * @return the name of the underlying algorithm followed by "/CBC".
  88. */
  89. public string AlgorithmName
  90. {
  91. get { return cipher.AlgorithmName + "/CBC"; }
  92. }
  93. public bool IsPartialBlockOkay
  94. {
  95. get { return false; }
  96. }
  97. /**
  98. * return the block size of the underlying cipher.
  99. *
  100. * @return the block size of the underlying cipher.
  101. */
  102. public int GetBlockSize()
  103. {
  104. return cipher.GetBlockSize();
  105. }
  106. /**
  107. * Process one block of input from the array in and write it to
  108. * the out array.
  109. *
  110. * @param in the array containing the input data.
  111. * @param inOff offset into the in array the data starts at.
  112. * @param out the array the output data will be copied into.
  113. * @param outOff the offset into the out array the output will start at.
  114. * @exception DataLengthException if there isn't enough data in in, or
  115. * space in out.
  116. * @exception InvalidOperationException if the cipher isn't initialised.
  117. * @return the number of bytes processed and produced.
  118. */
  119. public int ProcessBlock(
  120. byte[] input,
  121. int inOff,
  122. byte[] output,
  123. int outOff)
  124. {
  125. return (encrypting)
  126. ? EncryptBlock(input, inOff, output, outOff)
  127. : DecryptBlock(input, inOff, output, outOff);
  128. }
  129. /**
  130. * reset the chaining vector back to the IV and reset the underlying
  131. * cipher.
  132. */
  133. public void Reset()
  134. {
  135. Array.Copy(IV, 0, cbcV, 0, IV.Length);
  136. Array.Clear(cbcNextV, 0, cbcNextV.Length);
  137. cipher.Reset();
  138. }
  139. /**
  140. * Do the appropriate chaining step for CBC mode encryption.
  141. *
  142. * @param in the array containing the data to be encrypted.
  143. * @param inOff offset into the in array the data starts at.
  144. * @param out the array the encrypted data will be copied into.
  145. * @param outOff the offset into the out array the output will start at.
  146. * @exception DataLengthException if there isn't enough data in in, or
  147. * space in out.
  148. * @exception InvalidOperationException if the cipher isn't initialised.
  149. * @return the number of bytes processed and produced.
  150. */
  151. private unsafe int EncryptBlock(
  152. byte[] input,
  153. int inOff,
  154. byte[] outBytes,
  155. int outOff)
  156. {
  157. if ((inOff + blockSize) > input.Length)
  158. {
  159. throw new DataLengthException("input buffer too short");
  160. }
  161. /*
  162. * XOR the cbcV and the input,
  163. * then encrypt the cbcV
  164. */
  165. //for (int i = 0; i < blockSize; i++)
  166. //{
  167. // cbcV[i] ^= input[inOff + i];
  168. //}
  169. fixed (byte* pinput = input, pcbcV = cbcV)
  170. {
  171. ulong* pulongInput = (ulong*)&pinput[inOff], pulongcbcV = (ulong*)pcbcV;
  172. for (int i = 0; i < blockSize / 8; i++)
  173. pulongcbcV[i] ^= pulongInput[i];
  174. }
  175. int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
  176. /*
  177. * copy ciphertext to cbcV
  178. */
  179. Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
  180. return length;
  181. }
  182. /**
  183. * Do the appropriate chaining step for CBC mode decryption.
  184. *
  185. * @param in the array containing the data to be decrypted.
  186. * @param inOff offset into the in array the data starts at.
  187. * @param out the array the decrypted data will be copied into.
  188. * @param outOff the offset into the out array the output will start at.
  189. * @exception DataLengthException if there isn't enough data in in, or
  190. * space in out.
  191. * @exception InvalidOperationException if the cipher isn't initialised.
  192. * @return the number of bytes processed and produced.
  193. */
  194. private unsafe int DecryptBlock(
  195. byte[] input,
  196. int inOff,
  197. byte[] outBytes,
  198. int outOff)
  199. {
  200. if ((inOff + blockSize) > input.Length)
  201. {
  202. throw new DataLengthException("input buffer too short");
  203. }
  204. Array.Copy(input, inOff, cbcNextV, 0, blockSize);
  205. int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
  206. /*
  207. * XOR the cbcV and the output
  208. */
  209. //for (int i = 0; i < blockSize; i++)
  210. //{
  211. // outBytes[outOff + i] ^= cbcV[i];
  212. //}
  213. fixed (byte* poutBytes = outBytes, pcbcV = cbcV)
  214. {
  215. ulong* pulongBytes = (ulong*)&poutBytes[outOff], pulongcbcV = (ulong*)pcbcV;
  216. for (int i = 0; i < blockSize / 8; i++)
  217. pulongBytes[i] ^= pulongcbcV[i];
  218. }
  219. /*
  220. * swap the back up buffer into next position
  221. */
  222. byte[] tmp;
  223. tmp = cbcV;
  224. cbcV = cbcNextV;
  225. cbcNextV = tmp;
  226. return length;
  227. }
  228. }
  229. }
  230. #pragma warning restore
  231. #endif