TlsMac.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.IO;
  4. using Org.BouncyCastle.Crypto.Digests;
  5. using Org.BouncyCastle.Crypto.Macs;
  6. using Org.BouncyCastle.Crypto.Parameters;
  7. using Org.BouncyCastle.Security;
  8. using Org.BouncyCastle.Utilities;
  9. namespace Org.BouncyCastle.Crypto.Tls
  10. {
  11. /// <summary>
  12. /// A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest.
  13. /// </summary>
  14. public class TlsMac
  15. {
  16. protected readonly TlsContext context;
  17. protected readonly byte[] secret;
  18. protected readonly IMac mac;
  19. protected readonly int digestBlockSize;
  20. protected readonly int digestOverhead;
  21. protected readonly int macLength;
  22. /**
  23. * Generate a new instance of an TlsMac.
  24. *
  25. * @param context the TLS client context
  26. * @param digest The digest to use.
  27. * @param key A byte-array where the key for this MAC is located.
  28. * @param keyOff The number of bytes to skip, before the key starts in the buffer.
  29. * @param keyLen The length of the key.
  30. */
  31. public TlsMac(TlsContext context, IDigest digest, byte[] key, int keyOff, int keyLen)
  32. {
  33. this.context = context;
  34. KeyParameter keyParameter = new KeyParameter(key, keyOff, keyLen);
  35. this.secret = Arrays.Clone(keyParameter.GetKey());
  36. // TODO This should check the actual algorithm, not rely on the engine type
  37. if (digest is LongDigest)
  38. {
  39. this.digestBlockSize = 128;
  40. this.digestOverhead = 16;
  41. }
  42. else
  43. {
  44. this.digestBlockSize = 64;
  45. this.digestOverhead = 8;
  46. }
  47. if (TlsUtilities.IsSsl(context))
  48. {
  49. this.mac = new Ssl3Mac(digest);
  50. // TODO This should check the actual algorithm, not assume based on the digest size
  51. if (digest.GetDigestSize() == 20)
  52. {
  53. /*
  54. * NOTE: When SHA-1 is used with the SSL 3.0 MAC, the secret + input pad is not
  55. * digest block-aligned.
  56. */
  57. this.digestOverhead = 4;
  58. }
  59. }
  60. else
  61. {
  62. this.mac = new HMac(digest);
  63. // NOTE: The input pad for HMAC is always a full digest block
  64. }
  65. this.mac.Init(keyParameter);
  66. this.macLength = mac.GetMacSize();
  67. if (context.SecurityParameters.truncatedHMac)
  68. {
  69. this.macLength = System.Math.Min(this.macLength, 10);
  70. }
  71. }
  72. /**
  73. * @return the MAC write secret
  74. */
  75. public virtual byte[] MacSecret
  76. {
  77. get { return this.secret; }
  78. }
  79. /**
  80. * @return The output length of this MAC.
  81. */
  82. public virtual int Size
  83. {
  84. get { return macLength; }
  85. }
  86. /**
  87. * Calculate the MAC for some given data.
  88. *
  89. * @param type The message type of the message.
  90. * @param message A byte-buffer containing the message.
  91. * @param offset The number of bytes to skip, before the message starts.
  92. * @param length The length of the message.
  93. * @return A new byte-buffer containing the MAC value.
  94. */
  95. public virtual byte[] CalculateMac(long seqNo, byte type, byte[] message, int offset, int length)
  96. {
  97. ProtocolVersion serverVersion = context.ServerVersion;
  98. bool isSsl = serverVersion.IsSsl;
  99. byte[] macHeader = new byte[isSsl ? 11 : 13];
  100. TlsUtilities.WriteUint64(seqNo, macHeader, 0);
  101. TlsUtilities.WriteUint8(type, macHeader, 8);
  102. if (!isSsl)
  103. {
  104. TlsUtilities.WriteVersion(serverVersion, macHeader, 9);
  105. }
  106. TlsUtilities.WriteUint16(length, macHeader, macHeader.Length - 2);
  107. mac.BlockUpdate(macHeader, 0, macHeader.Length);
  108. mac.BlockUpdate(message, offset, length);
  109. return Truncate(MacUtilities.DoFinal(mac));
  110. }
  111. public virtual byte[] CalculateMacConstantTime(long seqNo, byte type, byte[] message, int offset, int length,
  112. int fullLength, byte[] dummyData)
  113. {
  114. /*
  115. * Actual MAC only calculated on 'length' bytes...
  116. */
  117. byte[] result = CalculateMac(seqNo, type, message, offset, length);
  118. /*
  119. * ...but ensure a constant number of complete digest blocks are processed (as many as would
  120. * be needed for 'fullLength' bytes of input).
  121. */
  122. int headerLength = TlsUtilities.IsSsl(context) ? 11 : 13;
  123. // How many extra full blocks do we need to calculate?
  124. int extra = GetDigestBlockCount(headerLength + fullLength) - GetDigestBlockCount(headerLength + length);
  125. while (--extra >= 0)
  126. {
  127. mac.BlockUpdate(dummyData, 0, digestBlockSize);
  128. }
  129. // One more byte in case the implementation is "lazy" about processing blocks
  130. mac.Update(dummyData[0]);
  131. mac.Reset();
  132. return result;
  133. }
  134. protected virtual int GetDigestBlockCount(int inputLength)
  135. {
  136. // NOTE: This calculation assumes a minimum of 1 pad byte
  137. return (inputLength + digestOverhead) / digestBlockSize;
  138. }
  139. protected virtual byte[] Truncate(byte[] bs)
  140. {
  141. if (bs.Length <= macLength)
  142. {
  143. return bs;
  144. }
  145. return Arrays.CopyOf(bs, macLength);
  146. }
  147. }
  148. }
  149. #endif