TlsMac.cs 5.9 KB

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