You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
5.9 KiB
203 lines
5.9 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs |
|
{ |
|
/// <summary> |
|
/// Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe |
|
/// Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf). |
|
/// </summary> |
|
/// <remarks> |
|
/// "SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d are the number of |
|
/// compression rounds and the number of finalization rounds. A compression round is identical to a |
|
/// finalization round and this round function is called SipRound. Given a 128-bit key k and a |
|
/// (possibly empty) byte string m, SipHash-c-d returns a 64-bit value..." |
|
/// </remarks> |
|
public class SipHash |
|
: IMac |
|
{ |
|
protected readonly int c, d; |
|
|
|
protected long k0, k1; |
|
protected long v0, v1, v2, v3; |
|
|
|
protected long m = 0; |
|
protected int wordPos = 0; |
|
protected int wordCount = 0; |
|
|
|
/// <summary>SipHash-2-4</summary> |
|
public SipHash() |
|
: this(2, 4) |
|
{ |
|
} |
|
|
|
/// <summary>SipHash-c-d</summary> |
|
/// <param name="c">the number of compression rounds</param> |
|
/// <param name="d">the number of finalization rounds</param> |
|
public SipHash(int c, int d) |
|
{ |
|
this.c = c; |
|
this.d = d; |
|
} |
|
|
|
public virtual string AlgorithmName |
|
{ |
|
get { return "SipHash-" + c + "-" + d; } |
|
} |
|
|
|
public virtual int GetMacSize() |
|
{ |
|
return 8; |
|
} |
|
|
|
public virtual void Init(ICipherParameters parameters) |
|
{ |
|
KeyParameter keyParameter = parameters as KeyParameter; |
|
if (keyParameter == null) |
|
throw new ArgumentException("must be an instance of KeyParameter", "parameters"); |
|
byte[] key = keyParameter.GetKey(); |
|
if (key.Length != 16) |
|
throw new ArgumentException("must be a 128-bit key", "parameters"); |
|
|
|
this.k0 = (long)Pack.LE_To_UInt64(key, 0); |
|
this.k1 = (long)Pack.LE_To_UInt64(key, 8); |
|
|
|
Reset(); |
|
} |
|
|
|
public virtual void Update(byte input) |
|
{ |
|
m = (long)(((ulong)m >> 8) | ((ulong)input << 56)); |
|
|
|
if (++wordPos == 8) |
|
{ |
|
ProcessMessageWord(); |
|
wordPos = 0; |
|
} |
|
} |
|
|
|
public virtual void BlockUpdate(byte[] input, int offset, int length) |
|
{ |
|
int i = 0, fullWords = length & ~7; |
|
if (wordPos == 0) |
|
{ |
|
for (; i < fullWords; i += 8) |
|
{ |
|
m = (long)Pack.LE_To_UInt64(input, offset + i); |
|
ProcessMessageWord(); |
|
} |
|
for (; i < length; ++i) |
|
{ |
|
m = (long)(((ulong)m >> 8) | ((ulong)input[offset + i] << 56)); |
|
} |
|
wordPos = length - fullWords; |
|
} |
|
else |
|
{ |
|
int bits = wordPos << 3; |
|
for (; i < fullWords; i += 8) |
|
{ |
|
ulong n = Pack.LE_To_UInt64(input, offset + i); |
|
m = (long)((n << bits) | ((ulong)m >> -bits)); |
|
ProcessMessageWord(); |
|
m = (long)n; |
|
} |
|
for (; i < length; ++i) |
|
{ |
|
m = (long)(((ulong)m >> 8) | ((ulong)input[offset + i] << 56)); |
|
|
|
if (++wordPos == 8) |
|
{ |
|
ProcessMessageWord(); |
|
wordPos = 0; |
|
} |
|
} |
|
} |
|
} |
|
|
|
public virtual long DoFinal() |
|
{ |
|
// NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0 |
|
m = (long)((ulong)m >> ((7 - wordPos) << 3)); |
|
m = (long)((ulong)m >> 8); |
|
m = (long)((ulong)m | ((ulong)((wordCount << 3) + wordPos) << 56)); |
|
|
|
ProcessMessageWord(); |
|
|
|
v2 ^= 0xffL; |
|
|
|
ApplySipRounds(d); |
|
|
|
long result = v0 ^ v1 ^ v2 ^ v3; |
|
|
|
Reset(); |
|
|
|
return result; |
|
} |
|
|
|
public virtual int DoFinal(byte[] output, int outOff) |
|
{ |
|
long result = DoFinal(); |
|
Pack.UInt64_To_LE((ulong)result, output, outOff); |
|
return 8; |
|
} |
|
|
|
public virtual void Reset() |
|
{ |
|
v0 = k0 ^ 0x736f6d6570736575L; |
|
v1 = k1 ^ 0x646f72616e646f6dL; |
|
v2 = k0 ^ 0x6c7967656e657261L; |
|
v3 = k1 ^ 0x7465646279746573L; |
|
|
|
m = 0; |
|
wordPos = 0; |
|
wordCount = 0; |
|
} |
|
|
|
protected virtual void ProcessMessageWord() |
|
{ |
|
++wordCount; |
|
v3 ^= m; |
|
ApplySipRounds(c); |
|
v0 ^= m; |
|
} |
|
|
|
protected virtual void ApplySipRounds(int n) |
|
{ |
|
long r0 = v0, r1 = v1, r2 = v2, r3 = v3; |
|
|
|
for (int r = 0; r < n; ++r) |
|
{ |
|
r0 += r1; |
|
r2 += r3; |
|
r1 = RotateLeft(r1, 13); |
|
r3 = RotateLeft(r3, 16); |
|
r1 ^= r0; |
|
r3 ^= r2; |
|
r0 = RotateLeft(r0, 32); |
|
r2 += r1; |
|
r0 += r3; |
|
r1 = RotateLeft(r1, 17); |
|
r3 = RotateLeft(r3, 21); |
|
r1 ^= r2; |
|
r3 ^= r0; |
|
r2 = RotateLeft(r2, 32); |
|
} |
|
|
|
v0 = r0; v1 = r1; v2 = r2; v3 = r3; |
|
} |
|
|
|
protected static long RotateLeft(long x, int n) |
|
{ |
|
ulong ux = (ulong)x; |
|
ux = (ux << n) | (ux >> -n); |
|
return (long)ux; |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|