add all
This commit is contained in:
372
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/digests/Blake2xsDigest.cs
vendored
Normal file
372
Packages/com.tivadar.best.http/Runtime/3rdParty/BouncyCastle/crypto/digests/Blake2xsDigest.cs
vendored
Normal file
@@ -0,0 +1,372 @@
|
||||
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
#pragma warning disable
|
||||
using System;
|
||||
|
||||
using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
|
||||
|
||||
namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
|
||||
{
|
||||
/*
|
||||
The BLAKE2 cryptographic hash function was designed by Jean-
|
||||
Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian
|
||||
Winnerlein.
|
||||
|
||||
Reference Implementation and Description can be found at: https://blake2.net/blake2x.pdf
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implementation of the eXtendable Output Function (XOF) BLAKE2xs.
|
||||
* <p/>
|
||||
* BLAKE2xs offers a built-in keying mechanism to be used directly
|
||||
* for authentication ("Prefix-MAC") rather than a HMAC construction.
|
||||
* <p/>
|
||||
* BLAKE2xs offers a built-in support for a salt for randomized hashing
|
||||
* and a personal string for defining a unique hash function for each application.
|
||||
* <p/>
|
||||
* BLAKE2xs is optimized for 32-bit platforms and produces digests of any size
|
||||
* between 1 and 2^16-2 bytes. The length can also be unknown and then the maximum
|
||||
* length will be 2^32 blocks of 32 bytes.
|
||||
*/
|
||||
public sealed class Blake2xsDigest
|
||||
: IXof
|
||||
{
|
||||
/**
|
||||
* Magic number to indicate an unknown length of digest
|
||||
*/
|
||||
public const int UnknownDigestLength = 65535;
|
||||
|
||||
private const int DigestLength = 32;
|
||||
private const long MaxNumberBlocks = 1L << 32;
|
||||
|
||||
/**
|
||||
* Expected digest length for the xof. It can be unknown.
|
||||
*/
|
||||
private int digestLength;
|
||||
|
||||
/**
|
||||
* Root hash that will take the updates
|
||||
*/
|
||||
private Blake2sDigest hash;
|
||||
|
||||
/**
|
||||
* Digest of the root hash
|
||||
*/
|
||||
private byte[] h0 = null;
|
||||
|
||||
/**
|
||||
* Digest of each round of the XOF
|
||||
*/
|
||||
private byte[] buf = new byte[32];
|
||||
|
||||
/**
|
||||
* Current position for a round
|
||||
*/
|
||||
private int bufPos = 32;
|
||||
|
||||
/**
|
||||
* Overall position of the digest. It is useful when the length is known
|
||||
* in advance to get last block length.
|
||||
*/
|
||||
private int digestPos = 0;
|
||||
|
||||
/**
|
||||
* Keep track of the round number to detect the end of the digest after
|
||||
* 2^32 blocks of 32 bytes.
|
||||
*/
|
||||
private long blockPos = 0;
|
||||
|
||||
/**
|
||||
* Current node offset incremented by 1 every round.
|
||||
*/
|
||||
private long nodeOffset;
|
||||
|
||||
/**
|
||||
* BLAKE2xs for hashing with unknown digest length
|
||||
*/
|
||||
public Blake2xsDigest()
|
||||
: this(UnknownDigestLength)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* BLAKE2xs for hashing
|
||||
*
|
||||
* @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1
|
||||
*/
|
||||
public Blake2xsDigest(int digestBytes)
|
||||
: this(digestBytes, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* BLAKE2xs with key
|
||||
*
|
||||
* @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1
|
||||
* @param key A key up to 32 bytes or null
|
||||
*/
|
||||
public Blake2xsDigest(int digestBytes, byte[] key)
|
||||
: this(digestBytes, key, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* BLAKE2xs with key, salt and personalization
|
||||
*
|
||||
* @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1
|
||||
* @param key A key up to 32 bytes or null
|
||||
* @param salt 8 bytes or null
|
||||
* @param personalization 8 bytes or null
|
||||
*/
|
||||
public Blake2xsDigest(int digestBytes, byte[] key, byte[] salt, byte[] personalization)
|
||||
{
|
||||
if (digestBytes < 1 || digestBytes > UnknownDigestLength)
|
||||
throw new ArgumentException("BLAKE2xs digest length must be between 1 and 2^16-1");
|
||||
|
||||
digestLength = digestBytes;
|
||||
nodeOffset = ComputeNodeOffset();
|
||||
hash = new Blake2sDigest(DigestLength, key, salt, personalization, nodeOffset);
|
||||
}
|
||||
|
||||
public Blake2xsDigest(Blake2xsDigest digest)
|
||||
{
|
||||
digestLength = digest.digestLength;
|
||||
hash = new Blake2sDigest(digest.hash);
|
||||
h0 = Arrays.Clone(digest.h0);
|
||||
buf = Arrays.Clone(digest.buf);
|
||||
bufPos = digest.bufPos;
|
||||
digestPos = digest.digestPos;
|
||||
blockPos = digest.blockPos;
|
||||
nodeOffset = digest.nodeOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the algorithm name.
|
||||
*
|
||||
* @return the algorithm name
|
||||
*/
|
||||
public string AlgorithmName => "BLAKE2xs";
|
||||
|
||||
/**
|
||||
* Return the size in bytes of the digest produced by this message digest.
|
||||
*
|
||||
* @return the size in bytes of the digest produced by this message digest.
|
||||
*/
|
||||
public int GetDigestSize() => digestLength;
|
||||
|
||||
/**
|
||||
* Return the size in bytes of the internal buffer the digest applies its
|
||||
* compression function to.
|
||||
*
|
||||
* @return byte length of the digest's internal buffer.
|
||||
*/
|
||||
public int GetByteLength() => hash.GetByteLength();
|
||||
|
||||
/**
|
||||
* Return the maximum size in bytes the digest can produce when the length
|
||||
* is unknown
|
||||
*
|
||||
* @return byte length of the largest digest with unknown length
|
||||
*/
|
||||
public long GetUnknownMaxLength()
|
||||
{
|
||||
return MaxNumberBlocks * DigestLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the message digest with a single byte.
|
||||
*
|
||||
* @param in the input byte to be entered.
|
||||
*/
|
||||
public void Update(byte b)
|
||||
{
|
||||
hash.Update(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the message digest with a block of bytes.
|
||||
*
|
||||
* @param in the byte array containing the data.
|
||||
* @param inOff the offset into the byte array where the data starts.
|
||||
* @param len the length of the data.
|
||||
*/
|
||||
public void BlockUpdate(byte[] input, int inOff, int inLen)
|
||||
{
|
||||
hash.BlockUpdate(input, inOff, inLen);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public void BlockUpdate(ReadOnlySpan<byte> input)
|
||||
{
|
||||
hash.BlockUpdate(input);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Reset the digest back to its initial state. The key, the salt and the
|
||||
* personal string will remain for further computations.
|
||||
*/
|
||||
public void Reset()
|
||||
{
|
||||
hash.Reset();
|
||||
|
||||
h0 = null;
|
||||
bufPos = DigestLength;
|
||||
digestPos = 0;
|
||||
blockPos = 0;
|
||||
nodeOffset = ComputeNodeOffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the digest, producing the final digest value. The doFinal() call
|
||||
* leaves the digest reset. Key, salt and personal string remain.
|
||||
*
|
||||
* @param out the array the digest is to be copied into.
|
||||
* @param outOffset the offset into the out array the digest is to start at.
|
||||
*/
|
||||
public int DoFinal(byte[] output, int outOff)
|
||||
{
|
||||
return OutputFinal(output, outOff, digestLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the digest, producing the final digest value. The doFinal() call
|
||||
* leaves the digest reset. Key, salt, personal string remain.
|
||||
*
|
||||
* @param out output array to write the output bytes to.
|
||||
* @param outOff offset to start writing the bytes at.
|
||||
* @param outLen the number of output bytes requested.
|
||||
*/
|
||||
public int OutputFinal(byte[] output, int outOff, int outLen)
|
||||
{
|
||||
int ret = Output(output, outOff, outLen);
|
||||
|
||||
Reset();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start outputting the results of the final calculation for this digest. Unlike doFinal, this method
|
||||
* will continue producing output until the Xof is explicitly reset, or signals otherwise.
|
||||
*
|
||||
* @param out output array to write the output bytes to.
|
||||
* @param outOff offset to start writing the bytes at.
|
||||
* @param outLen the number of output bytes requested.
|
||||
* @return the number of bytes written
|
||||
*/
|
||||
public int Output(byte[] output, int outOff, int outLen)
|
||||
{
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
return Output(output.AsSpan(outOff, outLen));
|
||||
#else
|
||||
if (h0 == null)
|
||||
{
|
||||
h0 = new byte[hash.GetDigestSize()];
|
||||
hash.DoFinal(h0, 0);
|
||||
}
|
||||
|
||||
if (digestLength != UnknownDigestLength)
|
||||
{
|
||||
if (digestPos + outLen > digestLength)
|
||||
throw new ArgumentException("Output length is above the digest length");
|
||||
}
|
||||
else if (blockPos << 5 >= GetUnknownMaxLength())
|
||||
{
|
||||
throw new ArgumentException("Maximum length is 2^32 blocks of 32 bytes");
|
||||
}
|
||||
|
||||
for (int i = 0; i < outLen; i++)
|
||||
{
|
||||
if (bufPos >= DigestLength)
|
||||
{
|
||||
Blake2sDigest h = new Blake2sDigest(ComputeStepLength(), DigestLength, nodeOffset);
|
||||
h.BlockUpdate(h0, 0, h0.Length);
|
||||
|
||||
Arrays.Fill(buf, 0);
|
||||
h.DoFinal(buf, 0);
|
||||
bufPos = 0;
|
||||
nodeOffset++;
|
||||
blockPos++;
|
||||
}
|
||||
output[outOff + i] = buf[bufPos];
|
||||
bufPos++;
|
||||
digestPos++;
|
||||
}
|
||||
|
||||
return outLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
|
||||
public int DoFinal(Span<byte> output)
|
||||
{
|
||||
return OutputFinal(output[..digestLength]);
|
||||
}
|
||||
|
||||
public int OutputFinal(Span<byte> output)
|
||||
{
|
||||
int ret = Output(output);
|
||||
|
||||
Reset();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public int Output(Span<byte> output)
|
||||
{
|
||||
int outLen = output.Length;
|
||||
if (h0 == null)
|
||||
{
|
||||
h0 = new byte[hash.GetDigestSize()];
|
||||
hash.DoFinal(h0);
|
||||
}
|
||||
|
||||
if (digestLength != UnknownDigestLength)
|
||||
{
|
||||
if (digestPos + outLen > digestLength)
|
||||
throw new ArgumentException("Output length is above the digest length");
|
||||
}
|
||||
else if (blockPos << 5 >= GetUnknownMaxLength())
|
||||
{
|
||||
throw new ArgumentException("Maximum length is 2^32 blocks of 32 bytes");
|
||||
}
|
||||
|
||||
for (int i = 0; i < outLen; i++)
|
||||
{
|
||||
if (bufPos >= DigestLength)
|
||||
{
|
||||
Blake2sDigest h = new Blake2sDigest(ComputeStepLength(), DigestLength, nodeOffset);
|
||||
h.BlockUpdate(h0);
|
||||
|
||||
Arrays.Fill(buf, 0);
|
||||
h.DoFinal(buf);
|
||||
bufPos = 0;
|
||||
nodeOffset++;
|
||||
blockPos++;
|
||||
}
|
||||
output[i] = buf[bufPos];
|
||||
bufPos++;
|
||||
digestPos++;
|
||||
}
|
||||
|
||||
return outLen;
|
||||
}
|
||||
#endif
|
||||
|
||||
// get the next round length. If the length is unknown, the digest length is always the maximum.
|
||||
private int ComputeStepLength()
|
||||
{
|
||||
if (digestLength == UnknownDigestLength)
|
||||
return DigestLength;
|
||||
|
||||
return System.Math.Min(DigestLength, digestLength - digestPos);
|
||||
}
|
||||
|
||||
private long ComputeNodeOffset()
|
||||
{
|
||||
return digestLength * 0x100000000L;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore
|
||||
#endif
|
||||
Reference in New Issue
Block a user