RFC3211WrapEngine.cs 4.4 KB

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