RFC3211WrapEngine.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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.Modes;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  7. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines
  8. {
  9. /**
  10. * an implementation of the RFC 3211 Key Wrap
  11. * Specification.
  12. */
  13. public class Rfc3211WrapEngine
  14. : IWrapper
  15. {
  16. private CbcBlockCipher engine;
  17. private ParametersWithIV param;
  18. private bool forWrapping;
  19. private SecureRandom rand;
  20. public Rfc3211WrapEngine(
  21. IBlockCipher engine)
  22. {
  23. this.engine = new CbcBlockCipher(engine);
  24. }
  25. public virtual void Init(bool forWrapping, ICipherParameters param)
  26. {
  27. this.forWrapping = forWrapping;
  28. if (param is ParametersWithRandom withRandom)
  29. {
  30. this.rand = withRandom.Random;
  31. this.param = withRandom.Parameters as ParametersWithIV;
  32. }
  33. else
  34. {
  35. if (forWrapping)
  36. {
  37. rand = CryptoServicesRegistrar.GetSecureRandom();
  38. }
  39. this.param = param as ParametersWithIV;
  40. }
  41. if (null == this.param)
  42. throw new ArgumentException("RFC3211Wrap requires an IV", "param");
  43. }
  44. public virtual string AlgorithmName
  45. {
  46. get { return engine.UnderlyingCipher.AlgorithmName + "/RFC3211Wrap"; }
  47. }
  48. public virtual byte[] Wrap(
  49. byte[] inBytes,
  50. int inOff,
  51. int inLen)
  52. {
  53. if (!forWrapping)
  54. throw new InvalidOperationException("not set for wrapping");
  55. if (inLen > 255 || inLen < 0)
  56. throw new ArgumentException("input must be from 0 to 255 bytes", "inLen");
  57. engine.Init(true, param);
  58. int blockSize = engine.GetBlockSize();
  59. byte[] cekBlock;
  60. if (inLen + 4 < blockSize * 2)
  61. {
  62. cekBlock = new byte[blockSize * 2];
  63. }
  64. else
  65. {
  66. cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize];
  67. }
  68. cekBlock[0] = (byte)inLen;
  69. Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
  70. rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
  71. cekBlock[1] = (byte)~cekBlock[4];
  72. cekBlock[2] = (byte)~cekBlock[4 + 1];
  73. cekBlock[3] = (byte)~cekBlock[4 + 2];
  74. for (int i = 0; i < cekBlock.Length; i += blockSize)
  75. {
  76. engine.ProcessBlock(cekBlock, i, cekBlock, i);
  77. }
  78. for (int i = 0; i < cekBlock.Length; i += blockSize)
  79. {
  80. engine.ProcessBlock(cekBlock, i, cekBlock, i);
  81. }
  82. return cekBlock;
  83. }
  84. public virtual byte[] Unwrap(
  85. byte[] inBytes,
  86. int inOff,
  87. int inLen)
  88. {
  89. if (forWrapping)
  90. {
  91. throw new InvalidOperationException("not set for unwrapping");
  92. }
  93. int blockSize = engine.GetBlockSize();
  94. if (inLen < 2 * blockSize)
  95. {
  96. throw new InvalidCipherTextException("input too short");
  97. }
  98. byte[] cekBlock = new byte[inLen];
  99. byte[] iv = new byte[blockSize];
  100. Array.Copy(inBytes, inOff, cekBlock, 0, inLen);
  101. Array.Copy(inBytes, inOff, iv, 0, iv.Length);
  102. engine.Init(false, new ParametersWithIV(param.Parameters, iv));
  103. for (int i = blockSize; i < cekBlock.Length; i += blockSize)
  104. {
  105. engine.ProcessBlock(cekBlock, i, cekBlock, i);
  106. }
  107. Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length);
  108. engine.Init(false, new ParametersWithIV(param.Parameters, iv));
  109. engine.ProcessBlock(cekBlock, 0, cekBlock, 0);
  110. engine.Init(false, param);
  111. for (int i = 0; i < cekBlock.Length; i += blockSize)
  112. {
  113. engine.ProcessBlock(cekBlock, i, cekBlock, i);
  114. }
  115. bool invalidLength = (int)cekBlock[0] > (cekBlock.Length - 4);
  116. byte[] key;
  117. if (invalidLength)
  118. {
  119. key = new byte[cekBlock.Length - 4];
  120. }
  121. else
  122. {
  123. key = new byte[cekBlock[0]];
  124. }
  125. Array.Copy(cekBlock, 4, key, 0, key.Length);
  126. // Note: Using constant time comparison
  127. int nonEqual = 0;
  128. for (int i = 0; i != 3; i++)
  129. {
  130. byte check = (byte)~cekBlock[1 + i];
  131. nonEqual |= (check ^ cekBlock[4 + i]);
  132. }
  133. Array.Clear(cekBlock, 0, cekBlock.Length);
  134. if (nonEqual != 0 | invalidLength)
  135. throw new InvalidCipherTextException("wrapped key corrupted");
  136. return key;
  137. }
  138. }
  139. }
  140. #pragma warning restore
  141. #endif