123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #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
- {
- /// <summary>
- /// ParallelHash - a hash designed to support the efficient hashing of very long strings, by taking advantage,
- /// of the parallelism available in modern processors with an optional XOF mode.
- /// <para>
- /// From NIST Special Publication 800-185 - SHA-3 Derived Functions:cSHAKE, KMAC, TupleHash and ParallelHash
- /// </para>
- /// </summary>
- public class ParallelHash
- : IXof, IDigest
- {
- private static readonly byte[] N_PARALLEL_HASH = Strings.ToByteArray("ParallelHash");
- private readonly CShakeDigest cshake;
- private readonly CShakeDigest compressor;
- private readonly int bitLength;
- private readonly int outputLength;
- private readonly int B;
- private readonly byte[] buffer;
- private readonly byte[] compressorBuffer;
- private bool firstOutput;
- private int nCount;
- private int bufOff;
- /**
- * Base constructor.
- *
- * @param bitLength bit length of the underlying SHAKE function, 128 or 256.
- * @param S the customization string - available for local use.
- * @param B the blocksize (in bytes) for hashing.
- */
- public ParallelHash(int bitLength, byte[] S, int B)
- : this(bitLength, S, B, bitLength * 2)
- {
- }
- public ParallelHash(int bitLength, byte[] S, int B, int outputSize)
- {
- this.cshake = new CShakeDigest(bitLength, N_PARALLEL_HASH, S);
- this.compressor = new CShakeDigest(bitLength, new byte[0], new byte[0]);
- this.bitLength = bitLength;
- this.B = B;
- this.outputLength = (outputSize + 7) / 8;
- this.buffer = new byte[B];
- this.compressorBuffer = new byte[bitLength * 2 / 8];
- Reset();
- }
- public ParallelHash(ParallelHash source)
- {
- this.cshake = new CShakeDigest(source.cshake);
- this.compressor = new CShakeDigest(source.compressor);
- this.bitLength = source.bitLength;
- this.B = source.B;
- this.outputLength = source.outputLength;
- this.buffer = Arrays.Clone(source.buffer);
- this.compressorBuffer = Arrays.Clone(source.compressorBuffer);
- }
- public virtual string AlgorithmName
- {
- get { return "ParallelHash" + cshake.AlgorithmName.Substring(6); }
- }
- public virtual int GetByteLength()
- {
- return cshake.GetByteLength();
- }
- public virtual int GetDigestSize()
- {
- return outputLength;
- }
- public virtual void Update(byte b)
- {
- buffer[bufOff++] = b;
- if (bufOff == buffer.Length)
- {
- Compress();
- }
- }
- public virtual void BlockUpdate(byte[] inBuf, int inOff, int len)
- {
- len = System.Math.Max(0, len);
- //
- // fill the current word
- //
- int i = 0;
- if (bufOff != 0)
- {
- while (i < len && bufOff != buffer.Length)
- {
- buffer[bufOff++] = inBuf[inOff + i++];
- }
- if (bufOff == buffer.Length)
- {
- Compress();
- }
- }
- if (i < len)
- {
- while (len - i >= B)
- {
- Compress(inBuf, inOff + i, B);
- i += B;
- }
- }
- while (i < len)
- {
- Update(inBuf[inOff + i++]);
- }
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
- public virtual void BlockUpdate(ReadOnlySpan<byte> input)
- {
- //
- // fill the current word
- //
- int i = 0;
- if (bufOff != 0)
- {
- while (i < input.Length && bufOff != buffer.Length)
- {
- buffer[bufOff++] = input[i++];
- }
- if (bufOff == buffer.Length)
- {
- Compress();
- }
- }
- if (i < input.Length)
- {
- while (input.Length - i >= B)
- {
- Compress(input, i, B);
- i += B;
- }
- }
- while (i < input.Length)
- {
- Update(input[i++]);
- }
- }
- #endif
- private void Compress()
- {
- Compress(buffer, 0, bufOff);
- bufOff = 0;
- }
- private void Compress(byte[] buf, int offSet, int len)
- {
- compressor.BlockUpdate(buf, offSet, len);
- compressor.OutputFinal(compressorBuffer, 0, compressorBuffer.Length);
- cshake.BlockUpdate(compressorBuffer, 0, compressorBuffer.Length);
- nCount++;
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
- private void Compress(ReadOnlySpan<byte> input, int pos, int len)
- {
- compressor.BlockUpdate(input.Slice(pos, len));
- compressor.OutputFinal(compressorBuffer, 0, compressorBuffer.Length);
- cshake.BlockUpdate(compressorBuffer, 0, compressorBuffer.Length);
- nCount++;
- }
- #endif
- private void WrapUp(int outputSize)
- {
- if (bufOff != 0)
- {
- Compress();
- }
- byte[] nOut = XofUtilities.RightEncode(nCount);
- byte[] encOut = XofUtilities.RightEncode(outputSize * 8);
- cshake.BlockUpdate(nOut, 0, nOut.Length);
- cshake.BlockUpdate(encOut, 0, encOut.Length);
- firstOutput = false;
- }
- public virtual int DoFinal(byte[] outBuf, int outOff)
- {
- if (firstOutput)
- {
- WrapUp(outputLength);
- }
- int rv = cshake.DoFinal(outBuf, outOff);
- Reset();
- return rv;
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
- public virtual int DoFinal(Span<byte> output)
- {
- if (firstOutput)
- {
- WrapUp(outputLength);
- }
- int rv = cshake.DoFinal(output);
- Reset();
- return rv;
- }
- #endif
- public virtual int OutputFinal(byte[] outBuf, int outOff, int outLen)
- {
- if (firstOutput)
- {
- WrapUp(outputLength);
- }
- int rv = cshake.OutputFinal(outBuf, outOff, outLen);
- Reset();
- return rv;
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
- public virtual int OutputFinal(Span<byte> output)
- {
- if (firstOutput)
- {
- WrapUp(outputLength);
- }
- int rv = cshake.OutputFinal(output);
- Reset();
- return rv;
- }
- #endif
- public virtual int Output(byte[] outBuf, int outOff, int outLen)
- {
- if (firstOutput)
- {
- WrapUp(0);
- }
- return cshake.Output(outBuf, outOff, outLen);
- }
- #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
- public virtual int Output(Span<byte> output)
- {
- if (firstOutput)
- {
- WrapUp(0);
- }
- return cshake.Output(output);
- }
- #endif
- public virtual void Reset()
- {
- cshake.Reset();
- Arrays.Clear(buffer);
- byte[] hdr = XofUtilities.LeftEncode(B);
- cshake.BlockUpdate(hdr, 0, hdr.Length);
- nCount = 0;
- bufOff = 0;
- firstOutput = true;
- }
- }
- }
- #pragma warning restore
- #endif
|