diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-08-25 01:03:22 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2022-08-25 01:03:22 +0700 |
commit | 145e57023efdc09d757a21c421a938786c75c48a (patch) | |
tree | 685d516e56d6405080c197ecbb67f886893f3dd5 | |
parent | Span-based variant for IAeadCipher.ProcessAadBytes (diff) | |
download | BouncyCastle.NET-ed25519-145e57023efdc09d757a21c421a938786c75c48a.tar.xz |
Span-based variant for IMac.DoFinal
-rw-r--r-- | crypto/src/crypto/IMac.cs | 8 | ||||
-rw-r--r-- | crypto/src/crypto/macs/CMac.cs | 39 | ||||
-rw-r--r-- | crypto/src/crypto/macs/CbcBlockCipherMac.cs | 44 | ||||
-rw-r--r-- | crypto/src/crypto/macs/CfbBlockCipherMac.cs | 34 | ||||
-rw-r--r-- | crypto/src/crypto/macs/DSTU7564Mac.cs | 22 | ||||
-rw-r--r-- | crypto/src/crypto/macs/DSTU7624Mac.cs | 24 | ||||
-rw-r--r-- | crypto/src/crypto/macs/GMac.cs | 11 | ||||
-rw-r--r-- | crypto/src/crypto/macs/GOST28147Mac.cs | 34 | ||||
-rw-r--r-- | crypto/src/crypto/macs/HMac.cs | 38 | ||||
-rw-r--r-- | crypto/src/crypto/macs/ISO9797Alg3Mac.cs | 52 | ||||
-rw-r--r-- | crypto/src/crypto/macs/Poly1305.cs | 56 | ||||
-rw-r--r-- | crypto/src/crypto/macs/SipHash.cs | 9 | ||||
-rw-r--r-- | crypto/src/crypto/macs/SkeinMac.cs | 7 | ||||
-rw-r--r-- | crypto/src/crypto/macs/VMPCMac.cs | 56 |
14 files changed, 413 insertions, 21 deletions
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 { |