CbcBlockCipher.cs 8.4 KB

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