ISO9796d1Encoding.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
  7. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Encodings
  8. {
  9. /**
  10. * ISO 9796-1 padding. Note in the light of recent results you should
  11. * only use this with RSA (rather than the "simpler" Rabin keys) and you
  12. * should never use it with anything other than a hash (ie. even if the
  13. * message is small don't sign the message, sign it's hash) or some "random"
  14. * value. See your favorite search engine for details.
  15. */
  16. public class ISO9796d1Encoding
  17. : IAsymmetricBlockCipher
  18. {
  19. private static readonly BigInteger Sixteen = BigInteger.ValueOf(16);
  20. private static readonly BigInteger Six = BigInteger.ValueOf(6);
  21. private static readonly byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
  22. 0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
  23. private static readonly byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
  24. 0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
  25. private readonly IAsymmetricBlockCipher engine;
  26. private bool forEncryption;
  27. private int bitSize;
  28. private int padBits = 0;
  29. private BigInteger modulus;
  30. public ISO9796d1Encoding(IAsymmetricBlockCipher cipher)
  31. {
  32. this.engine = cipher;
  33. }
  34. public string AlgorithmName => engine.AlgorithmName + "/ISO9796-1Padding";
  35. public IAsymmetricBlockCipher UnderlyingCipher => engine;
  36. public void Init(bool forEncryption, ICipherParameters parameters)
  37. {
  38. RsaKeyParameters kParam;
  39. if (parameters is ParametersWithRandom withRandom)
  40. {
  41. kParam = (RsaKeyParameters)withRandom.Parameters;
  42. }
  43. else
  44. {
  45. kParam = (RsaKeyParameters)parameters;
  46. }
  47. engine.Init(forEncryption, parameters);
  48. modulus = kParam.Modulus;
  49. bitSize = modulus.BitLength;
  50. this.forEncryption = forEncryption;
  51. }
  52. /**
  53. * return the input block size. The largest message we can process
  54. * is (key_size_in_bits + 3)/16, which in our world comes to
  55. * key_size_in_bytes / 2.
  56. */
  57. public int GetInputBlockSize()
  58. {
  59. int baseBlockSize = engine.GetInputBlockSize();
  60. if (forEncryption)
  61. {
  62. return (baseBlockSize + 1) / 2;
  63. }
  64. else
  65. {
  66. return baseBlockSize;
  67. }
  68. }
  69. /**
  70. * return the maximum possible size for the output.
  71. */
  72. public int GetOutputBlockSize()
  73. {
  74. int baseBlockSize = engine.GetOutputBlockSize();
  75. if (forEncryption)
  76. {
  77. return baseBlockSize;
  78. }
  79. else
  80. {
  81. return (baseBlockSize + 1) / 2;
  82. }
  83. }
  84. /**
  85. * set the number of bits in the next message to be treated as
  86. * pad bits.
  87. */
  88. public void SetPadBits(
  89. int padBits)
  90. {
  91. if (padBits > 7)
  92. {
  93. throw new ArgumentException("padBits > 7");
  94. }
  95. this.padBits = padBits;
  96. }
  97. /**
  98. * retrieve the number of pad bits in the last decoded message.
  99. */
  100. public int GetPadBits()
  101. {
  102. return padBits;
  103. }
  104. public byte[] ProcessBlock(
  105. byte[] input,
  106. int inOff,
  107. int length)
  108. {
  109. if (forEncryption)
  110. {
  111. return EncodeBlock(input, inOff, length);
  112. }
  113. else
  114. {
  115. return DecodeBlock(input, inOff, length);
  116. }
  117. }
  118. private byte[] EncodeBlock(
  119. byte[] input,
  120. int inOff,
  121. int inLen)
  122. {
  123. byte[] block = new byte[(bitSize + 7) / 8];
  124. int r = padBits + 1;
  125. int z = inLen;
  126. int t = (bitSize + 13) / 16;
  127. for (int i = 0; i < t; i += z)
  128. {
  129. if (i > t - z)
  130. {
  131. Array.Copy(input, inOff + inLen - (t - i),
  132. block, block.Length - t, t - i);
  133. }
  134. else
  135. {
  136. Array.Copy(input, inOff, block, block.Length - (i + z), z);
  137. }
  138. }
  139. for (int i = block.Length - 2 * t; i != block.Length; i += 2)
  140. {
  141. byte val = block[block.Length - t + i / 2];
  142. block[i] = (byte)((shadows[(uint) (val & 0xff) >> 4] << 4)
  143. | shadows[val & 0x0f]);
  144. block[i + 1] = val;
  145. }
  146. block[block.Length - 2 * z] ^= (byte) r;
  147. block[block.Length - 1] = (byte)((block[block.Length - 1] << 4) | 0x06);
  148. int maxBit = (8 - (bitSize - 1) % 8);
  149. int offSet = 0;
  150. if (maxBit != 8)
  151. {
  152. block[0] &= (byte) ((ushort) 0xff >> maxBit);
  153. block[0] |= (byte) ((ushort) 0x80 >> maxBit);
  154. }
  155. else
  156. {
  157. block[0] = 0x00;
  158. block[1] |= 0x80;
  159. offSet = 1;
  160. }
  161. return engine.ProcessBlock(block, offSet, block.Length - offSet);
  162. }
  163. /**
  164. * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
  165. */
  166. private byte[] DecodeBlock(
  167. byte[] input,
  168. int inOff,
  169. int inLen)
  170. {
  171. byte[] block = engine.ProcessBlock(input, inOff, inLen);
  172. int r = 1;
  173. int t = (bitSize + 13) / 16;
  174. BigInteger iS = new BigInteger(1, block);
  175. BigInteger iR;
  176. if (iS.Mod(Sixteen).Equals(Six))
  177. {
  178. iR = iS;
  179. }
  180. else
  181. {
  182. iR = modulus.Subtract(iS);
  183. if (!iR.Mod(Sixteen).Equals(Six))
  184. throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16");
  185. }
  186. block = iR.ToByteArrayUnsigned();
  187. if ((block[block.Length - 1] & 0x0f) != 0x6)
  188. throw new InvalidCipherTextException("invalid forcing byte in block");
  189. block[block.Length - 1] =
  190. (byte)(((ushort)(block[block.Length - 1] & 0xff) >> 4)
  191. | ((inverse[(block[block.Length - 2] & 0xff) >> 4]) << 4));
  192. block[0] = (byte)((shadows[(uint) (block[1] & 0xff) >> 4] << 4)
  193. | shadows[block[1] & 0x0f]);
  194. bool boundaryFound = false;
  195. int boundary = 0;
  196. for (int i = block.Length - 1; i >= block.Length - 2 * t; i -= 2)
  197. {
  198. int val = ((shadows[(uint) (block[i] & 0xff) >> 4] << 4)
  199. | shadows[block[i] & 0x0f]);
  200. if (((block[i - 1] ^ val) & 0xff) != 0)
  201. {
  202. if (!boundaryFound)
  203. {
  204. boundaryFound = true;
  205. r = (block[i - 1] ^ val) & 0xff;
  206. boundary = i - 1;
  207. }
  208. else
  209. {
  210. throw new InvalidCipherTextException("invalid tsums in block");
  211. }
  212. }
  213. }
  214. block[boundary] = 0;
  215. byte[] nblock = new byte[(block.Length - boundary) / 2];
  216. for (int i = 0; i < nblock.Length; i++)
  217. {
  218. nblock[i] = block[2 * i + boundary + 1];
  219. }
  220. padBits = r - 1;
  221. return nblock;
  222. }
  223. }
  224. }
  225. #pragma warning restore
  226. #endif