178 lines
5.9 KiB
C#
178 lines
5.9 KiB
C#
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
|
#pragma warning disable
|
|
using System;
|
|
using System.IO;
|
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
|
|
{
|
|
/// <summary>
|
|
/// A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest.
|
|
/// </summary>
|
|
public class TlsMac
|
|
{
|
|
protected readonly TlsContext context;
|
|
protected readonly byte[] secret;
|
|
protected readonly IMac mac;
|
|
protected readonly int digestBlockSize;
|
|
protected readonly int digestOverhead;
|
|
protected readonly int macLength;
|
|
|
|
/**
|
|
* Generate a new instance of an TlsMac.
|
|
*
|
|
* @param context the TLS client context
|
|
* @param digest The digest to use.
|
|
* @param key A byte-array where the key for this MAC is located.
|
|
* @param keyOff The number of bytes to skip, before the key starts in the buffer.
|
|
* @param keyLen The length of the key.
|
|
*/
|
|
public TlsMac(TlsContext context, IDigest digest, byte[] key, int keyOff, int keyLen)
|
|
{
|
|
this.context = context;
|
|
|
|
KeyParameter keyParameter = new KeyParameter(key, keyOff, keyLen);
|
|
|
|
this.secret = Arrays.Clone(keyParameter.GetKey());
|
|
|
|
// TODO This should check the actual algorithm, not rely on the engine type
|
|
if (digest is LongDigest)
|
|
{
|
|
this.digestBlockSize = 128;
|
|
this.digestOverhead = 16;
|
|
}
|
|
else
|
|
{
|
|
this.digestBlockSize = 64;
|
|
this.digestOverhead = 8;
|
|
}
|
|
|
|
if (TlsUtilities.IsSsl(context))
|
|
{
|
|
this.mac = new Ssl3Mac(digest);
|
|
|
|
// TODO This should check the actual algorithm, not assume based on the digest size
|
|
if (digest.GetDigestSize() == 20)
|
|
{
|
|
/*
|
|
* NOTE: When SHA-1 is used with the SSL 3.0 MAC, the secret + input pad is not
|
|
* digest block-aligned.
|
|
*/
|
|
this.digestOverhead = 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.mac = new HMac(digest);
|
|
|
|
// NOTE: The input pad for HMAC is always a full digest block
|
|
}
|
|
|
|
this.mac.Init(keyParameter);
|
|
|
|
this.macLength = mac.GetMacSize();
|
|
if (context.SecurityParameters.truncatedHMac)
|
|
{
|
|
this.macLength = System.Math.Min(this.macLength, 10);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the MAC write secret
|
|
*/
|
|
public virtual byte[] MacSecret
|
|
{
|
|
get { return this.secret; }
|
|
}
|
|
|
|
/**
|
|
* @return The output length of this MAC.
|
|
*/
|
|
public virtual int Size
|
|
{
|
|
get { return macLength; }
|
|
}
|
|
|
|
/**
|
|
* Calculate the MAC for some given data.
|
|
*
|
|
* @param type The message type of the message.
|
|
* @param message A byte-buffer containing the message.
|
|
* @param offset The number of bytes to skip, before the message starts.
|
|
* @param length The length of the message.
|
|
* @return A new byte-buffer containing the MAC value.
|
|
*/
|
|
public virtual byte[] CalculateMac(long seqNo, byte type, byte[] message, int offset, int length)
|
|
{
|
|
ProtocolVersion serverVersion = context.ServerVersion;
|
|
bool isSsl = serverVersion.IsSsl;
|
|
|
|
byte[] macHeader = new byte[isSsl ? 11 : 13];
|
|
TlsUtilities.WriteUint64(seqNo, macHeader, 0);
|
|
TlsUtilities.WriteUint8(type, macHeader, 8);
|
|
if (!isSsl)
|
|
{
|
|
TlsUtilities.WriteVersion(serverVersion, macHeader, 9);
|
|
}
|
|
TlsUtilities.WriteUint16(length, macHeader, macHeader.Length - 2);
|
|
|
|
mac.BlockUpdate(macHeader, 0, macHeader.Length);
|
|
mac.BlockUpdate(message, offset, length);
|
|
|
|
return Truncate(MacUtilities.DoFinal(mac));
|
|
}
|
|
|
|
public virtual byte[] CalculateMacConstantTime(long seqNo, byte type, byte[] message, int offset, int length,
|
|
int fullLength, byte[] dummyData)
|
|
{
|
|
/*
|
|
* Actual MAC only calculated on 'length' bytes...
|
|
*/
|
|
byte[] result = CalculateMac(seqNo, type, message, offset, length);
|
|
|
|
/*
|
|
* ...but ensure a constant number of complete digest blocks are processed (as many as would
|
|
* be needed for 'fullLength' bytes of input).
|
|
*/
|
|
int headerLength = TlsUtilities.IsSsl(context) ? 11 : 13;
|
|
|
|
// How many extra full blocks do we need to calculate?
|
|
int extra = GetDigestBlockCount(headerLength + fullLength) - GetDigestBlockCount(headerLength + length);
|
|
|
|
while (--extra >= 0)
|
|
{
|
|
mac.BlockUpdate(dummyData, 0, digestBlockSize);
|
|
}
|
|
|
|
// One more byte in case the implementation is "lazy" about processing blocks
|
|
mac.Update(dummyData[0]);
|
|
mac.Reset();
|
|
|
|
return result;
|
|
}
|
|
|
|
protected virtual int GetDigestBlockCount(int inputLength)
|
|
{
|
|
// NOTE: This calculation assumes a minimum of 1 pad byte
|
|
return (inputLength + digestOverhead) / digestBlockSize;
|
|
}
|
|
|
|
protected virtual byte[] Truncate(byte[] bs)
|
|
{
|
|
if (bs.Length <= macLength)
|
|
{
|
|
return bs;
|
|
}
|
|
|
|
return Arrays.CopyOf(bs, macLength);
|
|
}
|
|
}
|
|
}
|
|
#pragma warning restore
|
|
#endif
|