OfbBlockCipher.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  5. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
  6. {
  7. /**
  8. * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
  9. */
  10. public class OfbBlockCipher
  11. : IBlockCipherMode
  12. {
  13. private byte[] IV;
  14. private byte[] ofbV;
  15. private byte[] ofbOutV;
  16. private readonly int blockSize;
  17. private readonly IBlockCipher cipher;
  18. /**
  19. * Basic constructor.
  20. *
  21. * @param cipher the block cipher to be used as the basis of the
  22. * feedback mode.
  23. * @param blockSize the block size in bits (note: a multiple of 8)
  24. */
  25. public OfbBlockCipher(
  26. IBlockCipher cipher,
  27. int blockSize)
  28. {
  29. this.cipher = cipher;
  30. this.blockSize = blockSize / 8;
  31. this.IV = new byte[cipher.GetBlockSize()];
  32. this.ofbV = new byte[cipher.GetBlockSize()];
  33. this.ofbOutV = new byte[cipher.GetBlockSize()];
  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 UnderlyingCipher => cipher;
  41. /**
  42. * Initialise the cipher and, possibly, the initialisation vector (IV).
  43. * If an IV isn't passed as part of the parameter, the IV will be all zeros.
  44. * An IV which is too short is handled in FIPS compliant fashion.
  45. *
  46. * @param forEncryption if true the cipher is initialised for
  47. * encryption, if false for decryption.
  48. * @param param the key and other data required by the cipher.
  49. * @exception ArgumentException if the parameters argument is
  50. * inappropriate.
  51. */
  52. public void Init(
  53. bool forEncryption, //ignored by this OFB mode
  54. ICipherParameters parameters)
  55. {
  56. if (parameters is ParametersWithIV ivParam)
  57. {
  58. byte[] iv = ivParam.GetIV();
  59. if (iv.Length < IV.Length)
  60. {
  61. // prepend the supplied IV with zeros (per FIPS PUB 81)
  62. Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
  63. for (int i = 0; i < IV.Length - iv.Length; i++)
  64. {
  65. IV[i] = 0;
  66. }
  67. }
  68. else
  69. {
  70. Array.Copy(iv, 0, IV, 0, IV.Length);
  71. }
  72. parameters = ivParam.Parameters;
  73. }
  74. Reset();
  75. // if it's null, key is to be reused.
  76. if (parameters != null)
  77. {
  78. cipher.Init(true, parameters);
  79. }
  80. }
  81. /**
  82. * return the algorithm name and mode.
  83. *
  84. * @return the name of the underlying algorithm followed by "/OFB"
  85. * and the block size in bits
  86. */
  87. public string AlgorithmName
  88. {
  89. get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); }
  90. }
  91. public bool IsPartialBlockOkay
  92. {
  93. get { return true; }
  94. }
  95. /**
  96. * return the block size we are operating at (in bytes).
  97. *
  98. * @return the block size we are operating at (in bytes).
  99. */
  100. public int GetBlockSize()
  101. {
  102. return blockSize;
  103. }
  104. public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
  105. {
  106. Check.DataLength(input, inOff, blockSize, "input buffer too short");
  107. Check.OutputLength(output, outOff, blockSize, "output buffer too short");
  108. cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
  109. //
  110. // XOR the ofbV with the plaintext producing the cipher text (and
  111. // the next input block).
  112. //
  113. for (int i = 0; i < blockSize; i++)
  114. {
  115. output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
  116. }
  117. //
  118. // change over the input block.
  119. //
  120. Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
  121. Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
  122. return blockSize;
  123. }
  124. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  125. public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
  126. {
  127. Check.DataLength(input, blockSize, "input buffer too short");
  128. Check.OutputLength(output, blockSize, "output buffer too short");
  129. cipher.ProcessBlock(ofbV, ofbOutV);
  130. //
  131. // XOR the ofbV with the plaintext producing the cipher text (and
  132. // the next input block).
  133. //
  134. for (int i = 0; i < blockSize; i++)
  135. {
  136. output[i] = (byte)(ofbOutV[i] ^ input[i]);
  137. }
  138. //
  139. // change over the input block.
  140. //
  141. Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
  142. Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
  143. return blockSize;
  144. }
  145. #endif
  146. /**
  147. * reset the feedback vector back to the IV and reset the underlying
  148. * cipher.
  149. */
  150. public void Reset()
  151. {
  152. Array.Copy(IV, 0, ofbV, 0, IV.Length);
  153. }
  154. }
  155. }
  156. #pragma warning restore
  157. #endif