CbcBlockCipher.cs 7.3 KB

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