diff --git a/crypto/src/crypto/IMac.cs b/crypto/src/crypto/IMac.cs
index 3df4c354f..aa539b968 100644
--- a/crypto/src/crypto/IMac.cs
+++ b/crypto/src/crypto/IMac.cs
@@ -39,6 +39,14 @@ namespace Org.BouncyCastle.Crypto
/// <returns>the number of bytes written</returns>
int DoFinal(byte[] output, int outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// <summary>Perform final calculations, producing the result MAC.</summary>
+ /// <remarks>This call leaves the MAC reset.</remarks>
+ /// <param name="output">the span the MAC is to be copied into.</param>
+ /// <returns>the number of bytes written</returns>
+ int DoFinal(Span<byte> output);
+#endif
+
/// <summary>Reset the MAC back to its initial state.</summary>
void Reset();
}
diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index dbd696429..342dbd93d 100644
--- a/crypto/src/crypto/macs/CMac.cs
+++ b/crypto/src/crypto/macs/CMac.cs
@@ -233,10 +233,11 @@ namespace Org.BouncyCastle.Crypto.Macs
}
#endif
- public int DoFinal(
- byte[] outBytes,
- int outOff)
+ public int DoFinal(byte[] outBytes, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(outBytes.AsSpan(outOff));
+#else
int blockSize = cipher.GetBlockSize();
byte[] lu;
@@ -262,8 +263,40 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return macSize;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ byte[] lu;
+ if (bufOff == blockSize)
+ {
+ lu = Lu;
+ }
+ else
+ {
+ new ISO7816d4Padding().AddPadding(buf, bufOff);
+ lu = Lu2;
+ }
+
+ for (int i = 0; i < mac.Length; i++)
+ {
+ buf[i] ^= lu[i];
+ }
+
+ cipher.ProcessBlock(buf, mac);
+
+ mac.AsSpan(0, macSize).CopyTo(output);
+
+ Reset();
+
+ return macSize;
+ }
+#endif
+
/**
* Reset the mac generator.
*/
diff --git a/crypto/src/crypto/macs/CbcBlockCipherMac.cs b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
index de7a5f2e4..abf06170c 100644
--- a/crypto/src/crypto/macs/CbcBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
@@ -186,10 +186,11 @@ namespace Org.BouncyCastle.Crypto.Macs
}
#endif
- public int DoFinal(
- byte[] output,
- int outOff)
+ public int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
int blockSize = cipher.GetBlockSize();
if (padding == null)
@@ -218,9 +219,44 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return macSize;
+#endif
}
- /**
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ if (padding == null)
+ {
+ // pad with zeroes
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.ProcessBlock(buf, buf);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+ }
+
+ cipher.ProcessBlock(buf, buf);
+
+ buf.AsSpan(0, macSize).CopyTo(output);
+
+ Reset();
+
+ return macSize;
+ }
+#endif
+
+ /**
* Reset the mac generator.
*/
public void Reset()
diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
index b454306e3..a4d005700 100644
--- a/crypto/src/crypto/macs/CfbBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -354,6 +354,9 @@ namespace Org.BouncyCastle.Crypto.Macs
public int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
int blockSize = cipher.GetBlockSize();
// pad with zeroes
@@ -378,8 +381,39 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return macSize;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ // pad with zeroes
+ if (this.padding == null)
+ {
+ while (bufOff < blockSize)
+ {
+ Buffer[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ padding.AddPadding(Buffer, bufOff);
+ }
+
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ cipher.GetMacBlock(mac);
+
+ mac.AsSpan(0, macSize).CopyTo(output);
+
+ Reset();
+
+ return macSize;
+ }
+#endif
+
/**
* Reset the mac generator.
*/
diff --git a/crypto/src/crypto/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs
index 43fe7fb90..401d85a1e 100644
--- a/crypto/src/crypto/macs/DSTU7564Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -89,11 +89,11 @@ namespace Org.BouncyCastle.Crypto.Macs
public int DoFinal(byte[] output, int outOff)
{
- Check.OutputLength(output, outOff, macSize, "output buffer too short");
-
if (paddedKey == null)
throw new InvalidOperationException(AlgorithmName + " not initialised");
+ Check.OutputLength(output, outOff, macSize, "output buffer too short");
+
Pad();
engine.BlockUpdate(invertedKey, 0, invertedKey.Length);
@@ -103,6 +103,24 @@ namespace Org.BouncyCastle.Crypto.Macs
return engine.DoFinal(output, outOff);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ if (paddedKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.OutputLength(output, macSize, "output buffer too short");
+
+ Pad();
+
+ engine.BlockUpdate(invertedKey);
+
+ inputLength = 0;
+
+ return engine.DoFinal(output);
+ }
+#endif
+
public void Reset()
{
inputLength = 0;
diff --git a/crypto/src/crypto/macs/DSTU7624Mac.cs b/crypto/src/crypto/macs/DSTU7624Mac.cs
index 01c1f869c..8fecb1915 100644
--- a/crypto/src/crypto/macs/DSTU7624Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7624Mac.cs
@@ -177,19 +177,37 @@ namespace Org.BouncyCastle.Crypto.Macs
if (bufOff % buf.Length != 0)
throw new DataLengthException("Input must be a multiple of blocksize");
+ Check.OutputLength(output, outOff, macSize, "output buffer too short");
+
//Last block
Xor(c, 0, buf, 0, cTemp);
Xor(cTemp, 0, kDelta, 0, c);
engine.ProcessBlock(c, 0, c, 0);
- if (macSize + outOff > output.Length)
- throw new DataLengthException("Output buffer too short");
-
Array.Copy(c, 0, output, outOff, macSize);
return macSize;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ if (bufOff % buf.Length != 0)
+ throw new DataLengthException("Input must be a multiple of blocksize");
+
+ Check.OutputLength(output, macSize, "output buffer too short");
+
+ //Last block
+ Xor(c, 0, buf, 0, cTemp);
+ Xor(cTemp, 0, kDelta, 0, c);
+ engine.ProcessBlock(c, c);
+
+ c.AsSpan(0, macSize).CopyTo(output);
+
+ return macSize;
+ }
+#endif
+
public void Reset()
{
Arrays.Fill(c, (byte)0x00);
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
index e0a448dda..aa124bb04 100644
--- a/crypto/src/crypto/macs/GMac.cs
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -106,6 +106,17 @@ namespace Org.BouncyCastle.Crypto.Macs
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ // TODO[span] call cipher.DoFinal(Span<byte) when available
+ byte[] tmp = new byte[GetMacSize()];
+ int result = DoFinal(tmp, 0);
+ tmp.CopyTo(output);
+ return result;
+ }
+#endif
+
public void Reset()
{
cipher.Reset();
diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs
index 6a6907934..8c39fc6b0 100644
--- a/crypto/src/crypto/macs/GOST28147Mac.cs
+++ b/crypto/src/crypto/macs/GOST28147Mac.cs
@@ -283,6 +283,9 @@ namespace Org.BouncyCastle.Crypto.Macs
public int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
//padding with zero
while (bufOff < BlockSize)
{
@@ -307,8 +310,39 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return MacSize;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ //padding with zero
+ while (bufOff < BlockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+
+ byte[] sum = new byte[buf.Length];
+ if (firstStep)
+ {
+ firstStep = false;
+ Array.Copy(buf, 0, sum, 0, mac.Length);
+ }
+ else
+ {
+ Cm5Func(buf, 0, mac, sum);
+ }
+
+ Gost28147MacFunc(workingKey, sum, 0, mac, 0);
+
+ mac.AsSpan((mac.Length / 2) - MacSize, MacSize).CopyTo(output);
+
+ Reset();
+
+ return MacSize;
+ }
+#endif
+
public void Reset()
{
// Clear the buffer.
diff --git a/crypto/src/crypto/macs/HMac.cs b/crypto/src/crypto/macs/HMac.cs
index 389c03a23..3445a945b 100644
--- a/crypto/src/crypto/macs/HMac.cs
+++ b/crypto/src/crypto/macs/HMac.cs
@@ -108,12 +108,15 @@ namespace Org.BouncyCastle.Crypto.Macs
public virtual int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
digest.DoFinal(outputBuf, blockLength);
if (opadState != null)
{
((IMemoable)digest).Reset(opadState);
- digest.BlockUpdate(outputBuf, blockLength, digest.GetDigestSize());
+ digest.BlockUpdate(outputBuf, blockLength, digestSize);
}
else
{
@@ -134,8 +137,41 @@ namespace Org.BouncyCastle.Crypto.Macs
}
return len;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ digest.DoFinal(outputBuf.AsSpan(blockLength));
+
+ if (opadState != null)
+ {
+ ((IMemoable)digest).Reset(opadState);
+ digest.BlockUpdate(outputBuf.AsSpan(blockLength, digestSize));
+ }
+ else
+ {
+ digest.BlockUpdate(outputBuf);
+ }
+
+ int len = digest.DoFinal(output);
+
+ Array.Clear(outputBuf, blockLength, digestSize);
+
+ if (ipadState != null)
+ {
+ ((IMemoable)digest).Reset(ipadState);
+ }
+ else
+ {
+ digest.BlockUpdate(inputPad);
+ }
+
+ return len;
+ }
+#endif
+
/**
* Reset the mac generator.
*/
diff --git a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
index f516e9b96..40a68007e 100644
--- a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
+++ b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
@@ -246,10 +246,11 @@ namespace Org.BouncyCastle.Crypto.Macs
}
#endif
- public int DoFinal(
- byte[] output,
- int outOff)
+ public int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
int blockSize = cipher.GetBlockSize();
if (padding == null)
@@ -288,8 +289,53 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return macSize;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ if (padding == null)
+ {
+ // pad with zeroes
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.ProcessBlock(buf, mac);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+ }
+
+ cipher.ProcessBlock(buf, mac);
+
+ // Added to code from base class
+ DesEngine deseng = new DesEngine();
+
+ deseng.Init(false, this.lastKey2);
+ deseng.ProcessBlock(mac, mac);
+
+ deseng.Init(true, this.lastKey3);
+ deseng.ProcessBlock(mac, mac);
+ // ****
+
+ mac.AsSpan(0, macSize).CopyTo(output);
+
+ Reset();
+
+ return macSize;
+ }
+#endif
+
/**
* Reset the mac generator.
*/
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index 65fb8bf01..eb90e387e 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -328,7 +328,10 @@ namespace Org.BouncyCastle.Crypto.Macs
public int DoFinal(byte[] output, int outOff)
{
- Check.DataLength(output, outOff, BlockSize, "output buffer is too short.");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
+ Check.OutputLength(output, outOff, BlockSize, "output buffer is too short.");
if (currentBlockOffset > 0)
{
@@ -344,11 +347,7 @@ namespace Org.BouncyCastle.Crypto.Macs
h4 -= (1 << 24);
}
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- ProcessBlock(currentBlock);
-#else
ProcessBlock(currentBlock, 0);
-#endif
}
Debug.Assert(h4 >> 26 == 0);
@@ -372,8 +371,55 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return BlockSize;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ Check.OutputLength(output, BlockSize, "output buffer is too short.");
+
+ if (currentBlockOffset > 0)
+ {
+ // Process padded block
+ if (currentBlockOffset < BlockSize)
+ {
+ currentBlock[currentBlockOffset++] = 1;
+ while (currentBlockOffset < BlockSize)
+ {
+ currentBlock[currentBlockOffset++] = 0;
+ }
+
+ h4 -= (1 << 24);
+ }
+
+ ProcessBlock(currentBlock);
+ }
+
+ Debug.Assert(h4 >> 26 == 0);
+
+ //h0 += (h4 >> 26) * 5U + 5U; h4 &= 0x3ffffff;
+ h0 += 5U;
+ h1 += h0 >> 26; h0 &= 0x3ffffff;
+ h2 += h1 >> 26; h1 &= 0x3ffffff;
+ h3 += h2 >> 26; h2 &= 0x3ffffff;
+ h4 += h3 >> 26; h3 &= 0x3ffffff;
+
+ long c = ((int)(h4 >> 26) - 1) * 5;
+ c += (long)k0 + ((h0) | (h1 << 26));
+ Pack.UInt32_To_LE((uint)c, output); c >>= 32;
+ c += (long)k1 + ((h1 >> 6) | (h2 << 20));
+ Pack.UInt32_To_LE((uint)c, output[4..]); c >>= 32;
+ c += (long)k2 + ((h2 >> 12) | (h3 << 14));
+ Pack.UInt32_To_LE((uint)c, output[8..]); c >>= 32;
+ c += (long)k3 + ((h3 >> 18) | (h4 << 8));
+ Pack.UInt32_To_LE((uint)c, output[12..]);
+
+ Reset();
+ return BlockSize;
+ }
+#endif
+
public void Reset()
{
currentBlockOffset = 0;
diff --git a/crypto/src/crypto/macs/SipHash.cs b/crypto/src/crypto/macs/SipHash.cs
index fc0a66ed1..2e8a89e3d 100644
--- a/crypto/src/crypto/macs/SipHash.cs
+++ b/crypto/src/crypto/macs/SipHash.cs
@@ -190,6 +190,15 @@ namespace Org.BouncyCastle.Crypto.Macs
return 8;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ long result = DoFinal();
+ Pack.UInt64_To_LE((ulong)result, output);
+ return 8;
+ }
+#endif
+
public virtual void Reset()
{
v0 = k0 ^ 0x736f6d6570736575L;
diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs
index 6adc93ef9..aaf5b312d 100644
--- a/crypto/src/crypto/macs/SkeinMac.cs
+++ b/crypto/src/crypto/macs/SkeinMac.cs
@@ -120,5 +120,12 @@ namespace Org.BouncyCastle.Crypto.Macs
{
return engine.DoFinal(output, outOff);
}
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int DoFinal(Span<byte> output)
+ {
+ return engine.DoFinal(output);
+ }
+#endif
}
}
diff --git a/crypto/src/crypto/macs/VMPCMac.cs b/crypto/src/crypto/macs/VMPCMac.cs
index 76912f736..c2902179f 100644
--- a/crypto/src/crypto/macs/VMPCMac.cs
+++ b/crypto/src/crypto/macs/VMPCMac.cs
@@ -22,6 +22,9 @@ namespace Org.BouncyCastle.Crypto.Macs
public virtual int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
// Execute the Post-Processing Phase
for (int r = 1; r < 25; r++)
{
@@ -68,7 +71,60 @@ namespace Org.BouncyCastle.Crypto.Macs
Reset();
return M.Length;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ // Execute the Post-Processing Phase
+ for (int r = 1; r < 25; r++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+
+ x4 = P[(x4 + x3 + r) & 0xff];
+ x3 = P[(x3 + x2 + r) & 0xff];
+ x2 = P[(x2 + x1 + r) & 0xff];
+ x1 = P[(x1 + s + r) & 0xff];
+ T[g & 0x1f] = (byte)(T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte)(T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte)(T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte)(T[(g + 3) & 0x1f] ^ x4);
+ g = (byte)((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte)((n + 1) & 0xff);
+ }
+
+ // Input T to the IV-phase of the VMPC KSA
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ // Store 20 new outputs of the VMPC Stream Cipher input table M
+ byte[] M = new byte[20];
+ for (int i = 0; i < 20; i++)
+ {
+ s = P[(s + P[i & 0xff]) & 0xff];
+ M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+
+ byte temp = P[i & 0xff];
+ P[i & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ M.CopyTo(output);
+ Reset();
+
+ return M.Length;
}
+#endif
public virtual string AlgorithmName
{
|