RFC3211WrapEngine.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using Org.BouncyCastle.Crypto.Modes;
  4. using Org.BouncyCastle.Crypto.Parameters;
  5. using Org.BouncyCastle.Security;
  6. namespace Org.BouncyCastle.Crypto.Engines
  7. {
  8. /**
  9. * an implementation of the RFC 3211 Key Wrap
  10. * Specification.
  11. */
  12. public class Rfc3211WrapEngine
  13. : IWrapper
  14. {
  15. private CbcBlockCipher engine;
  16. private ParametersWithIV param;
  17. private bool forWrapping;
  18. private SecureRandom rand;
  19. public Rfc3211WrapEngine(
  20. IBlockCipher engine)
  21. {
  22. this.engine = new CbcBlockCipher(engine);
  23. }
  24. public virtual void Init(
  25. bool forWrapping,
  26. ICipherParameters param)
  27. {
  28. this.forWrapping = forWrapping;
  29. if (param is ParametersWithRandom)
  30. {
  31. ParametersWithRandom p = (ParametersWithRandom) param;
  32. this.rand = p.Random;
  33. this.param = (ParametersWithIV) p.Parameters;
  34. }
  35. else
  36. {
  37. if (forWrapping)
  38. {
  39. rand = new SecureRandom();
  40. }
  41. this.param = (ParametersWithIV) param;
  42. }
  43. }
  44. public virtual string AlgorithmName
  45. {
  46. get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
  47. }
  48. public virtual byte[] Wrap(
  49. byte[] inBytes,
  50. int inOff,
  51. int inLen)
  52. {
  53. if (!forWrapping)
  54. {
  55. throw new InvalidOperationException("not set for wrapping");
  56. }
  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. cekBlock[1] = (byte)~inBytes[inOff];
  70. cekBlock[2] = (byte)~inBytes[inOff + 1];
  71. cekBlock[3] = (byte)~inBytes[inOff + 2];
  72. Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
  73. rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
  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. if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
  116. {
  117. throw new InvalidCipherTextException("wrapped key corrupted");
  118. }
  119. byte[] key = new byte[cekBlock[0] & 0xff];
  120. Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
  121. // Note: Using constant time comparison
  122. int nonEqual = 0;
  123. for (int i = 0; i != 3; i++)
  124. {
  125. byte check = (byte)~cekBlock[1 + i];
  126. nonEqual |= (check ^ key[i]);
  127. }
  128. if (nonEqual != 0)
  129. throw new InvalidCipherTextException("wrapped key fails checksum");
  130. return key;
  131. }
  132. }
  133. }
  134. #endif