diff --git a/crypto/src/crypto/IDigest.cs b/crypto/src/crypto/IDigest.cs
index 6769dcc42..2ba1705c7 100644
--- a/crypto/src/crypto/IDigest.cs
+++ b/crypto/src/crypto/IDigest.cs
@@ -2,60 +2,52 @@ using System;
namespace Org.BouncyCastle.Crypto
{
- /**
- * interface that a message digest conforms to.
- */
+ /// <remarks>Base interface for a message digest.</remarks>
public interface IDigest
{
- /**
- * return the algorithm name
- *
- * @return the algorithm name
- */
+ /// <summary>the algorithm name</summary>
string AlgorithmName { get; }
- /**
- * 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.
- */
- int GetDigestSize();
-
- /**
- * return the size, in bytes, of the internal buffer used by this digest.
- *
- * @return the size, in bytes, of the internal buffer used by this digest.
- */
- int GetByteLength();
-
- /**
- * update the message digest with a single byte.
- *
- * @param inByte the input byte to be entered.
- */
+ /// <summary>Return the size, in bytes, of the digest produced by this message digest.</summary>
+ /// <returns>the size, in bytes, of the digest produced by this message digest.</returns>
+ int GetDigestSize();
+
+ /// <summary>Return the size, in bytes, of the internal buffer used by this digest.</summary>
+ /// <returns>the size, in bytes, of the internal buffer used by this digest.</returns>
+ int GetByteLength();
+
+ /// <summary>Update the message digest with a single byte.</summary>
+ /// <param name="input">the input byte to be entered.</param>
void Update(byte input);
- /**
- * update the message digest with a block of bytes.
- *
- * @param input 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.
- */
- void BlockUpdate(byte[] input, int inOff, int length);
-
- /**
- * Close the digest, producing the final digest value. The doFinal
- * call leaves the digest reset.
- *
- * @param output the array the digest is to be copied into.
- * @param outOff the offset into the out array the digest is to start at.
- */
+ /// <summary>Update the message digest with a block of bytes.</summary>
+ /// <param name="input">the byte array containing the data.</param>
+ /// <param name="inOff">the offset into the byte array where the data starts.</param>
+ /// <param name="inLen">the length of the data.</param>
+ void BlockUpdate(byte[] input, int inOff, int inLen);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// <summary>Update the message digest with a span of bytes.</summary>
+ /// <param name="input">the span containing the data.</param>
+ void BlockUpdate(ReadOnlySpan<byte> input);
+#endif
+
+ /// <summary>Close the digest, producing the final digest value.</summary>
+ /// <remarks>This call leaves the digest reset.</remarks>
+ /// <param name="output">the byte array the digest is to be copied into.</param>
+ /// <param name="outOff">the offset into the byte array the digest is to start at.</param>
+ /// <returns>the number of bytes written</returns>
int DoFinal(byte[] output, int outOff);
- /**
- * reset the digest back to it's initial state.
- */
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// <summary>Close the digest, producing the final digest value.</summary>
+ /// <remarks>This call leaves the digest reset.</remarks>
+ /// <param name="output">the span the digest is to be copied into.</param>
+ /// <returns>the number of bytes written</returns>
+ int DoFinal(Span<byte> output);
+#endif
+
+ /// <summary>Reset the digest back to its initial state.</summary>
void Reset();
}
}
diff --git a/crypto/src/crypto/IXof.cs b/crypto/src/crypto/IXof.cs
index f76304d48..8cddb2870 100644
--- a/crypto/src/crypto/IXof.cs
+++ b/crypto/src/crypto/IXof.cs
@@ -4,13 +4,13 @@ namespace Org.BouncyCastle.Crypto
{
/// <remarks>
/// With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes.
- /// This interface provides the extra method required to support variable output on a digest implementation.
+ /// This interface provides the extra methods required to support variable output on a digest implementation.
/// </remarks>
public interface IXof
: IDigest
{
/// <summary>
- /// Output the results of the final calculation for this digest to outLen number of bytes.
+ /// Output the results of the final calculation for this XOF to outLen number of bytes.
/// </summary>
/// <param name="output">output array to write the output bytes to.</param>
/// <param name="outOff">offset to start writing the bytes at.</param>
@@ -18,14 +18,33 @@ namespace Org.BouncyCastle.Crypto
/// <returns>the number of bytes written</returns>
int DoFinal(byte[] output, int outOff, int outLen);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>
- /// 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.
+ /// Output the results of the final calculation for this XOF to fill the output span.
+ /// </summary>
+ /// <param name="output">span to fill with the output bytes.</param>
+ /// <returns>the number of bytes written</returns>
+ int OutputFinal(Span<byte> output);
+#endif
+
+ /// <summary>
+ /// Start outputting the results of the final calculation for this XOF. Unlike DoFinal, this method
+ /// will continue producing output until the XOF is explicitly reset, or signals otherwise.
/// </summary>
/// <param name="output">output array to write the output bytes to.</param>
/// <param name="outOff">offset to start writing the bytes at.</param>
/// <param name="outLen">the number of output bytes requested.</param>
/// <returns>the number of bytes written</returns>
int DoOutput(byte[] output, int outOff, int outLen);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// <summary>
+ /// Start outputting the results of the final calculation for this XOF. Unlike OutputFinal, this method
+ /// will continue producing output until the XOF is explicitly reset, or signals otherwise.
+ /// </summary>
+ /// <param name="output">span to fill with the output bytes.</param>
+ /// <returns>the number of bytes written</returns>
+ int Output(Span<byte> output);
+#endif
}
}
diff --git a/crypto/src/crypto/digests/Blake2bDigest.cs b/crypto/src/crypto/digests/Blake2bDigest.cs
index 1ac9cfa35..ec80a3355 100644
--- a/crypto/src/crypto/digests/Blake2bDigest.cs
+++ b/crypto/src/crypto/digests/Blake2bDigest.cs
@@ -357,11 +357,63 @@ namespace Org.BouncyCastle.Crypto.Digests
}
// fill the buffer with left bytes, this might be a full block
- Array.Copy(message, messagePos, buffer, 0, offset + len
- - messagePos);
+ Array.Copy(message, messagePos, buffer, 0, offset + len - messagePos);
bufferPos += offset + len - messagePos;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ if (input.IsEmpty)
+ return;
+
+ int remainingLength = 0; // left bytes of buffer
+
+ if (bufferPos != 0)
+ { // commenced, incomplete buffer
+
+ // complete the buffer:
+ remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
+ if (remainingLength < input.Length)
+ { // full buffer + at least 1 byte
+ input[..remainingLength].CopyTo(buffer.AsSpan(bufferPos));
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ { // if message > 2^64
+ t1++;
+ }
+ Compress(buffer, 0);
+ bufferPos = 0;
+ Array.Clear(buffer, 0, buffer.Length);// clear buffer
+ }
+ else
+ {
+ input.CopyTo(buffer.AsSpan(bufferPos));
+ bufferPos += input.Length;
+ return;
+ }
+ }
+
+ // process blocks except last block (also if last block is full)
+ int messagePos;
+ int blockWiseLastPos = input.Length - BLOCK_LENGTH_BYTES;
+ for (messagePos = remainingLength; messagePos < blockWiseLastPos; messagePos += BLOCK_LENGTH_BYTES)
+ { // block wise 128 bytes
+ // without buffer:
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ {
+ t1++;
+ }
+ Compress(input[messagePos..]);
+ }
+
+ // fill the buffer with left bytes, this might be a full block
+ input[messagePos..].CopyTo(buffer.AsSpan());
+ bufferPos += input.Length - messagePos;
+ }
+#endif
+
/**
* close the digest, producing the final digest value. The doFinal
* call leaves the digest reset.
@@ -382,19 +434,42 @@ namespace Org.BouncyCastle.Crypto.Digests
Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
Array.Clear(internalState, 0, internalState.Length);
- byte[] bytes = new byte[8];
- for (int i = 0; i < chainValue.Length && (i * 8 < digestLength); i++)
+ int full = digestLength >> 3, partial = digestLength & 7;
+ Pack.UInt64_To_LE(chainValue, 0, full, output, outOffset);
+ if (partial > 0)
+ {
+ byte[] bytes = new byte[8];
+ Pack.UInt64_To_LE(chainValue[full], bytes, 0);
+ Array.Copy(bytes, 0, output, outOffset + digestLength - partial, partial);
+ }
+
+ Array.Clear(chainValue, 0, chainValue.Length);
+
+ Reset();
+
+ return digestLength;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ f0 = 0xFFFFFFFFFFFFFFFFUL;
+ t0 += (ulong)bufferPos;
+ if (bufferPos > 0 && t0 == 0)
{
- Pack.UInt64_To_LE(chainValue[i], bytes, 0);
+ t1++;
+ }
+ Compress(buffer, 0);
+ Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
+ Array.Clear(internalState, 0, internalState.Length);
- if (i * 8 < digestLength - 8)
- {
- Array.Copy(bytes, 0, output, outOffset + i * 8, 8);
- }
- else
- {
- Array.Copy(bytes, 0, output, outOffset + i * 8, digestLength - (i * 8));
- }
+ int full = digestLength >> 3, partial = digestLength & 7;
+ Pack.UInt64_To_LE(chainValue.AsSpan(0, full), output);
+ if (partial > 0)
+ {
+ Span<byte> bytes = stackalloc byte[8];
+ Pack.UInt64_To_LE(chainValue[full], bytes);
+ bytes[..partial].CopyTo(output[(digestLength - partial)..]);
}
Array.Clear(chainValue, 0, chainValue.Length);
@@ -403,6 +478,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return digestLength;
}
+#endif
/**
* Reset the digest back to it's initial state.
@@ -453,6 +529,36 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void Compress(ReadOnlySpan<byte> message)
+ {
+ InitializeInternalState();
+
+ Span<ulong> m = stackalloc ulong[16];
+ Pack.LE_To_UInt64(message, m);
+
+ for (int round = 0; round < ROUNDS; round++)
+ {
+ // G apply to columns of internalState:m[blake2b_sigma[round][2 * blockPos]] /+1
+ G(m[blake2b_sigma[round, 0]], m[blake2b_sigma[round, 1]], 0, 4, 8, 12);
+ G(m[blake2b_sigma[round, 2]], m[blake2b_sigma[round, 3]], 1, 5, 9, 13);
+ G(m[blake2b_sigma[round, 4]], m[blake2b_sigma[round, 5]], 2, 6, 10, 14);
+ G(m[blake2b_sigma[round, 6]], m[blake2b_sigma[round, 7]], 3, 7, 11, 15);
+ // G apply to diagonals of internalState:
+ G(m[blake2b_sigma[round, 8]], m[blake2b_sigma[round, 9]], 0, 5, 10, 15);
+ G(m[blake2b_sigma[round, 10]], m[blake2b_sigma[round, 11]], 1, 6, 11, 12);
+ G(m[blake2b_sigma[round, 12]], m[blake2b_sigma[round, 13]], 2, 7, 8, 13);
+ G(m[blake2b_sigma[round, 14]], m[blake2b_sigma[round, 15]], 3, 4, 9, 14);
+ }
+
+ // update chain values:
+ for (int offset = 0; offset < chainValue.Length; offset++)
+ {
+ chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
+ }
+ }
+#endif
+
private void G(ulong m1, ulong m2, int posA, int posB, int posC, int posD)
{
internalState[posA] = internalState[posA] + internalState[posB] + m1;
diff --git a/crypto/src/crypto/digests/Blake2sDigest.cs b/crypto/src/crypto/digests/Blake2sDigest.cs
index f50419126..187808aa0 100644
--- a/crypto/src/crypto/digests/Blake2sDigest.cs
+++ b/crypto/src/crypto/digests/Blake2sDigest.cs
@@ -381,6 +381,61 @@ namespace Org.BouncyCastle.Crypto.Digests
bufferPos += offset + len - messagePos;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ if (input.IsEmpty)
+ return;
+
+ int remainingLength = 0; // left bytes of buffer
+
+ if (bufferPos != 0)
+ { // commenced, incomplete buffer
+
+ // complete the buffer:
+ remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
+ if (remainingLength < input.Length)
+ { // full buffer + at least 1 byte
+ input[..remainingLength].CopyTo(buffer.AsSpan(bufferPos));
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ { // if message > 2^32
+ t1++;
+ }
+ Compress(buffer, 0);
+ bufferPos = 0;
+ Array.Clear(buffer, 0, buffer.Length);// clear buffer
+ }
+ else
+ {
+ input.CopyTo(buffer.AsSpan(bufferPos));
+ bufferPos += input.Length;
+ return;
+ }
+ }
+
+ // process blocks except last block (also if last block is full)
+ int messagePos;
+ int blockWiseLastPos = input.Length - BLOCK_LENGTH_BYTES;
+ for (messagePos = remainingLength;
+ messagePos < blockWiseLastPos;
+ messagePos += BLOCK_LENGTH_BYTES)
+ { // block wise 64 bytes
+ // without buffer:
+ t0 += BLOCK_LENGTH_BYTES;
+ if (t0 == 0)
+ {
+ t1++;
+ }
+ Compress(input[messagePos..]);
+ }
+
+ // fill the buffer with left bytes, this might be a full block
+ input[messagePos..].CopyTo(buffer.AsSpan());
+ bufferPos += input.Length - messagePos;
+ }
+#endif
+
/**
* Close the digest, producing the final digest value. The doFinal() call
* leaves the digest reset. Key, salt and personal string remain.
@@ -402,19 +457,44 @@ namespace Org.BouncyCastle.Crypto.Digests
Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
Array.Clear(internalState, 0, internalState.Length);
- byte[] bytes = new byte[4];
- for (int i = 0; i < chainValue.Length && (i * 4 < digestLength); i++)
+ int full = digestLength >> 2, partial = digestLength & 3;
+ Pack.UInt32_To_LE(chainValue, 0, full, output, outOffset);
+ if (partial > 0)
+ {
+ byte[] bytes = new byte[4];
+ Pack.UInt32_To_LE(chainValue[full], bytes, 0);
+ Array.Copy(bytes, 0, output, outOffset + digestLength - partial, partial);
+ }
+
+ Array.Clear(chainValue, 0, chainValue.Length);
+
+ Reset();
+
+ return digestLength;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ f0 = 0xFFFFFFFFU;
+ t0 += (uint)bufferPos;
+ // bufferPos may be < 64, so (t0 == 0) does not work
+ // for 2^32 < message length > 2^32 - 63
+ if ((t0 < 0) && (bufferPos > -t0))
{
- Pack.UInt32_To_LE(chainValue[i], bytes, 0);
+ t1++;
+ }
+ Compress(buffer, 0);
+ Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
+ Array.Clear(internalState, 0, internalState.Length);
- if (i * 4 < digestLength - 4)
- {
- Array.Copy(bytes, 0, output, outOffset + i * 4, 4);
- }
- else
- {
- Array.Copy(bytes, 0, output, outOffset + i * 4, digestLength - (i * 4));
- }
+ int full = digestLength >> 2, partial = digestLength & 3;
+ Pack.UInt32_To_LE(chainValue.AsSpan(0, full), output);
+ if (partial > 0)
+ {
+ Span<byte> bytes = stackalloc byte[4];
+ Pack.UInt32_To_LE(chainValue[full], bytes);
+ bytes[..partial].CopyTo(output[(digestLength - partial)..]);
}
Array.Clear(chainValue, 0, chainValue.Length);
@@ -423,6 +503,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return digestLength;
}
+#endif
/**
* Reset the digest back to its initial state. The key, the salt and the
@@ -453,9 +534,7 @@ namespace Org.BouncyCastle.Crypto.Digests
for (int round = 0; round < ROUNDS; round++)
{
-
- // G apply to columns of internalState:m[blake2s_sigma[round][2 *
- // blockPos]] /+1
+ // G apply to columns of internalState: m[blake2s_sigma[round][2 * blockPos]] /+1
G(m[blake2s_sigma[round,0]], m[blake2s_sigma[round,1]], 0, 4, 8, 12);
G(m[blake2s_sigma[round,2]], m[blake2s_sigma[round,3]], 1, 5, 9, 13);
G(m[blake2s_sigma[round,4]], m[blake2s_sigma[round,5]], 2, 6, 10, 14);
@@ -474,6 +553,36 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void Compress(ReadOnlySpan<byte> message)
+ {
+ InitializeInternalState();
+
+ Span<uint> m = stackalloc uint[16];
+ Pack.LE_To_UInt32(message, m);
+
+ for (int round = 0; round < ROUNDS; round++)
+ {
+ // G apply to columns of internalState: m[blake2s_sigma[round][2 * blockPos]] /+1
+ G(m[blake2s_sigma[round, 0]], m[blake2s_sigma[round, 1]], 0, 4, 8, 12);
+ G(m[blake2s_sigma[round, 2]], m[blake2s_sigma[round, 3]], 1, 5, 9, 13);
+ G(m[blake2s_sigma[round, 4]], m[blake2s_sigma[round, 5]], 2, 6, 10, 14);
+ G(m[blake2s_sigma[round, 6]], m[blake2s_sigma[round, 7]], 3, 7, 11, 15);
+ // G apply to diagonals of internalState:
+ G(m[blake2s_sigma[round, 8]], m[blake2s_sigma[round, 9]], 0, 5, 10, 15);
+ G(m[blake2s_sigma[round, 10]], m[blake2s_sigma[round, 11]], 1, 6, 11, 12);
+ G(m[blake2s_sigma[round, 12]], m[blake2s_sigma[round, 13]], 2, 7, 8, 13);
+ G(m[blake2s_sigma[round, 14]], m[blake2s_sigma[round, 15]], 3, 4, 9, 14);
+ }
+
+ // update chain values:
+ for (int offset = 0; offset < chainValue.Length; offset++)
+ {
+ chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
+ }
+ }
+#endif
+
private void G(uint m1, uint m2, int posA, int posB, int posC, int posD)
{
internalState[posA] = internalState[posA] + internalState[posB] + m1;
diff --git a/crypto/src/crypto/digests/CSHAKEDigest.cs b/crypto/src/crypto/digests/CSHAKEDigest.cs
index c3b0b7068..fc37b865c 100644
--- a/crypto/src/crypto/digests/CSHAKEDigest.cs
+++ b/crypto/src/crypto/digests/CSHAKEDigest.cs
@@ -95,6 +95,25 @@ namespace Org.BouncyCastle.Crypto.Digests
return outLen;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int Output(Span<byte> output)
+ {
+ if (diff == null)
+ {
+ return base.Output(output);
+ }
+
+ if (!squeezing)
+ {
+ AbsorbBits(0x00, 2);
+ }
+
+ Squeeze(output);
+
+ return output.Length;
+ }
+#endif
+
public override void Reset()
{
base.Reset();
diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs
index b2d90799d..901e549be 100644
--- a/crypto/src/crypto/digests/DSTU7564Digest.cs
+++ b/crypto/src/crypto/digests/DSTU7564Digest.cs
@@ -1,11 +1,7 @@
using System;
-using Org.BouncyCastle.Crypto.Engines;
-using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
-
using Org.BouncyCastle.Utilities;
-using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Crypto.Digests
{
@@ -132,25 +128,103 @@ namespace Org.BouncyCastle.Crypto.Digests
--length;
}
- if (length > 0)
+ while (length >= blockSize)
+ {
+ ProcessBlock(input, inOff);
+ inOff += blockSize;
+ length -= blockSize;
+ ++inputBlocks;
+ }
+
+ while (length > 0)
+ {
+ Update(input[inOff++]);
+ --length;
+ }
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ while (bufOff != 0 && input.Length > 0)
{
- while (length >= blockSize)
+ Update(input[0]);
+ input = input[1..];
+ }
+
+ while (input.Length >= blockSize)
+ {
+ ProcessBlock(input);
+ input = input[blockSize..];
+ ++inputBlocks;
+ }
+
+ while (input.Length > 0)
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+ }
+#endif
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ // Apply padding: terminator byte and 96-bit length field
+ {
+ int inputBytes = bufOff;
+ buf[bufOff++] = (byte)0x80;
+
+ int lenPos = blockSize - 12;
+ if (bufOff > lenPos)
{
- ProcessBlock(input, inOff);
- inOff += blockSize;
- length -= blockSize;
- ++inputBlocks;
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ bufOff = 0;
+ ProcessBlock(buf, 0);
}
- while (length > 0)
+ while (bufOff < lenPos)
{
- Update(input[inOff++]);
- --length;
+ buf[bufOff++] = 0;
+ }
+
+ ulong c = ((inputBlocks & 0xFFFFFFFFUL) * (ulong)blockSize + (uint)inputBytes) << 3;
+ Pack.UInt32_To_LE((uint)c, buf, bufOff);
+ bufOff += 4;
+ c >>= 32;
+ c += ((inputBlocks >> 32) * (ulong)blockSize) << 3;
+ Pack.UInt64_To_LE(c, buf, bufOff);
+ //bufOff += 8;
+ ProcessBlock(buf, 0);
+ }
+
+ {
+ Array.Copy(state, 0, tempState1, 0, columns);
+
+ P(tempState1);
+
+ for (int col = 0; col < columns; ++col)
+ {
+ state[col] ^= tempState1[col];
}
}
+
+ int neededColumns = hashSize / 8;
+ for (int col = columns - neededColumns; col < columns; ++col)
+ {
+ Pack.UInt64_To_LE(state[col], output, outOff);
+ outOff += 8;
+ }
+
+ Reset();
+
+ return hashSize;
}
- public virtual int DoFinal(byte[] output, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
{
// Apply padding: terminator byte and 96-bit length field
{
@@ -179,7 +253,7 @@ namespace Org.BouncyCastle.Crypto.Digests
c >>= 32;
c += ((inputBlocks >> 32) * (ulong)blockSize) << 3;
Pack.UInt64_To_LE(c, buf, bufOff);
- // bufOff += 8;
+ //bufOff += 8;
ProcessBlock(buf, 0);
}
@@ -197,14 +271,15 @@ namespace Org.BouncyCastle.Crypto.Digests
int neededColumns = hashSize / 8;
for (int col = columns - neededColumns; col < columns; ++col)
{
- Pack.UInt64_To_LE(state[col], output, outOff);
- outOff += 8;
+ Pack.UInt64_To_LE(state[col], output);
+ output = output[8..];
}
Reset();
return hashSize;
}
+#endif
public virtual void Reset()
{
@@ -236,6 +311,28 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected virtual void ProcessBlock(ReadOnlySpan<byte> input)
+ {
+ for (int col = 0; col < columns; ++col)
+ {
+ ulong word = Pack.LE_To_UInt64(input);
+ input = input[8..];
+
+ tempState1[col] = state[col] ^ word;
+ tempState2[col] = word;
+ }
+
+ P(tempState1);
+ Q(tempState2);
+
+ for (int col = 0; col < columns; ++col)
+ {
+ state[col] ^= tempState1[col] ^ tempState2[col];
+ }
+ }
+#endif
+
private void P(ulong[] s)
{
for (int round = 0; round < rounds; ++round)
diff --git a/crypto/src/crypto/digests/GOST3411Digest.cs b/crypto/src/crypto/digests/GOST3411Digest.cs
index 123751baa..dc1d376c3 100644
--- a/crypto/src/crypto/digests/GOST3411Digest.cs
+++ b/crypto/src/crypto/digests/GOST3411Digest.cs
@@ -91,10 +91,7 @@ namespace Org.BouncyCastle.Crypto.Digests
byteCount++;
}
- public void BlockUpdate(
- byte[] input,
- int inOff,
- int length)
+ public void BlockUpdate(byte[] input, int inOff, int length)
{
while ((xBufOff != 0) && (length > 0))
{
@@ -123,6 +120,34 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ while ((xBufOff != 0) && (input.Length > 0))
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+
+ while (input.Length >= xBuf.Length)
+ {
+ input[..xBuf.Length].CopyTo(xBuf.AsSpan());
+
+ sumByteArray(xBuf); // calc sum M
+ processBlock(xBuf, 0);
+ input = input[xBuf.Length..];
+ byteCount += (uint)xBuf.Length;
+ }
+
+ // load in the remainder.
+ while (input.Length > 0)
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+ }
+#endif
+
// (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8
private byte[] K = new byte[32];
@@ -234,7 +259,7 @@ namespace Org.BouncyCastle.Crypto.Digests
Array.Copy(S, 0, H, 0, H.Length);
}
- private void finish()
+ private void Finish()
{
ulong bitCount = byteCount * 8;
Pack.UInt64_To_LE(bitCount, L);
@@ -248,11 +273,9 @@ namespace Org.BouncyCastle.Crypto.Digests
processBlock(Sum, 0);
}
- public int DoFinal(
- byte[] output,
- int outOff)
+ public int DoFinal(byte[] output, int outOff)
{
- finish();
+ Finish();
H.CopyTo(output, outOff);
@@ -261,6 +284,19 @@ namespace Org.BouncyCastle.Crypto.Digests
return DIGEST_LENGTH;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ H.CopyTo(output);
+
+ Reset();
+
+ return DIGEST_LENGTH;
+ }
+#endif
+
/**
* reset the chaining variables to the IV values.
*/
diff --git a/crypto/src/crypto/digests/GOST3411_2012Digest.cs b/crypto/src/crypto/digests/GOST3411_2012Digest.cs
index 68cb6c035..259f4bcae 100644
--- a/crypto/src/crypto/digests/GOST3411_2012Digest.cs
+++ b/crypto/src/crypto/digests/GOST3411_2012Digest.cs
@@ -1,10 +1,11 @@
using System;
-using Org.BouncyCastle.Crypto;
+
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Digests
{
- public abstract class Gost3411_2012Digest:IDigest,IMemoable
+ public abstract class Gost3411_2012Digest
+ : IDigest, IMemoable
{
private readonly byte[] IV = new byte[64];
private readonly byte[] N = new byte[64];
@@ -21,8 +22,8 @@ namespace Org.BouncyCastle.Crypto.Digests
protected Gost3411_2012Digest(byte[] IV)
{
- System.Array.Copy(IV,this.IV,64);
- System.Array.Copy(IV, h, 64);
+ Array.Copy(IV,this.IV,64);
+ Array.Copy(IV, h, 64);
}
public abstract string AlgorithmName { get; }
@@ -43,7 +44,7 @@ namespace Org.BouncyCastle.Crypto.Digests
if (bOff != 64)
{
- System.Array.Copy(block, bOff, m, 64 - lenM, lenM);
+ Array.Copy(block, bOff, m, 64 - lenM, lenM);
}
g_N(h, N, m);
@@ -60,6 +61,39 @@ namespace Org.BouncyCastle.Crypto.Digests
return 64;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ int lenM = 64 - bOff;
+
+ // At this point it is certain that lenM is smaller than 64
+ for (int i = 0; i != 64 - lenM; i++)
+ {
+ m[i] = 0;
+ }
+
+ m[63 - lenM] = 1;
+
+ if (bOff != 64)
+ {
+ Array.Copy(block, bOff, m, 64 - lenM, lenM);
+ }
+
+ g_N(h, N, m);
+ addMod512(N, lenM * 8);
+ addMod512(Sigma, m);
+ g_N(h, Zero, N);
+ g_N(h, Zero, Sigma);
+
+ reverse(h, tmp);
+
+ tmp.CopyTo(output);
+
+ Reset();
+ return 64;
+ }
+#endif
+
public int GetByteLength()
{
return 64;
@@ -73,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Digests
bOff = 64;
Arrays.Fill(N, (byte)0);
Arrays.Fill(Sigma, (byte)0);
- System.Array.Copy(IV, 0, h, 0, 64);
+ Array.Copy(IV, 0, h, 0, 64);
Arrays.Fill(block, (byte)0);
}
@@ -81,14 +115,14 @@ namespace Org.BouncyCastle.Crypto.Digests
{
Gost3411_2012Digest o = (Gost3411_2012Digest)other;
- System.Array.Copy(o.IV, 0, this.IV, 0, 64);
- System.Array.Copy(o.N, 0, this.N, 0, 64);
- System.Array.Copy(o.Sigma, 0, this.Sigma, 0, 64);
- System.Array.Copy(o.Ki, 0, this.Ki, 0, 64);
- System.Array.Copy(o.m, 0, this.m, 0, 64);
- System.Array.Copy(o.h, 0, this.h, 0, 64);
+ Array.Copy(o.IV, 0, this.IV, 0, 64);
+ Array.Copy(o.N, 0, this.N, 0, 64);
+ Array.Copy(o.Sigma, 0, this.Sigma, 0, 64);
+ Array.Copy(o.Ki, 0, this.Ki, 0, 64);
+ Array.Copy(o.m, 0, this.m, 0, 64);
+ Array.Copy(o.h, 0, this.h, 0, 64);
- System.Array.Copy(o.block, 0, this.block, 0, 64);
+ Array.Copy(o.block, 0, this.block, 0, 64);
this.bOff = o.bOff;
}
@@ -104,7 +138,6 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
-
public void BlockUpdate(byte[] input, int inOff, int len)
{
while (bOff != 64 && len > 0)
@@ -114,7 +147,7 @@ namespace Org.BouncyCastle.Crypto.Digests
}
while (len >= 64)
{
- System.Array.Copy(input, inOff, tmp, 0, 64);
+ Array.Copy(input, inOff, tmp, 0, 64);
reverse(tmp, block);
g_N(h, N, block);
addMod512(N, 512);
@@ -130,8 +163,31 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
-
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ while (bOff != 64 && input.Length > 0)
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+ while (input.Length >= 64)
+ {
+ input[..64].CopyTo(tmp.AsSpan());
+ reverse(tmp, block);
+ g_N(h, N, block);
+ addMod512(N, 512);
+ addMod512(Sigma, block);
+ input = input[64..];
+ }
+ while (input.Length > 0)
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+ }
+#endif
private void F(byte[] V)
{
@@ -317,7 +373,7 @@ namespace Org.BouncyCastle.Crypto.Digests
private void E(byte[] K, byte[] m)
{
- System.Array.Copy(K, 0, Ki, 0, 64);
+ Array.Copy(K, 0, Ki, 0, 64);
xor512(K, m);
F(K);
for (int i = 0; i < 11; ++i)
@@ -334,7 +390,7 @@ namespace Org.BouncyCastle.Crypto.Digests
private void g_N(byte[] h, byte[] N, byte[] m)
{
- System.Array.Copy(h, 0, tmp, 0, 64);
+ Array.Copy(h, 0, tmp, 0, 64);
xor512(h, N);
F(h);
diff --git a/crypto/src/crypto/digests/GOST3411_2012_256Digest.cs b/crypto/src/crypto/digests/GOST3411_2012_256Digest.cs
index 77cf6c50f..47877b2b5 100644
--- a/crypto/src/crypto/digests/GOST3411_2012_256Digest.cs
+++ b/crypto/src/crypto/digests/GOST3411_2012_256Digest.cs
@@ -46,6 +46,18 @@ namespace Org.BouncyCastle.Crypto.Digests
return 32;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Span<byte> result = stackalloc byte[64];
+ base.DoFinal(result);
+
+ result[32..].CopyTo(output);
+
+ return 32;
+ }
+#endif
+
public override IMemoable Copy()
{
return new Gost3411_2012_256Digest(this);
diff --git a/crypto/src/crypto/digests/GeneralDigest.cs b/crypto/src/crypto/digests/GeneralDigest.cs
index c38b35fd3..02bad2cfb 100644
--- a/crypto/src/crypto/digests/GeneralDigest.cs
+++ b/crypto/src/crypto/digests/GeneralDigest.cs
@@ -95,6 +95,50 @@ namespace Org.BouncyCastle.Crypto.Digests
byteCount += length;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ int length = input.Length;
+
+ //
+ // fill the current word
+ //
+ int i = 0;
+ if (xBufOff != 0)
+ {
+ while (i < length)
+ {
+ xBuf[xBufOff++] = input[i++];
+ if (xBufOff == 4)
+ {
+ ProcessWord(xBuf, 0);
+ xBufOff = 0;
+ break;
+ }
+ }
+ }
+
+ //
+ // process whole words.
+ //
+ int limit = length - 3;
+ for (; i < limit; i += 4)
+ {
+ ProcessWord(input.Slice(i, 4));
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (i < length)
+ {
+ xBuf[xBufOff++] = input[i++];
+ }
+
+ byteCount += length;
+ }
+#endif
+
public void Finish()
{
long bitLength = (byteCount << 3);
@@ -122,6 +166,9 @@ namespace Org.BouncyCastle.Crypto.Digests
}
internal abstract void ProcessWord(byte[] input, int inOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal abstract void ProcessWord(ReadOnlySpan<byte> word);
+#endif
internal abstract void ProcessLength(long bitLength);
internal abstract void ProcessBlock();
public abstract string AlgorithmName { get; }
@@ -129,5 +176,8 @@ namespace Org.BouncyCastle.Crypto.Digests
public abstract int DoFinal(byte[] output, int outOff);
public abstract IMemoable Copy();
public abstract void Reset(IMemoable t);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public abstract int DoFinal(Span<byte> output);
+#endif
}
}
diff --git a/crypto/src/crypto/digests/Haraka256Digest.cs b/crypto/src/crypto/digests/Haraka256Digest.cs
index f7af4bf69..27aea9b29 100644
--- a/crypto/src/crypto/digests/Haraka256Digest.cs
+++ b/crypto/src/crypto/digests/Haraka256Digest.cs
@@ -93,7 +93,58 @@ namespace Org.BouncyCastle.Crypto.Digests
return DIGEST_SIZE;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int haraka256256(byte[] msg, Span<byte> output)
+ {
+ byte[][] s1 = new byte[2][];
+ s1[0] = new byte[16];
+ s1[1] = new byte[16];
+ byte[][] s2 = new byte[2][];
+ s2[0] = new byte[16];
+ s2[1] = new byte[16];
+
+ Array.Copy(msg, 0, s1[0], 0, 16);
+ Array.Copy(msg, 16, s1[1], 0, 16);
+
+ s1[0] = aesEnc(s1[0], RC[0]);
+ s1[1] = aesEnc(s1[1], RC[1]);
+ s1[0] = aesEnc(s1[0], RC[2]);
+ s1[1] = aesEnc(s1[1], RC[3]);
+ mix256(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[4]);
+ s1[1] = aesEnc(s2[1], RC[5]);
+ s1[0] = aesEnc(s1[0], RC[6]);
+ s1[1] = aesEnc(s1[1], RC[7]);
+ mix256(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[8]);
+ s1[1] = aesEnc(s2[1], RC[9]);
+ s1[0] = aesEnc(s1[0], RC[10]);
+ s1[1] = aesEnc(s1[1], RC[11]);
+ mix256(s1, s2);
+ s1[0] = aesEnc(s2[0], RC[12]);
+ s1[1] = aesEnc(s2[1], RC[13]);
+ s1[0] = aesEnc(s1[0], RC[14]);
+ s1[1] = aesEnc(s1[1], RC[15]);
+ mix256(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[16]);
+ s1[1] = aesEnc(s2[1], RC[17]);
+ s1[0] = aesEnc(s1[0], RC[18]);
+ s1[1] = aesEnc(s1[1], RC[19]);
+ mix256(s1, s2);
+
+ s1[0] = Xor(s2[0], msg, 0);
+ s1[1] = Xor(s2[1], msg, 16);
+
+ s1[0].AsSpan(0, 16).CopyTo(output);
+ s1[1].AsSpan(0, 16).CopyTo(output[16..]);
+
+ return DIGEST_SIZE;
+ }
+#endif
public Haraka256Digest()
{
@@ -106,10 +157,7 @@ namespace Org.BouncyCastle.Crypto.Digests
this.off = digest.off;
}
- public string getAlgorithmName()
- {
- return "Haraka-256";
- }
+ public override string AlgorithmName => "Haraka-256";
public override void Update(byte input)
{
@@ -132,6 +180,19 @@ namespace Org.BouncyCastle.Crypto.Digests
off += len;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ if (off + input.Length > 32)
+ {
+ throw new ArgumentException("total input cannot be more than 32 bytes");
+ }
+
+ input.CopyTo(buffer.AsSpan(off));
+ off += input.Length;
+ }
+#endif
+
public override int DoFinal(byte[] output, int outOff)
{
if (off != 32)
@@ -151,6 +212,27 @@ namespace Org.BouncyCastle.Crypto.Digests
return rv;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ if (off != 32)
+ {
+ throw new ArgumentException("input must be exactly 32 bytes");
+ }
+
+ if (output.Length < 32)
+ {
+ throw new ArgumentException("output too short to receive digest");
+ }
+
+ int rv = haraka256256(buffer, output);
+
+ Reset();
+
+ return rv;
+ }
+#endif
+
public override void Reset()
{
off = 0;
diff --git a/crypto/src/crypto/digests/Haraka512Digest.cs b/crypto/src/crypto/digests/Haraka512Digest.cs
index 36bdcbabe..0faeae710 100644
--- a/crypto/src/crypto/digests/Haraka512Digest.cs
+++ b/crypto/src/crypto/digests/Haraka512Digest.cs
@@ -1,5 +1,7 @@
using System;
+using Org.BouncyCastle.Utilities;
+
namespace Org.BouncyCastle.Crypto.Digests
{
public class Haraka512Digest : HarakaBase
@@ -167,10 +169,92 @@ namespace Org.BouncyCastle.Crypto.Digests
return DIGEST_SIZE;
}
- public string GetAlgorithmName()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int Haraka512256(byte[] msg, Span<byte> output)
{
- return "Haraka-512";
+ byte[][] s1 = new byte[4][];
+ s1[0] = new byte[16];
+ s1[1] = new byte[16];
+ s1[2] = new byte[16];
+ s1[3] = new byte[16];
+ byte[][] s2 = new byte[4][];
+ s2[0] = new byte[16];
+ s2[1] = new byte[16];
+ s2[2] = new byte[16];
+ s2[3] = new byte[16];
+
+ //-- Unrolled version of above.
+
+ Array.Copy(msg, 0, s1[0], 0, 16);
+ Array.Copy(msg, 16, s1[1], 0, 16);
+ Array.Copy(msg, 32, s1[2], 0, 16);
+ Array.Copy(msg, 48, s1[3], 0, 16);
+
+ s1[0] = aesEnc(s1[0], RC[0]);
+ s1[1] = aesEnc(s1[1], RC[1]);
+ s1[2] = aesEnc(s1[2], RC[2]);
+ s1[3] = aesEnc(s1[3], RC[3]);
+ s1[0] = aesEnc(s1[0], RC[4]);
+ s1[1] = aesEnc(s1[1], RC[5]);
+ s1[2] = aesEnc(s1[2], RC[6]);
+ s1[3] = aesEnc(s1[3], RC[7]);
+ Mix512(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[8]);
+ s1[1] = aesEnc(s2[1], RC[9]);
+ s1[2] = aesEnc(s2[2], RC[10]);
+ s1[3] = aesEnc(s2[3], RC[11]);
+ s1[0] = aesEnc(s1[0], RC[12]);
+ s1[1] = aesEnc(s1[1], RC[13]);
+ s1[2] = aesEnc(s1[2], RC[14]);
+ s1[3] = aesEnc(s1[3], RC[15]);
+ Mix512(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[16]);
+ s1[1] = aesEnc(s2[1], RC[17]);
+ s1[2] = aesEnc(s2[2], RC[18]);
+ s1[3] = aesEnc(s2[3], RC[19]);
+ s1[0] = aesEnc(s1[0], RC[20]);
+ s1[1] = aesEnc(s1[1], RC[21]);
+ s1[2] = aesEnc(s1[2], RC[22]);
+ s1[3] = aesEnc(s1[3], RC[23]);
+ Mix512(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[24]);
+ s1[1] = aesEnc(s2[1], RC[25]);
+ s1[2] = aesEnc(s2[2], RC[26]);
+ s1[3] = aesEnc(s2[3], RC[27]);
+ s1[0] = aesEnc(s1[0], RC[28]);
+ s1[1] = aesEnc(s1[1], RC[29]);
+ s1[2] = aesEnc(s1[2], RC[30]);
+ s1[3] = aesEnc(s1[3], RC[31]);
+ Mix512(s1, s2);
+
+ s1[0] = aesEnc(s2[0], RC[32]);
+ s1[1] = aesEnc(s2[1], RC[33]);
+ s1[2] = aesEnc(s2[2], RC[34]);
+ s1[3] = aesEnc(s2[3], RC[35]);
+ s1[0] = aesEnc(s1[0], RC[36]);
+ s1[1] = aesEnc(s1[1], RC[37]);
+ s1[2] = aesEnc(s1[2], RC[38]);
+ s1[3] = aesEnc(s1[3], RC[39]);
+ Mix512(s1, s2);
+
+ s1[0] = Xor(s2[0], msg, 0);
+ s1[1] = Xor(s2[1], msg, 16);
+ s1[2] = Xor(s2[2], msg, 32);
+ s1[3] = Xor(s2[3], msg, 48);
+
+ s1[0].AsSpan(8, 8).CopyTo(output);
+ s1[1].AsSpan(8, 8).CopyTo(output[8..]);
+ s1[2].AsSpan(0, 8).CopyTo(output[16..]);
+ s1[3].AsSpan(0, 8).CopyTo(output[24..]);
+
+ return DIGEST_SIZE;
}
+#endif
+
+ public override string AlgorithmName => "Haraka-512";
public override void Update(byte input)
{
@@ -193,6 +277,19 @@ namespace Org.BouncyCastle.Crypto.Digests
off += len;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ if (off + input.Length > 64)
+ {
+ throw new ArgumentException("total input cannot be more than 64 bytes");
+ }
+
+ input.CopyTo(buffer.AsSpan(off));
+ off += input.Length;
+ }
+#endif
+
public override int DoFinal(byte[] output, int outOff)
{
if (off != 64)
@@ -212,6 +309,27 @@ namespace Org.BouncyCastle.Crypto.Digests
return rv;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ if (off != 64)
+ {
+ throw new ArgumentException("input must be exactly 64 bytes");
+ }
+
+ if (output.Length < 32)
+ {
+ throw new ArgumentException("output too short to receive digest");
+ }
+
+ int rv = Haraka512256(buffer, output);
+
+ Reset();
+
+ return rv;
+ }
+#endif
+
public override void Reset()
{
off = 0;
diff --git a/crypto/src/crypto/digests/HarakaBase.cs b/crypto/src/crypto/digests/HarakaBase.cs
index 6157198f1..1270de35c 100644
--- a/crypto/src/crypto/digests/HarakaBase.cs
+++ b/crypto/src/crypto/digests/HarakaBase.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Text;
namespace Org.BouncyCastle.Crypto.Digests
{
@@ -26,10 +24,7 @@ namespace Org.BouncyCastle.Crypto.Digests
{(byte)0xe1, (byte)0xf8, (byte)0x98, (byte)0x11, (byte)0x69, (byte)0xd9, (byte)0x8e, (byte)0x94, (byte)0x9b, (byte)0x1e, (byte)0x87, (byte)0xe9, (byte)0xce, (byte)0x55, (byte)0x28, (byte)0xdf},
{(byte)0x8c, (byte)0xa1, (byte)0x89, (byte)0x0d, (byte)0xbf, (byte)0xe6, (byte)0x42, (byte)0x68, (byte)0x41, (byte)0x99, (byte)0x2d, (byte)0x0f, (byte)0xb0, (byte)0x54, (byte)0xbb, (byte)0x16}};
- public string AlgorithmName
- {
- get { return "Haraka Base"; }
- }
+ public abstract string AlgorithmName { get; }
static byte sBox(byte x)
{
@@ -144,5 +139,10 @@ namespace Org.BouncyCastle.Crypto.Digests
public abstract void Reset();
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public abstract void BlockUpdate(ReadOnlySpan<byte> input);
+
+ public abstract int DoFinal(Span<byte> output);
+#endif
}
}
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
index 2da2e099e..b8305cc13 100644
--- a/crypto/src/crypto/digests/KeccakDigest.cs
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -76,6 +76,13 @@ namespace Org.BouncyCastle.Crypto.Digests
Absorb(input, inOff, len);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ Absorb(input);
+ }
+#endif
+
public virtual int DoFinal(byte[] output, int outOff)
{
Squeeze(output, outOff, fixedOutputLength);
@@ -85,6 +92,18 @@ namespace Org.BouncyCastle.Crypto.Digests
return GetDigestSize();
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ int digestSize = GetDigestSize();
+ Squeeze(output[..digestSize]);
+
+ Reset();
+
+ return digestSize;
+ }
+#endif
+
/*
* TODO Possible API change to support partial-byte suffixes.
*/
@@ -199,6 +218,46 @@ namespace Org.BouncyCastle.Crypto.Digests
this.bitsInQueue = remaining << 3;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected void Absorb(ReadOnlySpan<byte> data)
+ {
+ if ((bitsInQueue & 7) != 0)
+ throw new InvalidOperationException("attempt to absorb with odd length queue");
+ if (squeezing)
+ throw new InvalidOperationException("attempt to absorb while squeezing");
+
+ int bytesInQueue = bitsInQueue >> 3;
+ int rateBytes = rate >> 3;
+
+ int len = data.Length;
+ int available = rateBytes - bytesInQueue;
+ if (len < available)
+ {
+ data.CopyTo(dataQueue.AsSpan(bytesInQueue));
+ this.bitsInQueue += len << 3;
+ return;
+ }
+
+ int count = 0;
+ if (bytesInQueue > 0)
+ {
+ data[..available].CopyTo(dataQueue.AsSpan(bytesInQueue));
+ count += available;
+ KeccakAbsorb(dataQueue, 0);
+ }
+
+ int remaining;
+ while ((remaining = len - count) >= rateBytes)
+ {
+ KeccakAbsorb(data[count..]);
+ count += rateBytes;
+ }
+
+ data[count..].CopyTo(dataQueue.AsSpan());
+ this.bitsInQueue = remaining << 3;
+ }
+#endif
+
protected void AbsorbBits(int data, int bits)
{
if (bits < 1 || bits > 7)
@@ -270,6 +329,30 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected void Squeeze(Span<byte> output)
+ {
+ if (!squeezing)
+ {
+ PadAndSwitchToSqueezingPhase();
+ }
+ long outputLength = (long)output.Length << 3;
+
+ long i = 0;
+ while (i < outputLength)
+ {
+ if (bitsInQueue == 0)
+ {
+ KeccakExtract();
+ }
+ int partialBlock = (int)System.Math.Min(bitsInQueue, outputLength - i);
+ dataQueue.AsSpan((rate - bitsInQueue) >> 3, partialBlock >> 3).CopyTo(output[(int)(i >> 3)..]);
+ bitsInQueue -= partialBlock;
+ i += partialBlock;
+ }
+ }
+#endif
+
private void KeccakAbsorb(byte[] data, int off)
{
int count = rate >> 6;
@@ -282,6 +365,20 @@ namespace Org.BouncyCastle.Crypto.Digests
KeccakPermutation();
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void KeccakAbsorb(ReadOnlySpan<byte> data)
+ {
+ int count = rate >> 6, off = 0;
+ for (int i = 0; i < count; ++i)
+ {
+ state[i] ^= Pack.LE_To_UInt64(data[off..]);
+ off += 8;
+ }
+
+ KeccakPermutation();
+ }
+#endif
+
private void KeccakExtract()
{
KeccakPermutation();
diff --git a/crypto/src/crypto/digests/LongDigest.cs b/crypto/src/crypto/digests/LongDigest.cs
index aaa0b43ce..6a2f94ece 100644
--- a/crypto/src/crypto/digests/LongDigest.cs
+++ b/crypto/src/crypto/digests/LongDigest.cs
@@ -10,46 +10,46 @@ namespace Org.BouncyCastle.Crypto.Digests
* Base class for SHA-384 and SHA-512.
*/
public abstract class LongDigest
- : IDigest, IMemoable
+ : IDigest, IMemoable
{
- private int MyByteLength = 128;
+ private int MyByteLength = 128;
- private byte[] xBuf;
- private int xBufOff;
+ private byte[] xBuf;
+ private int xBufOff;
- private long byteCount1;
- private long byteCount2;
+ private long byteCount1;
+ private long byteCount2;
internal ulong H1, H2, H3, H4, H5, H6, H7, H8;
private ulong[] W = new ulong[80];
private int wOff;
- /**
+ /**
* Constructor for variable length word
*/
internal LongDigest()
{
xBuf = new byte[8];
- Reset();
+ Reset();
}
- /**
+ /**
* Copy constructor. We are using copy constructors in place
* of the object.Clone() interface as this interface is not
* supported by J2ME.
*/
internal LongDigest(
- LongDigest t)
- {
- xBuf = new byte[t.xBuf.Length];
+ LongDigest t)
+ {
+ xBuf = new byte[t.xBuf.Length];
- CopyIn(t);
- }
+ CopyIn(t);
+ }
- protected void CopyIn(LongDigest t)
- {
+ protected void CopyIn(LongDigest t)
+ {
Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
xBufOff = t.xBufOff;
@@ -84,9 +84,9 @@ namespace Org.BouncyCastle.Crypto.Digests
}
public void BlockUpdate(
- byte[] input,
- int inOff,
- int length)
+ byte[] input,
+ int inOff,
+ int length)
{
//
// fill the current word
@@ -123,12 +123,54 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ int inOff = 0;
+ int length = input.Length;
+
+ //
+ // fill the current word
+ //
+ while ((xBufOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length >= xBuf.Length)
+ {
+ ProcessWord(input.Slice(inOff, xBuf.Length));
+
+ inOff += xBuf.Length;
+ length -= xBuf.Length;
+ byteCount1 += xBuf.Length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+#endif
+
public void Finish()
{
AdjustByteCounts();
- long lowBitLength = byteCount1 << 3;
- long hiBitLength = byteCount2;
+ long lowBitLength = byteCount1 << 3;
+ long hiBitLength = byteCount2;
//
// add the pad bytes.
@@ -151,20 +193,20 @@ namespace Org.BouncyCastle.Crypto.Digests
byteCount2 = 0;
xBufOff = 0;
- for ( int i = 0; i < xBuf.Length; i++ )
+ for (int i = 0; i < xBuf.Length; i++)
{
xBuf[i] = 0;
}
wOff = 0;
- Array.Clear(W, 0, W.Length);
+ Array.Clear(W, 0, W.Length);
}
internal void ProcessWord(
- byte[] input,
- int inOff)
+ byte[] input,
+ int inOff)
{
- W[wOff] = Pack.BE_To_UInt64(input, inOff);
+ W[wOff] = Pack.BE_To_UInt64(input, inOff);
if (++wOff == 16)
{
@@ -172,6 +214,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ W[wOff] = Pack.BE_To_UInt64(word);
+
+ if (++wOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
/**
* adjust the byte counts so that byteCount2 represents the
* upper long (less 3 bits) word of the byte count.
@@ -180,14 +234,14 @@ namespace Org.BouncyCastle.Crypto.Digests
{
if (byteCount1 > 0x1fffffffffffffffL)
{
- byteCount2 += (long) ((ulong) byteCount1 >> 61);
+ byteCount2 += (long)((ulong)byteCount1 >> 61);
byteCount1 &= 0x1fffffffffffffffL;
}
}
internal void ProcessLength(
- long lowW,
- long hiW)
+ long lowW,
+ long hiW)
{
if (wOff > 14)
{
@@ -222,51 +276,51 @@ namespace Org.BouncyCastle.Crypto.Digests
ulong g = H7;
ulong h = H8;
- int t = 0;
- for(int i = 0; i < 10; i ++)
- {
- // t = 8 * i
- h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
- d += h;
- h += Sum0(a) + Maj(a, b, c);
-
- // t = 8 * i + 1
- g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
- c += g;
- g += Sum0(h) + Maj(h, a, b);
-
- // t = 8 * i + 2
- f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
- b += f;
- f += Sum0(g) + Maj(g, h, a);
-
- // t = 8 * i + 3
- e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
- a += e;
- e += Sum0(f) + Maj(f, g, h);
-
- // t = 8 * i + 4
- d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
- h += d;
- d += Sum0(e) + Maj(e, f, g);
-
- // t = 8 * i + 5
- c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
- g += c;
- c += Sum0(d) + Maj(d, e, f);
-
- // t = 8 * i + 6
- b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
- f += b;
- b += Sum0(c) + Maj(c, d, e);
-
- // t = 8 * i + 7
- a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
- e += a;
- a += Sum0(b) + Maj(b, c, d);
- }
-
- H1 += a;
+ int t = 0;
+ for (int i = 0; i < 10; i++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ }
+
+ H1 += a;
H2 += b;
H3 += c;
H4 += d;
@@ -275,14 +329,14 @@ namespace Org.BouncyCastle.Crypto.Digests
H7 += g;
H8 += h;
- //
+ //
// reset the offset and clean out the word buffer.
//
wOff = 0;
- Array.Clear(W, 0, 16);
- }
+ Array.Clear(W, 0, 16);
+ }
- /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+ /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
private static ulong Ch(ulong x, ulong y, ulong z)
{
return (x & y) ^ (~x & z);
@@ -295,61 +349,64 @@ namespace Org.BouncyCastle.Crypto.Digests
private static ulong Sum0(ulong x)
{
- return ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39));
+ return ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39));
}
- private static ulong Sum1(ulong x)
+ private static ulong Sum1(ulong x)
{
- return ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41));
+ return ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41));
}
private static ulong Sigma0(ulong x)
{
- return ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7);
+ return ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7);
}
private static ulong Sigma1(ulong x)
{
- return ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6);
+ return ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6);
}
/* SHA-384 and SHA-512 Constants
* (represent the first 64 bits of the fractional parts of the
* cube roots of the first sixty-four prime numbers)
*/
- internal static readonly ulong[] K =
- {
- 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
- 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
- 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
- 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
- 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
- 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
- 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
- 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
- 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
- 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
- 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
- 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
- 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
- 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
- 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
- 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
- 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
- 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
- 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
- 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
- };
-
- public int GetByteLength()
- {
- return MyByteLength;
- }
-
- public abstract string AlgorithmName { get; }
- public abstract int GetDigestSize();
+ internal static readonly ulong[] K =
+ {
+ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+ 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+ 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
+ 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
+ 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+ 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
+ 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+ 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+ };
+
+ public int GetByteLength()
+ {
+ return MyByteLength;
+ }
+
+ public abstract string AlgorithmName { get; }
+ public abstract int GetDigestSize();
public abstract int DoFinal(byte[] output, int outOff);
- public abstract IMemoable Copy();
- public abstract void Reset(IMemoable t);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public abstract int DoFinal(Span<byte> output);
+#endif
+ public abstract IMemoable Copy();
+ public abstract void Reset(IMemoable t);
}
}
diff --git a/crypto/src/crypto/digests/MD2Digest.cs b/crypto/src/crypto/digests/MD2Digest.cs
index f72d08768..cea89a311 100644
--- a/crypto/src/crypto/digests/MD2Digest.cs
+++ b/crypto/src/crypto/digests/MD2Digest.cs
@@ -1,6 +1,5 @@
using System;
-using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Digests
@@ -99,6 +98,30 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ // add padding
+ byte paddingByte = (byte)(M.Length - mOff);
+ for (int i = mOff; i < M.Length; i++)
+ {
+ M[i] = paddingByte;
+ }
+ //do final check sum
+ ProcessChecksum(M);
+ // do final block process
+ ProcessBlock(M);
+
+ ProcessBlock(C);
+
+ X.AsSpan(xOff, 16).CopyTo(output);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the digest back to it's initial state.
*/
@@ -179,6 +202,40 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ //
+ // fill the current word
+ //
+ while ((mOff != 0) && (input.Length > 0))
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+
+ //
+ // process whole words.
+ //
+ while (input.Length >= 16)
+ {
+ input[..16].CopyTo(M);
+ ProcessChecksum(M);
+ ProcessBlock(M);
+ input = input[16..];
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (input.Length > 0)
+ {
+ Update(input[0]);
+ input = input[1..];
+ }
+ }
+#endif
+
internal void ProcessChecksum(byte[] m)
{
int L = C[15];
diff --git a/crypto/src/crypto/digests/MD4Digest.cs b/crypto/src/crypto/digests/MD4Digest.cs
index 8743f7dad..2eb2c8400 100644
--- a/crypto/src/crypto/digests/MD4Digest.cs
+++ b/crypto/src/crypto/digests/MD4Digest.cs
@@ -1,5 +1,6 @@
using System;
+using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Digests
@@ -60,12 +61,9 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
- internal override void ProcessWord(
- byte[] input,
- int inOff)
+ internal override void ProcessWord(byte[] input, int inOff)
{
- X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
- | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+ X[xOff++] = (int)Pack.LE_To_UInt32(input, inOff);
if (xOff == 16)
{
@@ -73,6 +71,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff++] = (int)Pack.LE_To_UInt32(word);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(
long bitLength)
{
@@ -85,32 +95,35 @@ namespace Org.BouncyCastle.Crypto.Digests
X[15] = (int)((ulong) bitLength >> 32);
}
- private void UnpackWord(
- int word,
- byte[] outBytes,
- int outOff)
+ public override int DoFinal(byte[] output, int outOff)
{
- outBytes[outOff] = (byte)word;
- outBytes[outOff + 1] = (byte)((uint) word >> 8);
- outBytes[outOff + 2] = (byte)((uint) word >> 16);
- outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ Finish();
+
+ Pack.UInt32_To_LE((uint)H1, output, outOff);
+ Pack.UInt32_To_LE((uint)H2, output, outOff + 4);
+ Pack.UInt32_To_LE((uint)H3, output, outOff + 8);
+ Pack.UInt32_To_LE((uint)H4, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
}
- public override int DoFinal(
- byte[] output,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
{
Finish();
- UnpackWord(H1, output, outOff);
- UnpackWord(H2, output, outOff + 4);
- UnpackWord(H3, output, outOff + 8);
- UnpackWord(H4, output, outOff + 12);
+ Pack.UInt32_To_LE((uint)H1, output);
+ Pack.UInt32_To_LE((uint)H2, output[4..]);
+ Pack.UInt32_To_LE((uint)H3, output[8..]);
+ Pack.UInt32_To_LE((uint)H4, output[12..]);
Reset();
return DigestLength;
}
+#endif
/**
* reset the chaining variables to the IV values.
diff --git a/crypto/src/crypto/digests/MD5Digest.cs b/crypto/src/crypto/digests/MD5Digest.cs
index c60ac92a3..062d7bb46 100644
--- a/crypto/src/crypto/digests/MD5Digest.cs
+++ b/crypto/src/crypto/digests/MD5Digest.cs
@@ -55,9 +55,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
- internal override void ProcessWord(
- byte[] input,
- int inOff)
+ internal override void ProcessWord(byte[] input, int inOff)
{
X[xOff] = Pack.LE_To_UInt32(input, inOff);
@@ -67,6 +65,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff] = Pack.LE_To_UInt32(word);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(
long bitLength)
{
@@ -103,6 +113,22 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_LE(H1, output);
+ Pack.UInt32_To_LE(H2, output[4..]);
+ Pack.UInt32_To_LE(H3, output[8..]);
+ Pack.UInt32_To_LE(H4, output[12..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables to the IV values.
*/
diff --git a/crypto/src/crypto/digests/NonMemoableDigest.cs b/crypto/src/crypto/digests/NonMemoableDigest.cs
index 02c49b887..bad38911b 100644
--- a/crypto/src/crypto/digests/NonMemoableDigest.cs
+++ b/crypto/src/crypto/digests/NonMemoableDigest.cs
@@ -44,11 +44,25 @@ namespace Org.BouncyCastle.Crypto.Digests
mBaseDigest.BlockUpdate(input, inOff, len);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ mBaseDigest.BlockUpdate(input);
+ }
+#endif
+
public virtual int DoFinal(byte[] output, int outOff)
{
return mBaseDigest.DoFinal(output, outOff);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ return mBaseDigest.DoFinal(output);
+ }
+#endif
+
public virtual void Reset()
{
mBaseDigest.Reset();
diff --git a/crypto/src/crypto/digests/NullDigest.cs b/crypto/src/crypto/digests/NullDigest.cs
index d14dd5c9f..28554cf3e 100644
--- a/crypto/src/crypto/digests/NullDigest.cs
+++ b/crypto/src/crypto/digests/NullDigest.cs
@@ -35,17 +35,48 @@ namespace Org.BouncyCastle.Crypto.Digests
bOut.Write(inBytes, inOff, len);
}
- public int DoFinal(byte[] outBytes, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
{
+ bOut.Write(input);
+ }
+#endif
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ try
+ {
+ byte[] data = bOut.GetBuffer();
+ int length = Convert.ToInt32(bOut.Length);
+
+ Array.Copy(data, 0, outBytes, outOff, length);
+
+ return length;
+ }
+ finally
+ {
+ Reset();
+ }
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
try
{
- return Streams.WriteBufTo(bOut, outBytes, outOff);
+ byte[] data = bOut.GetBuffer();
+ int length = Convert.ToInt32(bOut.Length);
+
+ data.AsSpan(0, length).CopyTo(output);
+
+ return length;
}
finally
{
Reset();
}
}
+#endif
public void Reset()
{
diff --git a/crypto/src/crypto/digests/ParallelHash.cs b/crypto/src/crypto/digests/ParallelHash.cs
index f28795f5a..8054b2005 100644
--- a/crypto/src/crypto/digests/ParallelHash.cs
+++ b/crypto/src/crypto/digests/ParallelHash.cs
@@ -85,7 +85,7 @@ namespace Org.BouncyCastle.Crypto.Digests
buffer[bufOff++] = b;
if (bufOff == buffer.Length)
{
- compress();
+ Compress();
}
}
@@ -106,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Digests
if (bufOff == buffer.Length)
{
- compress();
+ Compress();
}
}
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Digests
{
while (len - i >= B)
{
- compress(inBuf, inOff + i, B);
+ Compress(inBuf, inOff + i, B);
i += B;
}
}
@@ -125,13 +125,49 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
- private void compress()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
{
- compress(buffer, 0, bufOff);
+ //
+ // 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)
+ private void Compress(byte[] buf, int offSet, int len)
{
compressor.BlockUpdate(buf, offSet, len);
compressor.DoFinal(compressorBuffer, 0, compressorBuffer.Length);
@@ -141,11 +177,23 @@ namespace Org.BouncyCastle.Crypto.Digests
nCount++;
}
- private void wrapUp(int outputSize)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void Compress(ReadOnlySpan<byte> input, int pos, int len)
+ {
+ compressor.BlockUpdate(input.Slice(pos, len));
+ compressor.DoFinal(compressorBuffer, 0, compressorBuffer.Length);
+
+ cshake.BlockUpdate(compressorBuffer, 0, compressorBuffer.Length);
+
+ nCount++;
+ }
+#endif
+
+ private void WrapUp(int outputSize)
{
if (bufOff != 0)
{
- compress();
+ Compress();
}
byte[] nOut = XofUtilities.RightEncode(nCount);
byte[] encOut = XofUtilities.RightEncode(outputSize * 8);
@@ -160,21 +208,37 @@ namespace Org.BouncyCastle.Crypto.Digests
{
if (firstOutput)
{
- wrapUp(outputLength);
+ WrapUp(outputLength);
+ }
+
+ int rv = cshake.DoFinal(outBuf, outOff);
+
+ Reset();
+
+ return rv;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ WrapUp(outputLength);
}
- int rv = cshake.DoFinal(outBuf, outOff, GetDigestSize());
+ int rv = cshake.DoFinal(output);
Reset();
return rv;
}
+#endif
public virtual int DoFinal(byte[] outBuf, int outOff, int outLen)
{
if (firstOutput)
{
- wrapUp(outputLength);
+ WrapUp(outputLength);
}
int rv = cshake.DoFinal(outBuf, outOff, outLen);
@@ -184,16 +248,44 @@ namespace Org.BouncyCastle.Crypto.Digests
return rv;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int OutputFinal(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ WrapUp(outputLength);
+ }
+
+ int rv = cshake.OutputFinal(output);
+
+ Reset();
+
+ return rv;
+ }
+#endif
+
public virtual int DoOutput(byte[] outBuf, int outOff, int outLen)
{
if (firstOutput)
{
- wrapUp(0);
+ WrapUp(0);
}
return cshake.DoOutput(outBuf, outOff, outLen);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int Output(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ WrapUp(0);
+ }
+
+ return cshake.Output(output);
+ }
+#endif
+
public virtual void Reset()
{
cshake.Reset();
diff --git a/crypto/src/crypto/digests/RipeMD128Digest.cs b/crypto/src/crypto/digests/RipeMD128Digest.cs
index cba2c65d3..b66452682 100644
--- a/crypto/src/crypto/digests/RipeMD128Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD128Digest.cs
@@ -68,6 +68,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff++] = (int)Pack.LE_To_UInt32(word);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(
long bitLength)
{
@@ -94,6 +106,22 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_LE((uint)H0, output);
+ Pack.UInt32_To_LE((uint)H1, output[4..]);
+ Pack.UInt32_To_LE((uint)H2, output[8..]);
+ Pack.UInt32_To_LE((uint)H3, output[12..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables to the IV values.
*/
diff --git a/crypto/src/crypto/digests/RipeMD160Digest.cs b/crypto/src/crypto/digests/RipeMD160Digest.cs
index 0fc2a4a1c..a95bff48a 100644
--- a/crypto/src/crypto/digests/RipeMD160Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD160Digest.cs
@@ -70,6 +70,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff++] = (int)Pack.LE_To_UInt32(word);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(
long bitLength)
{
@@ -97,6 +109,23 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_LE((uint)H0, output);
+ Pack.UInt32_To_LE((uint)H1, output[4..]);
+ Pack.UInt32_To_LE((uint)H2, output[8..]);
+ Pack.UInt32_To_LE((uint)H3, output[12..]);
+ Pack.UInt32_To_LE((uint)H4, output[16..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables to the IV values.
*/
diff --git a/crypto/src/crypto/digests/RipeMD256Digest.cs b/crypto/src/crypto/digests/RipeMD256Digest.cs
index 621162a6f..40508e9f7 100644
--- a/crypto/src/crypto/digests/RipeMD256Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD256Digest.cs
@@ -70,6 +70,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff++] = (int)Pack.LE_To_UInt32(word);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(
long bitLength)
{
@@ -100,6 +112,26 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_LE((uint)H0, output);
+ Pack.UInt32_To_LE((uint)H1, output[4..]);
+ Pack.UInt32_To_LE((uint)H2, output[8..]);
+ Pack.UInt32_To_LE((uint)H3, output[12..]);
+ Pack.UInt32_To_LE((uint)H4, output[16..]);
+ Pack.UInt32_To_LE((uint)H5, output[20..]);
+ Pack.UInt32_To_LE((uint)H6, output[24..]);
+ Pack.UInt32_To_LE((uint)H7, output[28..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/// <summary> reset the chaining variables to the IV values.</summary>
public override void Reset()
{
diff --git a/crypto/src/crypto/digests/RipeMD320Digest.cs b/crypto/src/crypto/digests/RipeMD320Digest.cs
index c46bc4fea..ddaf858ff 100644
--- a/crypto/src/crypto/digests/RipeMD320Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD320Digest.cs
@@ -73,6 +73,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff++] = (int)Pack.LE_To_UInt32(word);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(
long bitLength)
{
@@ -105,6 +117,28 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_LE((uint)H0, output);
+ Pack.UInt32_To_LE((uint)H1, output[4..]);
+ Pack.UInt32_To_LE((uint)H2, output[8..]);
+ Pack.UInt32_To_LE((uint)H3, output[12..]);
+ Pack.UInt32_To_LE((uint)H4, output[16..]);
+ Pack.UInt32_To_LE((uint)H5, output[20..]);
+ Pack.UInt32_To_LE((uint)H6, output[24..]);
+ Pack.UInt32_To_LE((uint)H7, output[28..]);
+ Pack.UInt32_To_LE((uint)H8, output[32..]);
+ Pack.UInt32_To_LE((uint)H9, output[36..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/// <summary> reset the chaining variables to the IV values.</summary>
public override void Reset()
{
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
index 3dc63a6ed..778c453d8 100644
--- a/crypto/src/crypto/digests/SHA3Digest.cs
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -55,6 +55,15 @@ namespace Org.BouncyCastle.Crypto.Digests
return base.DoFinal(output, outOff);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ AbsorbBits(0x02, 2);
+
+ return base.DoFinal(output);
+ }
+#endif
+
/*
* TODO Possible API change to support partial-byte suffixes.
*/
diff --git a/crypto/src/crypto/digests/SM3Digest.cs b/crypto/src/crypto/digests/SM3Digest.cs
index 449d7c161..81d4a68a9 100644
--- a/crypto/src/crypto/digests/SM3Digest.cs
+++ b/crypto/src/crypto/digests/SM3Digest.cs
@@ -118,7 +118,6 @@ namespace Org.BouncyCastle.Crypto.Digests
this.xOff = 0;
}
-
public override int DoFinal(byte[] output, int outOff)
{
Finish();
@@ -130,13 +129,22 @@ namespace Org.BouncyCastle.Crypto.Digests
return DIGEST_LENGTH;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(V, output);
+
+ Reset();
- internal override void ProcessWord(byte[] input,
- int inOff)
+ return DIGEST_LENGTH;
+ }
+#endif
+
+ internal override void ProcessWord(byte[] input, int inOff)
{
- uint n = Pack.BE_To_UInt32(input, inOff);
- this.inwords[this.xOff] = n;
- ++this.xOff;
+ inwords[xOff++] = Pack.BE_To_UInt32(input, inOff);
if (this.xOff >= 16)
{
@@ -144,7 +152,19 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
- internal override void ProcessLength(long bitLength)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ inwords[xOff++] = Pack.BE_To_UInt32(word);
+
+ if (this.xOff >= 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
+ internal override void ProcessLength(long bitLength)
{
if (this.xOff > (BLOCK_SIZE - 2))
{
diff --git a/crypto/src/crypto/digests/Sha1Digest.cs b/crypto/src/crypto/digests/Sha1Digest.cs
index 60ec651d5..9b384b8cb 100644
--- a/crypto/src/crypto/digests/Sha1Digest.cs
+++ b/crypto/src/crypto/digests/Sha1Digest.cs
@@ -61,9 +61,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
- internal override void ProcessWord(
- byte[] input,
- int inOff)
+ internal override void ProcessWord(byte[] input, int inOff)
{
X[xOff] = Pack.BE_To_UInt32(input, inOff);
@@ -73,6 +71,18 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff] = Pack.BE_To_UInt32(word);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
internal override void ProcessLength(long bitLength)
{
if (xOff > 14)
@@ -101,6 +111,23 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(H1, output);
+ Pack.UInt32_To_BE(H2, output[4..]);
+ Pack.UInt32_To_BE(H3, output[8..]);
+ Pack.UInt32_To_BE(H4, output[12..]);
+ Pack.UInt32_To_BE(H5, output[16..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables
*/
@@ -279,6 +306,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
}
}
diff --git a/crypto/src/crypto/digests/Sha224Digest.cs b/crypto/src/crypto/digests/Sha224Digest.cs
index b4e853745..28d09adec 100644
--- a/crypto/src/crypto/digests/Sha224Digest.cs
+++ b/crypto/src/crypto/digests/Sha224Digest.cs
@@ -72,9 +72,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
- internal override void ProcessWord(
- byte[] input,
- int inOff)
+ internal override void ProcessWord(byte[] input, int inOff)
{
X[xOff] = Pack.BE_To_UInt32(input, inOff);
@@ -84,7 +82,19 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
- internal override void ProcessLength(
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff] = Pack.BE_To_UInt32(word);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
+ internal override void ProcessLength(
long bitLength)
{
if (xOff > 14)
@@ -96,9 +106,7 @@ namespace Org.BouncyCastle.Crypto.Digests
X[15] = (uint)((ulong)bitLength);
}
- public override int DoFinal(
- byte[] output,
- int outOff)
+ public override int DoFinal(byte[] output, int outOff)
{
Finish();
@@ -115,7 +123,26 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(H1, output);
+ Pack.UInt32_To_BE(H2, output[4..]);
+ Pack.UInt32_To_BE(H3, output[8..]);
+ Pack.UInt32_To_BE(H4, output[12..]);
+ Pack.UInt32_To_BE(H5, output[16..]);
+ Pack.UInt32_To_BE(H6, output[20..]);
+ Pack.UInt32_To_BE(H7, output[24..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
+ /**
* reset the chaining variables
*/
public override void Reset()
@@ -284,6 +311,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
}
}
diff --git a/crypto/src/crypto/digests/Sha256Digest.cs b/crypto/src/crypto/digests/Sha256Digest.cs
index 63d5b8bee..51859697e 100644
--- a/crypto/src/crypto/digests/Sha256Digest.cs
+++ b/crypto/src/crypto/digests/Sha256Digest.cs
@@ -67,9 +67,7 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
- internal override void ProcessWord(
- byte[] input,
- int inOff)
+ internal override void ProcessWord(byte[] input, int inOff)
{
X[xOff] = Pack.BE_To_UInt32(input, inOff);
@@ -79,7 +77,19 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
- internal override void ProcessLength(
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal override void ProcessWord(ReadOnlySpan<byte> word)
+ {
+ X[xOff] = Pack.BE_To_UInt32(word);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+#endif
+
+ internal override void ProcessLength(
long bitLength)
{
if (xOff > 14)
@@ -91,26 +101,44 @@ namespace Org.BouncyCastle.Crypto.Digests
X[15] = (uint)((ulong)bitLength);
}
- public override int DoFinal(
- byte[] output,
- int outOff)
+ public override int DoFinal(byte[] output, int outOff)
{
Finish();
- Pack.UInt32_To_BE((uint)H1, output, outOff);
- Pack.UInt32_To_BE((uint)H2, output, outOff + 4);
- Pack.UInt32_To_BE((uint)H3, output, outOff + 8);
- Pack.UInt32_To_BE((uint)H4, output, outOff + 12);
- Pack.UInt32_To_BE((uint)H5, output, outOff + 16);
- Pack.UInt32_To_BE((uint)H6, output, outOff + 20);
- Pack.UInt32_To_BE((uint)H7, output, outOff + 24);
- Pack.UInt32_To_BE((uint)H8, output, outOff + 28);
+ Pack.UInt32_To_BE(H1, output, outOff);
+ Pack.UInt32_To_BE(H2, output, outOff + 4);
+ Pack.UInt32_To_BE(H3, output, outOff + 8);
+ Pack.UInt32_To_BE(H4, output, outOff + 12);
+ Pack.UInt32_To_BE(H5, output, outOff + 16);
+ Pack.UInt32_To_BE(H6, output, outOff + 20);
+ Pack.UInt32_To_BE(H7, output, outOff + 24);
+ Pack.UInt32_To_BE(H8, output, outOff + 28);
Reset();
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(H1, output);
+ Pack.UInt32_To_BE(H2, output[4..]);
+ Pack.UInt32_To_BE(H3, output[8..]);
+ Pack.UInt32_To_BE(H4, output[12..]);
+ Pack.UInt32_To_BE(H5, output[16..]);
+ Pack.UInt32_To_BE(H6, output[20..]);
+ Pack.UInt32_To_BE(H7, output[24..]);
+ Pack.UInt32_To_BE(H8, output[28..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables
*/
@@ -313,6 +341,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
}
}
diff --git a/crypto/src/crypto/digests/Sha384Digest.cs b/crypto/src/crypto/digests/Sha384Digest.cs
index e6c9a9aa9..e4e65ed85 100644
--- a/crypto/src/crypto/digests/Sha384Digest.cs
+++ b/crypto/src/crypto/digests/Sha384Digest.cs
@@ -64,6 +64,24 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt64_To_BE(H1, output);
+ Pack.UInt64_To_BE(H2, output[8..]);
+ Pack.UInt64_To_BE(H3, output[16..]);
+ Pack.UInt64_To_BE(H4, output[24..]);
+ Pack.UInt64_To_BE(H5, output[32..]);
+ Pack.UInt64_To_BE(H6, output[40..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables
*/
@@ -72,9 +90,9 @@ namespace Org.BouncyCastle.Crypto.Digests
base.Reset();
/* SHA-384 initial hash value
- * The first 64 bits of the fractional parts of the square roots
- * of the 9th through 16th prime numbers
- */
+ * The first 64 bits of the fractional parts of the square roots
+ * of the 9th through 16th prime numbers
+ */
H1 = 0xcbbb9d5dc1059ed8;
H2 = 0x629a292a367cd507;
H3 = 0x9159015a3070dd17;
@@ -96,6 +114,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
}
}
diff --git a/crypto/src/crypto/digests/Sha512Digest.cs b/crypto/src/crypto/digests/Sha512Digest.cs
index 2a0964fd3..9156c24bf 100644
--- a/crypto/src/crypto/digests/Sha512Digest.cs
+++ b/crypto/src/crypto/digests/Sha512Digest.cs
@@ -67,6 +67,26 @@ namespace Org.BouncyCastle.Crypto.Digests
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt64_To_BE(H1, output);
+ Pack.UInt64_To_BE(H2, output[8..]);
+ Pack.UInt64_To_BE(H3, output[16..]);
+ Pack.UInt64_To_BE(H4, output[24..]);
+ Pack.UInt64_To_BE(H5, output[32..]);
+ Pack.UInt64_To_BE(H6, output[40..]);
+ Pack.UInt64_To_BE(H7, output[48..]);
+ Pack.UInt64_To_BE(H8, output[56..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables
*/
@@ -99,6 +119,5 @@ namespace Org.BouncyCastle.Crypto.Digests
CopyIn(d);
}
-
}
}
diff --git a/crypto/src/crypto/digests/Sha512tDigest.cs b/crypto/src/crypto/digests/Sha512tDigest.cs
index 2caefa763..939dbda4f 100644
--- a/crypto/src/crypto/digests/Sha512tDigest.cs
+++ b/crypto/src/crypto/digests/Sha512tDigest.cs
@@ -76,6 +76,26 @@ namespace Org.BouncyCastle.Crypto.Digests
return digestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ UInt64_To_BE(H1, output, 0, digestLength);
+ UInt64_To_BE(H2, output, 8, digestLength - 8);
+ UInt64_To_BE(H3, output, 16, digestLength - 16);
+ UInt64_To_BE(H4, output, 24, digestLength - 24);
+ UInt64_To_BE(H5, output, 32, digestLength - 32);
+ UInt64_To_BE(H6, output, 40, digestLength - 40);
+ UInt64_To_BE(H7, output, 48, digestLength - 48);
+ UInt64_To_BE(H8, output, 56, digestLength - 56);
+
+ Reset();
+
+ return digestLength;
+ }
+#endif
+
/**
* reset the chaining variables
*/
@@ -170,7 +190,32 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
- public override IMemoable Copy()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private static void UInt64_To_BE(ulong n, Span<byte> bs, int off, int max)
+ {
+ if (max > 0)
+ {
+ UInt32_To_BE((uint)(n >> 32), bs, off, max);
+
+ if (max > 4)
+ {
+ UInt32_To_BE((uint)n, bs, off + 4, max - 4);
+ }
+ }
+ }
+
+ private static void UInt32_To_BE(uint n, Span<byte> bs, int off, int max)
+ {
+ int num = System.Math.Min(4, max);
+ while (--num >= 0)
+ {
+ int shift = 8 * (3 - num);
+ bs[off + num] = (byte)(n >> shift);
+ }
+ }
+#endif
+
+ public override IMemoable Copy()
{
return new Sha512tDigest(this);
}
diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs
index 8d7a7d6e3..17d262261 100644
--- a/crypto/src/crypto/digests/ShakeDigest.cs
+++ b/crypto/src/crypto/digests/ShakeDigest.cs
@@ -77,6 +77,34 @@ namespace Org.BouncyCastle.Crypto.Digests
return outLen;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public override int DoFinal(Span<byte> output)
+ {
+ return OutputFinal(output[..GetDigestSize()]);
+ }
+
+ public virtual int OutputFinal(Span<byte> output)
+ {
+ int length = Output(output);
+
+ Reset();
+
+ return length;
+ }
+
+ public virtual int Output(Span<byte> output)
+ {
+ if (!squeezing)
+ {
+ AbsorbBits(0x0F, 4);
+ }
+
+ Squeeze(output);
+
+ return output.Length;
+ }
+#endif
+
/*
* TODO Possible API change to support partial-byte suffixes.
*/
diff --git a/crypto/src/crypto/digests/ShortenedDigest.cs b/crypto/src/crypto/digests/ShortenedDigest.cs
index 9e4d99e7b..9e9998560 100644
--- a/crypto/src/crypto/digests/ShortenedDigest.cs
+++ b/crypto/src/crypto/digests/ShortenedDigest.cs
@@ -1,5 +1,4 @@
using System;
-using Org.BouncyCastle.Crypto;
namespace Org.BouncyCastle.Crypto.Digests
{
@@ -58,7 +57,14 @@ namespace Org.BouncyCastle.Crypto.Digests
baseDigest.BlockUpdate(input, inOff, length);
}
- public int DoFinal(byte[] output, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ baseDigest.BlockUpdate(input);
+ }
+#endif
+
+ public int DoFinal(byte[] output, int outOff)
{
byte[] tmp = new byte[baseDigest.GetDigestSize()];
@@ -69,7 +75,20 @@ namespace Org.BouncyCastle.Crypto.Digests
return length;
}
- public void Reset()
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ Span<byte> tmp = stackalloc byte[baseDigest.GetDigestSize()];
+
+ baseDigest.DoFinal(tmp);
+
+ tmp[..length].CopyTo(output);
+
+ return length;
+ }
+#endif
+
+ public void Reset()
{
baseDigest.Reset();
}
diff --git a/crypto/src/crypto/digests/SkeinDigest.cs b/crypto/src/crypto/digests/SkeinDigest.cs
index 394f0acd5..3dba9ec75 100644
--- a/crypto/src/crypto/digests/SkeinDigest.cs
+++ b/crypto/src/crypto/digests/SkeinDigest.cs
@@ -5,7 +5,6 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Digests
{
-
/// <summary>
/// Implementation of the Skein parameterised hash function in 256, 512 and 1024 bit block sizes,
/// based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
@@ -111,5 +110,16 @@ namespace Org.BouncyCastle.Crypto.Digests
return engine.DoFinal(outBytes, outOff);
}
- }
-}
\ No newline at end of file
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ engine.Update(input);
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ return engine.DoFinal(output);
+ }
+#endif
+ }
+}
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
index a36ac8fe7..86aa3c938 100644
--- a/crypto/src/crypto/digests/SkeinEngine.cs
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -431,7 +431,7 @@ namespace Org.BouncyCastle.Crypto.Digests
currentOffset = 0;
}
- int toCopy = System.Math.Min((len - copied), currentBlock.Length - currentOffset);
+ int toCopy = System.Math.Min(len - copied, currentBlock.Length - currentOffset);
Array.Copy(value, offset + copied, currentBlock, currentOffset, toCopy);
copied += toCopy;
currentOffset += toCopy;
@@ -439,6 +439,32 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void Update(ReadOnlySpan<byte> input, ulong[] output)
+ {
+ /*
+ * Buffer complete blocks for the underlying Threefish cipher, only flushing when there
+ * are subsequent bytes (last block must be processed in doFinal() with final=true set).
+ */
+ int copied = 0, len = input.Length;
+ while (len > copied)
+ {
+ if (currentOffset == currentBlock.Length)
+ {
+ ProcessBlock(output);
+ tweak.First = false;
+ currentOffset = 0;
+ }
+
+ int toCopy = System.Math.Min(len - copied, currentBlock.Length - currentOffset);
+ input.Slice(copied, toCopy).CopyTo(currentBlock.AsSpan(currentOffset));
+ copied += toCopy;
+ currentOffset += toCopy;
+ tweak.AdvancePosition(toCopy);
+ }
+ }
+#endif
+
private void ProcessBlock(ulong[] output)
{
engine.threefish.Init(true, engine.chain, tweak.GetWords());
@@ -735,6 +761,14 @@ namespace Org.BouncyCastle.Crypto.Digests
ubi.Update(inBytes, inOff, len, chain);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void Update(ReadOnlySpan<byte> input)
+ {
+ CheckInitialised();
+ ubi.Update(input, chain);
+ }
+#endif
+
public int DoFinal(byte[] outBytes, int outOff)
{
CheckInitialised();
@@ -770,6 +804,42 @@ namespace Org.BouncyCastle.Crypto.Digests
return outputSizeBytes;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ CheckInitialised();
+ if (output.Length < outputSizeBytes)
+ throw new DataLengthException("Output span is too short to hold output");
+
+ // Finalise message block
+ UbiFinal();
+
+ // Process additional post-message parameters
+ if (postMessageParameters != null)
+ {
+ for (int i = 0; i < postMessageParameters.Length; i++)
+ {
+ Parameter param = postMessageParameters[i];
+ UbiComplete(param.Type, param.Value);
+ }
+ }
+
+ // Perform the output transform
+ int blockSize = BlockSize;
+ int blocksRequired = (outputSizeBytes + blockSize - 1) / blockSize;
+ for (int i = 0; i < blocksRequired; i++)
+ {
+ int toWrite = System.Math.Min(blockSize, outputSizeBytes - (i * blockSize));
+ //Output((ulong)i, outBytes, outOff + (i * blockSize), toWrite);
+ Output((ulong)i, output[(i * blockSize)..], toWrite);
+ }
+
+ Reset();
+
+ return outputSizeBytes;
+ }
+#endif
+
private void Output(ulong outputSequence, byte[] outBytes, int outOff, int outputBytes)
{
byte[] currentBytes = new byte[8];
@@ -796,5 +866,34 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void Output(ulong outputSequence, Span<byte> output, int outputBytes)
+ {
+ Span<byte> currentBytes = stackalloc byte[8];
+ Pack.UInt64_To_LE(outputSequence, currentBytes);
+
+ // Output is a sequence of UBI invocations all of which use and preserve the pre-output state
+ ulong[] outputWords = new ulong[chain.Length];
+ UbiInit(PARAM_TYPE_OUTPUT);
+ this.ubi.Update(currentBytes, outputWords);
+ ubi.DoFinal(outputWords);
+
+ int wordsRequired = (outputBytes + 8 - 1) / 8;
+ for (int i = 0; i < wordsRequired; i++)
+ {
+ int toWrite = System.Math.Min(8, outputBytes - (i * 8));
+ if (toWrite == 8)
+ {
+ Pack.UInt64_To_LE(outputWords[i], output[(i * 8)..]);
+ }
+ else
+ {
+ Pack.UInt64_To_LE(outputWords[i], currentBytes);
+ currentBytes[..toWrite].CopyTo(output[(i * 8)..]);
+ }
+ }
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/digests/TigerDigest.cs b/crypto/src/crypto/digests/TigerDigest.cs
index a452d3f0b..d83e905db 100644
--- a/crypto/src/crypto/digests/TigerDigest.cs
+++ b/crypto/src/crypto/digests/TigerDigest.cs
@@ -603,6 +603,20 @@ namespace Org.BouncyCastle.Crypto.Digests
bOff = 0;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void ProcessWord(ReadOnlySpan<byte> b)
+ {
+ x[xOff++] = (long)Pack.LE_To_UInt64(b);
+
+ if (xOff == x.Length)
+ {
+ ProcessBlock();
+ }
+
+ bOff = 0;
+ }
+#endif
+
public void Update(
byte input)
{
@@ -656,6 +670,47 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ int inOff = 0, length = input.Length;
+
+ //
+ // fill the current word
+ //
+ while ((bOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length >= 8)
+ {
+ ProcessWord(input[inOff..]);
+
+ inOff += 8;
+ length -= 8;
+ byteCount += 8;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+#endif
+
private void RoundABC(
long x,
long mul)
@@ -809,6 +864,21 @@ namespace Org.BouncyCastle.Crypto.Digests
return DigestLength;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ Finish();
+
+ Pack.UInt64_To_LE((ulong)a, output);
+ Pack.UInt64_To_LE((ulong)b, output[8..]);
+ Pack.UInt64_To_LE((ulong)c, output[16..]);
+
+ Reset();
+
+ return DigestLength;
+ }
+#endif
+
/**
* reset the chaining variables
*/
diff --git a/crypto/src/crypto/digests/TupleHash.cs b/crypto/src/crypto/digests/TupleHash.cs
index 98c2d2acf..43030d5d5 100644
--- a/crypto/src/crypto/digests/TupleHash.cs
+++ b/crypto/src/crypto/digests/TupleHash.cs
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Crypto.Digests
cshake.BlockUpdate(bytes, 0, bytes.Length);
}
- private void wrapUp(int outputSize)
+ private void WrapUp(int outputSize)
{
byte[] encOut = XofUtilities.RightEncode(outputSize * 8);
@@ -89,23 +89,14 @@ namespace Org.BouncyCastle.Crypto.Digests
public virtual int DoFinal(byte[] outBuf, int outOff)
{
- if (firstOutput)
- {
- wrapUp(GetDigestSize());
- }
-
- int rv = cshake.DoFinal(outBuf, outOff, GetDigestSize());
-
- Reset();
-
- return rv;
+ return DoFinal(outBuf, outOff, GetDigestSize());
}
public virtual int DoFinal(byte[] outBuf, int outOff, int outLen)
{
if (firstOutput)
{
- wrapUp(GetDigestSize());
+ WrapUp(GetDigestSize());
}
int rv = cshake.DoFinal(outBuf, outOff, outLen);
@@ -119,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Digests
{
if (firstOutput)
{
- wrapUp(0);
+ WrapUp(0);
}
return cshake.DoOutput(outBuf, outOff, outLen);
@@ -130,5 +121,41 @@ namespace Org.BouncyCastle.Crypto.Digests
cshake.Reset();
firstOutput = true;
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ XofUtilities.EncodeTo(cshake, input);
+ }
+
+ public virtual int DoFinal(Span<byte> output)
+ {
+ return OutputFinal(output[..GetDigestSize()]);
+ }
+
+ public virtual int OutputFinal(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ WrapUp(GetDigestSize());
+ }
+
+ int rv = cshake.OutputFinal(output);
+
+ Reset();
+
+ return rv;
+ }
+
+ public virtual int Output(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ WrapUp(0);
+ }
+
+ return cshake.Output(output);
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/digests/WhirlpoolDigest.cs b/crypto/src/crypto/digests/WhirlpoolDigest.cs
index b28e259f3..73d389a3c 100644
--- a/crypto/src/crypto/digests/WhirlpoolDigest.cs
+++ b/crypto/src/crypto/digests/WhirlpoolDigest.cs
@@ -162,6 +162,20 @@ namespace Org.BouncyCastle.Crypto.Digests
return GetDigestSize();
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ // sets output[0..DIGEST_LENGTH_BYTES]
+ Finish();
+
+ Pack.UInt64_To_BE(_hash, output);
+
+ Reset();
+
+ return GetDigestSize();
+ }
+#endif
+
/**
* Reset the chaining variables
*/
@@ -276,6 +290,16 @@ namespace Org.BouncyCastle.Crypto.Digests
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ for (int i = 0; i < input.Length; ++i)
+ {
+ Update(input[i]);
+ }
+ }
+#endif
+
private void Finish()
{
/*
diff --git a/crypto/src/crypto/digests/XofUtils.cs b/crypto/src/crypto/digests/XofUtils.cs
index a4d6622b3..a1242f987 100644
--- a/crypto/src/crypto/digests/XofUtils.cs
+++ b/crypto/src/crypto/digests/XofUtils.cs
@@ -28,6 +28,26 @@ namespace Org.BouncyCastle.Crypto.Digests
return b;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal static int LeftEncode(long length, Span<byte> lengthEncoding)
+ {
+ byte n = 1;
+
+ long v = length;
+ while ((v >>= 8) != 0)
+ {
+ n++;
+ }
+
+ lengthEncoding[0] = n;
+ for (int i = 1; i <= n; i++)
+ {
+ lengthEncoding[i] = (byte)(length >> (8 * (n - i)));
+ }
+ return 1 + n;
+ }
+#endif
+
internal static byte[] RightEncode(long strLen)
{
byte n = 1;
@@ -50,6 +70,26 @@ namespace Org.BouncyCastle.Crypto.Digests
return b;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal static int RightEncode(long length, Span<byte> lengthEncoding)
+ {
+ byte n = 1;
+
+ long v = length;
+ while ((v >>= 8) != 0)
+ {
+ n++;
+ }
+
+ lengthEncoding[n] = n;
+ for (int i = 0; i < n; i++)
+ {
+ lengthEncoding[i] = (byte)(length >> (8 * (n - i - 1)));
+ }
+ return n + 1;
+ }
+#endif
+
internal static byte[] Encode(byte X)
{
return Arrays.Concatenate(LeftEncode(8), new byte[] { X });
@@ -63,5 +103,15 @@ namespace Org.BouncyCastle.Crypto.Digests
}
return Arrays.Concatenate(LeftEncode(len * 8), Arrays.CopyOfRange(inBuf, inOff, inOff + len));
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal static void EncodeTo(IDigest digest, ReadOnlySpan<byte> buf)
+ {
+ Span<byte> lengthEncoding = stackalloc byte[9];
+ int count = LeftEncode(buf.Length * 8, lengthEncoding);
+ digest.BlockUpdate(lengthEncoding[..count]);
+ digest.BlockUpdate(buf);
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/macs/KMac.cs b/crypto/src/crypto/macs/KMac.cs
index 05031ac2f..ce6c9f701 100644
--- a/crypto/src/crypto/macs/KMac.cs
+++ b/crypto/src/crypto/macs/KMac.cs
@@ -39,6 +39,16 @@ namespace Org.BouncyCastle.Crypto.Macs
cshake.BlockUpdate(input, inOff, len);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("KMAC not initialized");
+
+ cshake.BlockUpdate(input);
+ }
+#endif
+
public int DoFinal(byte[] output, int outOff)
{
if (firstOutput)
@@ -58,6 +68,27 @@ namespace Org.BouncyCastle.Crypto.Macs
return rv;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("KMAC not initialized");
+
+ Span<byte> lengthEncoding = stackalloc byte[9];
+ int count = XofUtilities.RightEncode(GetMacSize() * 8, lengthEncoding);
+ cshake.BlockUpdate(lengthEncoding[..count]);
+ }
+
+ int rv = cshake.OutputFinal(output[..GetMacSize()]);
+
+ Reset();
+
+ return rv;
+ }
+#endif
+
public int DoFinal(byte[] output, int outOff, int outLen)
{
if (firstOutput)
@@ -77,6 +108,27 @@ namespace Org.BouncyCastle.Crypto.Macs
return rv;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int OutputFinal(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("KMAC not initialized");
+
+ Span<byte> lengthEncoding = stackalloc byte[9];
+ int count = XofUtilities.RightEncode(output.Length * 8, lengthEncoding);
+ cshake.BlockUpdate(lengthEncoding[..count]);
+ }
+
+ int rv = cshake.OutputFinal(output);
+
+ Reset();
+
+ return rv;
+ }
+#endif
+
public int DoOutput(byte[] output, int outOff, int outLen)
{
if (firstOutput)
@@ -94,6 +146,25 @@ namespace Org.BouncyCastle.Crypto.Macs
return cshake.DoOutput(output, outOff, outLen);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int Output(Span<byte> output)
+ {
+ if (firstOutput)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("KMAC not initialized");
+
+ Span<byte> lengthEncoding = stackalloc byte[9];
+ int count = XofUtilities.RightEncode(0, lengthEncoding);
+ cshake.BlockUpdate(lengthEncoding[..count]);
+
+ firstOutput = false;
+ }
+
+ return cshake.Output(output);
+ }
+#endif
+
public int GetByteLength()
{
return cshake.GetByteLength();
diff --git a/crypto/src/pqc/crypto/lms/LMSContext.cs b/crypto/src/pqc/crypto/lms/LMSContext.cs
index 35c33093b..2113184fe 100644
--- a/crypto/src/pqc/crypto/lms/LMSContext.cs
+++ b/crypto/src/pqc/crypto/lms/LMSContext.cs
@@ -124,5 +124,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
{
digest.Reset();
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public void BlockUpdate(ReadOnlySpan<byte> input)
+ {
+ digest.BlockUpdate(input);
+ }
+
+ public int DoFinal(Span<byte> output)
+ {
+ return digest.DoFinal(output);
+ }
+#endif
}
-}
\ No newline at end of file
+}
diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs
index 2c9e89277..035280fd6 100644
--- a/crypto/src/security/DigestUtilities.cs
+++ b/crypto/src/security/DigestUtilities.cs
@@ -266,9 +266,22 @@ namespace Org.BouncyCastle.Security
public static byte[] CalculateDigest(string algorithm, byte[] input)
{
IDigest digest = GetDigest(algorithm);
- digest.BlockUpdate(input, 0, input.Length);
- return DoFinal(digest);
+ return DoFinal(digest, input);
+ }
+
+ public static byte[] CalculateDigest(string algorithm, byte[] buf, int off, int len)
+ {
+ IDigest digest = GetDigest(algorithm);
+ return DoFinal(digest, buf, off, len);
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public static byte[] CalculateDigest(string algorithm, ReadOnlySpan<byte> buffer)
+ {
+ IDigest digest = GetDigest(algorithm);
+ return DoFinal(digest, buffer);
}
+#endif
public static byte[] DoFinal(IDigest digest)
{
@@ -282,5 +295,19 @@ namespace Org.BouncyCastle.Security
digest.BlockUpdate(input, 0, input.Length);
return DoFinal(digest);
}
+
+ public static byte[] DoFinal(IDigest digest, byte[] buf, int off, int len)
+ {
+ digest.BlockUpdate(buf, off, len);
+ return DoFinal(digest);
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public static byte[] DoFinal(IDigest digest, ReadOnlySpan<byte> buffer)
+ {
+ digest.BlockUpdate(buffer);
+ return DoFinal(digest);
+ }
+#endif
}
}
|