From e643cf1909bc27a1307a27f31ac5b981f9ba225a Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 24 Aug 2022 14:37:11 +0700 Subject: Span-based variant for IMac.BlockUpdate --- crypto/src/crypto/IMac.cs | 76 ++++----- crypto/src/crypto/digests/SkeinDigest.cs | 4 +- crypto/src/crypto/digests/SkeinEngine.cs | 6 +- crypto/src/crypto/macs/CMac.cs | 43 ++++- crypto/src/crypto/macs/CbcBlockCipherMac.cs | 45 ++++-- crypto/src/crypto/macs/CfbBlockCipherMac.cs | 51 ++++-- crypto/src/crypto/macs/DSTU7564Mac.cs | 11 ++ crypto/src/crypto/macs/DSTU7624Mac.cs | 196 ++++++++++++++--------- crypto/src/crypto/macs/GMac.cs | 20 ++- crypto/src/crypto/macs/GOST28147Mac.cs | 234 +++++++++++++++------------- crypto/src/crypto/macs/HMac.cs | 7 + crypto/src/crypto/macs/ISO9797Alg3Mac.cs | 38 ++++- crypto/src/crypto/macs/Poly1305.cs | 93 ++++++++++- crypto/src/crypto/macs/SipHash.cs | 46 ++++++ crypto/src/crypto/macs/SkeinMac.cs | 10 +- crypto/src/crypto/macs/VMPCMac.cs | 17 +- 16 files changed, 613 insertions(+), 284 deletions(-) diff --git a/crypto/src/crypto/IMac.cs b/crypto/src/crypto/IMac.cs index 03a86e8b6..3df4c354f 100644 --- a/crypto/src/crypto/IMac.cs +++ b/crypto/src/crypto/IMac.cs @@ -2,68 +2,44 @@ using System; namespace Org.BouncyCastle.Crypto { - /** - * The base interface for implementations of message authentication codes (MACs). - */ + /// The base interface for implementations of message authentication codes (MACs). public interface IMac { - /** - * Initialise the MAC. - * - * @param param the key and other data required by the MAC. - * @exception ArgumentException if the parameters argument is - * inappropriate. - */ + /// Initialise the MAC. + /// The key or other data required by the MAC. void Init(ICipherParameters parameters); - /** - * Return the name of the algorithm the MAC implements. - * - * @return the name of the algorithm the MAC implements. - */ + /// The algorithm name. string AlgorithmName { get; } - /** - * Return the block size for this MAC (in bytes). - * - * @return the block size for this MAC in bytes. - */ - int GetMacSize(); + /// Return the size, in bytes, of the MAC produced by this implementation. + /// the size, in bytes, of the MAC produced by this implementation. + int GetMacSize(); - /** - * add a single byte to the mac for processing. - * - * @param in the byte to be processed. - * @exception InvalidOperationException if the MAC is not initialised. - */ + /// Update the MAC with a single byte. + /// the input byte to be entered. void Update(byte input); - /** - * @param in the array containing the input. - * @param inOff the index in the array the data begins at. - * @param len the length of the input starting at inOff. - * @exception InvalidOperationException if the MAC is not initialised. - * @exception DataLengthException if there isn't enough data in in. - */ - void BlockUpdate(byte[] input, int inOff, int len); + /// Update the MAC with a block of bytes. + /// the byte array containing the data. + /// the offset into the byte array where the data starts. + /// the length of the data. + void BlockUpdate(byte[] input, int inOff, int inLen); - /** - * Compute the final stage of the MAC writing the output to the out - * parameter. - *

- * doFinal leaves the MAC in the same state it was after the last init. - *

- * @param out the array the MAC is to be output to. - * @param outOff the offset into the out buffer the output is to start at. - * @exception DataLengthException if there isn't enough space in out. - * @exception InvalidOperationException if the MAC is not initialised. - */ +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + /// Update the MAC with a span of bytes. + /// the span containing the data. + void BlockUpdate(ReadOnlySpan input); +#endif + + /// Perform final calculations, producing the result MAC. + /// This call leaves the MAC reset. + /// the byte array the MAC is to be copied into. + /// the offset into the byte array the MAC is to start at. + /// the number of bytes written int DoFinal(byte[] output, int outOff); - /** - * Reset the MAC. At the end of resetting the MAC should be in the - * in the same state it was after the last init (if there was one). - */ + /// Reset the MAC back to its initial state. void Reset(); } } diff --git a/crypto/src/crypto/digests/SkeinDigest.cs b/crypto/src/crypto/digests/SkeinDigest.cs index 3dba9ec75..d56c0e788 100644 --- a/crypto/src/crypto/digests/SkeinDigest.cs +++ b/crypto/src/crypto/digests/SkeinDigest.cs @@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Digests public void BlockUpdate(byte[] inBytes, int inOff, int len) { - engine.Update(inBytes, inOff, len); + engine.BlockUpdate(inBytes, inOff, len); } public int DoFinal(byte[] outBytes, int outOff) @@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Crypto.Digests #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public void BlockUpdate(ReadOnlySpan input) { - engine.Update(input); + engine.BlockUpdate(input); } public int DoFinal(Span output) diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs index 86aa3c938..2535f786a 100644 --- a/crypto/src/crypto/digests/SkeinEngine.cs +++ b/crypto/src/crypto/digests/SkeinEngine.cs @@ -752,17 +752,17 @@ namespace Org.BouncyCastle.Crypto.Digests public void Update(byte inByte) { singleByte[0] = inByte; - Update(singleByte, 0, 1); + BlockUpdate(singleByte, 0, 1); } - public void Update(byte[] inBytes, int inOff, int len) + public void BlockUpdate(byte[] inBytes, int inOff, int len) { CheckInitialised(); ubi.Update(inBytes, inOff, len, chain); } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER - public void Update(ReadOnlySpan input) + public void BlockUpdate(ReadOnlySpan input) { CheckInitialised(); ubi.Update(input, chain); diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs index 682c12bac..dbd696429 100644 --- a/crypto/src/crypto/macs/CMac.cs +++ b/crypto/src/crypto/macs/CMac.cs @@ -132,8 +132,7 @@ namespace Org.BouncyCastle.Crypto.Macs return ret; } - public void Init( - ICipherParameters parameters) + public void Init(ICipherParameters parameters) { if (parameters is KeyParameter) { @@ -159,8 +158,7 @@ namespace Org.BouncyCastle.Crypto.Macs return macSize; } - public void Update( - byte input) + public void Update(byte input) { if (bufOff == buf.Length) { @@ -171,14 +169,14 @@ namespace Org.BouncyCastle.Crypto.Macs buf[bufOff++] = input; } - public void BlockUpdate( - byte[] inBytes, - int inOff, - int len) + public void BlockUpdate(byte[] inBytes, int inOff, int len) { if (len < 0) throw new ArgumentException("Can't have a negative input length!"); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(inBytes.AsSpan(inOff, len)); +#else int blockSize = cipher.GetBlockSize(); int gapLen = blockSize - bufOff; @@ -204,8 +202,37 @@ namespace Org.BouncyCastle.Crypto.Macs Array.Copy(inBytes, inOff, buf, bufOff, len); bufOff += len; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int blockSize = cipher.GetBlockSize(); + int gapLen = blockSize - bufOff; + + if (input.Length > gapLen) + { + input[..gapLen].CopyTo(buf.AsSpan(bufOff)); + + cipher.ProcessBlock(buf, mac); + + bufOff = 0; + input = input[gapLen..]; + + while (input.Length > blockSize) + { + cipher.ProcessBlock(input, mac); + input = input[blockSize..]; + } + } + + input.CopyTo(buf.AsSpan(bufOff)); + + bufOff += input.Length; + } +#endif + public int DoFinal( byte[] outBytes, int outOff) diff --git a/crypto/src/crypto/macs/CbcBlockCipherMac.cs b/crypto/src/crypto/macs/CbcBlockCipherMac.cs index 146e16aa8..de7a5f2e4 100644 --- a/crypto/src/crypto/macs/CbcBlockCipherMac.cs +++ b/crypto/src/crypto/macs/CbcBlockCipherMac.cs @@ -99,8 +99,7 @@ namespace Org.BouncyCastle.Crypto.Macs get { return cipher.AlgorithmName; } } - public void Init( - ICipherParameters parameters) + public void Init(ICipherParameters parameters) { Reset(); @@ -112,8 +111,7 @@ namespace Org.BouncyCastle.Crypto.Macs return macSize; } - public void Update( - byte input) + public void Update(byte input) { if (bufOff == buf.Length) { @@ -124,15 +122,15 @@ namespace Org.BouncyCastle.Crypto.Macs buf[bufOff++] = input; } - public void BlockUpdate( - byte[] input, - int inOff, - int len) + public void BlockUpdate(byte[] input, int inOff, int len) { if (len < 0) throw new ArgumentException("Can't have a negative input length!"); - int blockSize = cipher.GetBlockSize(); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(inOff, len)); +#else + int blockSize = cipher.GetBlockSize(); int gapLen = blockSize - bufOff; if (len > gapLen) @@ -157,7 +155,36 @@ namespace Org.BouncyCastle.Crypto.Macs Array.Copy(input, inOff, buf, bufOff, len); bufOff += len; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int blockSize = cipher.GetBlockSize(); + int gapLen = blockSize - bufOff; + + if (input.Length > gapLen) + { + input[..gapLen].CopyTo(buf.AsSpan(bufOff)); + + cipher.ProcessBlock(buf, buf); + + bufOff = 0; + input = input[gapLen..]; + + while (input.Length > blockSize) + { + cipher.ProcessBlock(input, buf); + input = input[blockSize..]; + } + } + + input.CopyTo(buf.AsSpan(bufOff)); + + bufOff += input.Length; } +#endif public int DoFinal( byte[] output, diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs index e10bb438d..b454306e3 100644 --- a/crypto/src/crypto/macs/CfbBlockCipherMac.cs +++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs @@ -263,8 +263,7 @@ namespace Org.BouncyCastle.Crypto.Macs get { return cipher.AlgorithmName; } } - public void Init( - ICipherParameters parameters) + public void Init(ICipherParameters parameters) { Reset(); @@ -276,8 +275,7 @@ namespace Org.BouncyCastle.Crypto.Macs return macSize; } - public void Update( - byte input) + public void Update(byte input) { if (bufOff == Buffer.Length) { @@ -288,15 +286,15 @@ namespace Org.BouncyCastle.Crypto.Macs Buffer[bufOff++] = input; } - public void BlockUpdate( - byte[] input, - int inOff, - int len) + public void BlockUpdate(byte[] input, int inOff, int len) { if (len < 0) throw new ArgumentException("Can't have a negative input length!"); - int blockSize = cipher.GetBlockSize(); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(inOff, len)); +#else + int blockSize = cipher.GetBlockSize(); int resultLen = 0; int gapLen = blockSize - bufOff; @@ -322,11 +320,39 @@ namespace Org.BouncyCastle.Crypto.Macs Array.Copy(input, inOff, Buffer, bufOff, len); bufOff += len; +#endif } - public int DoFinal( - byte[] output, - int outOff) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int blockSize = cipher.GetBlockSize(); + int resultLen = 0; + int gapLen = blockSize - bufOff; + + if (input.Length > gapLen) + { + input[..gapLen].CopyTo(Buffer.AsSpan(bufOff)); + + resultLen += cipher.ProcessBlock(Buffer, mac); + + bufOff = 0; + input = input[gapLen..]; + + while (input.Length > blockSize) + { + resultLen += cipher.ProcessBlock(input, mac); + input = input[blockSize..]; + } + } + + input.CopyTo(Buffer.AsSpan(bufOff)); + + bufOff += input.Length; + } +#endif + + public int DoFinal(byte[] output, int outOff) { int blockSize = cipher.GetBlockSize(); @@ -367,5 +393,4 @@ namespace Org.BouncyCastle.Crypto.Macs cipher.Reset(); } } - } diff --git a/crypto/src/crypto/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs index fc905cc99..43fe7fb90 100644 --- a/crypto/src/crypto/macs/DSTU7564Mac.cs +++ b/crypto/src/crypto/macs/DSTU7564Mac.cs @@ -70,6 +70,17 @@ namespace Org.BouncyCastle.Crypto.Macs inputLength += (ulong)len; } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + if (paddedKey == null) + throw new InvalidOperationException(AlgorithmName + " not initialised"); + + engine.BlockUpdate(input); + inputLength += (ulong)input.Length; + } +#endif + public void Update(byte input) { engine.Update(input); diff --git a/crypto/src/crypto/macs/DSTU7624Mac.cs b/crypto/src/crypto/macs/DSTU7624Mac.cs index 953d8164f..01c1f869c 100644 --- a/crypto/src/crypto/macs/DSTU7624Mac.cs +++ b/crypto/src/crypto/macs/DSTU7624Mac.cs @@ -1,87 +1,89 @@ using System; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; - +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Macs { - /** + /** * implementation of DSTU 7624 MAC */ - public class Dstu7624Mac : IMac - { - private int macSize; - - private Dstu7624Engine engine; - private int blockSize; + public class Dstu7624Mac : IMac + { + private int macSize; + + private Dstu7624Engine engine; + private int blockSize; + + private byte[] c, cTemp, kDelta; + private byte[] buf; + private int bufOff; + + public Dstu7624Mac(int blockSizeBits, int q) + { + engine = new Dstu7624Engine(blockSizeBits); + + blockSize = blockSizeBits / 8; - private byte[] c, cTemp, kDelta; - private byte[] buf; - private int bufOff; + macSize = q / 8; - public Dstu7624Mac(int blockSizeBits, int q) - { - engine = new Dstu7624Engine(blockSizeBits); + c = new byte[blockSize]; - blockSize = blockSizeBits / 8; + cTemp = new byte[blockSize]; - macSize = q / 8; + kDelta = new byte[blockSize]; + buf = new byte[blockSize]; + } + + public void Init(ICipherParameters parameters) + { + if (parameters is KeyParameter) + { + engine.Init(true, (KeyParameter)parameters); + + engine.ProcessBlock(kDelta, 0, kDelta, 0); + } + else + { + throw new ArgumentException("invalid parameter passed to Dstu7624Mac init - " + + Platform.GetTypeName(parameters)); + } + } - c = new byte[blockSize]; - - cTemp = new byte[blockSize]; + public string AlgorithmName + { + get { return "Dstu7624Mac"; } + } - kDelta = new byte[blockSize]; - buf = new byte[blockSize]; + public int GetMacSize() + { + return macSize; } - public void Init(ICipherParameters parameters) - { - if (parameters is KeyParameter) - { - engine.Init(true, (KeyParameter)parameters); - - engine.ProcessBlock(kDelta, 0, kDelta, 0); - } - else - { - throw new ArgumentException("invalid parameter passed to Dstu7624Mac init - " - + Platform.GetTypeName(parameters)); - } - } - - public string AlgorithmName - { - get { return "Dstu7624Mac"; } - } - - public int GetMacSize() - { - return macSize; - } - - public void Update(byte input) - { + public void Update(byte input) + { if (bufOff == buf.Length) { - processBlock(buf, 0); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ProcessBlock(buf); +#else + ProcessBlock(buf, 0); +#endif bufOff = 0; } buf[bufOff++] = input; } - public void BlockUpdate(byte[] input, int inOff, int len) - { + public void BlockUpdate(byte[] input, int inOff, int len) + { if (len < 0) - { - throw new ArgumentException( - "Can't have a negative input length!"); - } + throw new ArgumentException("Can't have a negative input length!"); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(inOff, len)); +#else int blockSize = engine.GetBlockSize(); int gapLen = blockSize - bufOff; @@ -89,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Macs { Array.Copy(input, inOff, buf, bufOff, gapLen); - processBlock(buf, 0); + ProcessBlock(buf, 0); bufOff = 0; len -= gapLen; @@ -97,7 +99,7 @@ namespace Org.BouncyCastle.Crypto.Macs while (len > blockSize) { - processBlock(input, inOff); + ProcessBlock(input, inOff); len -= blockSize; inOff += blockSize; @@ -107,29 +109,73 @@ namespace Org.BouncyCastle.Crypto.Macs Array.Copy(input, inOff, buf, bufOff, len); bufOff += len; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int blockSize = engine.GetBlockSize(); + int gapLen = blockSize - bufOff; + + if (input.Length > gapLen) + { + input[..gapLen].CopyTo(buf.AsSpan(bufOff)); + + ProcessBlock(buf); + + bufOff = 0; + input = input[gapLen..]; + + while (input.Length > blockSize) + { + ProcessBlock(input); + input = input[blockSize..]; + } + } + + input.CopyTo(buf.AsSpan(bufOff)); + + bufOff += input.Length; + } +#endif + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void ProcessBlock(ReadOnlySpan input) + { + Xor(c, input, cTemp); + + engine.ProcessBlock(cTemp, c); } - private void processBlock(byte[] input, int inOff) + private void Xor(ReadOnlySpan c, ReadOnlySpan input, Span xorResult) + { + for (int byteIndex = 0; byteIndex < blockSize; byteIndex++) + { + xorResult[byteIndex] = (byte)(c[byteIndex] ^ input[byteIndex]); + } + } +#else + private void ProcessBlock(byte[] input, int inOff) { Xor(c, 0, input, inOff, cTemp); engine.ProcessBlock(cTemp, 0, c, 0); } +#endif private void Xor(byte[] c, int cOff, byte[] input, int inOff, byte[] xorResult) - { - for (int byteIndex = 0; byteIndex < blockSize; byteIndex++) - { - xorResult[byteIndex] = (byte)(c[byteIndex + cOff] ^ input[byteIndex + inOff]); - } - } - - public int DoFinal(byte[] output, int outOff) - { - if (bufOff % buf.Length != 0) + { + for (int byteIndex = 0; byteIndex < blockSize; byteIndex++) { - throw new DataLengthException("Input must be a multiple of blocksize"); + xorResult[byteIndex] = (byte)(c[byteIndex + cOff] ^ input[byteIndex + inOff]); } + } + + public int DoFinal(byte[] output, int outOff) + { + if (bufOff % buf.Length != 0) + throw new DataLengthException("Input must be a multiple of blocksize"); //Last block Xor(c, 0, buf, 0, cTemp); @@ -137,17 +183,15 @@ namespace Org.BouncyCastle.Crypto.Macs 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; } - public void Reset() - { + public void Reset() + { Arrays.Fill(c, (byte)0x00); Arrays.Fill(cTemp, (byte)0x00); Arrays.Fill(kDelta, (byte)0x00); @@ -156,5 +200,5 @@ namespace Org.BouncyCastle.Crypto.Macs engine.ProcessBlock(kDelta, 0, kDelta, 0); bufOff = 0; } - } + } } diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs index 0554c44f0..804097b3b 100644 --- a/crypto/src/crypto/macs/GMac.cs +++ b/crypto/src/crypto/macs/GMac.cs @@ -52,10 +52,8 @@ namespace Org.BouncyCastle.Crypto.Macs /// public void Init(ICipherParameters parameters) { - if (parameters is ParametersWithIV) + if (parameters is ParametersWithIV param) { - ParametersWithIV param = (ParametersWithIV)parameters; - byte[] iv = param.GetIV(); KeyParameter keyParam = (KeyParameter)param.Parameters; @@ -88,6 +86,22 @@ namespace Org.BouncyCastle.Crypto.Macs cipher.ProcessAadBytes(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + // TODO[span] Add span-based variant of ProcessAadBytes + byte[] tmp = new byte[64]; + while (input.Length > 64) + { + input[..64].CopyTo(tmp); + input = input[64..]; + cipher.ProcessAadBytes(tmp, 0, 64); + } + input.CopyTo(tmp); + cipher.ProcessAadBytes(tmp, 0, input.Length); + } +#endif + public int DoFinal(byte[] output, int outOff) { try diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs index 33c2d67ee..6a6907934 100644 --- a/crypto/src/crypto/macs/GOST28147Mac.cs +++ b/crypto/src/crypto/macs/GOST28147Mac.cs @@ -1,7 +1,7 @@ using System; -using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Macs @@ -9,10 +9,11 @@ namespace Org.BouncyCastle.Crypto.Macs /** * implementation of GOST 28147-89 MAC */ - public class Gost28147Mac : IMac + public class Gost28147Mac + : IMac { - private const int blockSize = 8; - private const int macSize = 4; + private const int BlockSize = 8; + private const int MacSize = 4; private int bufOff; private byte[] buf; private byte[] mac; @@ -36,8 +37,8 @@ namespace Org.BouncyCastle.Crypto.Macs public Gost28147Mac() { - mac = new byte[blockSize]; - buf = new byte[blockSize]; + mac = new byte[BlockSize]; + buf = new byte[BlockSize]; bufOff = 0; } @@ -50,22 +51,19 @@ namespace Org.BouncyCastle.Crypto.Macs int[] key = new int[8]; for(int i=0; i!=8; i++) { - key[i] = bytesToint(userKey,i*4); + key[i] = (int)Pack.LE_To_UInt32(userKey, i * 4); } return key; } - public void Init( - ICipherParameters parameters) + public void Init(ICipherParameters parameters) { Reset(); - buf = new byte[blockSize]; + buf = new byte[BlockSize]; macIV = null; - if (parameters is ParametersWithSBox) + if (parameters is ParametersWithSBox param) { - ParametersWithSBox param = (ParametersWithSBox)parameters; - // // Set the S-Box // @@ -79,17 +77,15 @@ namespace Org.BouncyCastle.Crypto.Macs workingKey = GenerateWorkingKey(((KeyParameter)param.Parameters).GetKey()); } } - else if (parameters is KeyParameter) + else if (parameters is KeyParameter keyParameter) { - workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey()); + workingKey = GenerateWorkingKey(keyParameter.GetKey()); } - else if (parameters is ParametersWithIV) + else if (parameters is ParametersWithIV ivParam) { - ParametersWithIV p = (ParametersWithIV)parameters; - - workingKey = GenerateWorkingKey(((KeyParameter)p.Parameters).GetKey()); - Array.Copy(p.GetIV(), 0, mac, 0, mac.Length); - macIV = p.GetIV(); // don't skip the initial CM5Func + workingKey = GenerateWorkingKey(((KeyParameter)ivParam.Parameters).GetKey()); + macIV = ivParam.GetIV(); // don't skip the initial CM5Func + Array.Copy(macIV, 0, mac, 0, mac.Length); } else { @@ -105,10 +101,10 @@ namespace Org.BouncyCastle.Crypto.Macs public int GetMacSize() { - return macSize; + return MacSize; } - private int gost28147_mainStep(int n1, int key) + private int Gost28147_mainStep(int n1, int key) { int cm = (key + n1); // CM1 @@ -130,177 +126,187 @@ namespace Org.BouncyCastle.Crypto.Macs return omLeft | omRight; } - private void gost28147MacFunc( + private void Gost28147MacFunc( int[] workingKey, byte[] input, int inOff, byte[] output, int outOff) { - int N1, N2, tmp; //tmp -> for saving N1 - N1 = bytesToint(input, inOff); - N2 = bytesToint(input, inOff + 4); + int N1 = (int)Pack.LE_To_UInt32(input, inOff); + int N2 = (int)Pack.LE_To_UInt32(input, inOff + 4); + int tmp; //tmp -> for saving N1 for (int k = 0; k < 2; k++) // 1-16 steps { for (int j = 0; j < 8; j++) { tmp = N1; - N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2 + N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2 N2 = tmp; } } - intTobytes(N1, output, outOff); - intTobytes(N2, output, outOff + 4); - } - - //array of bytes to type int - private static int bytesToint( - byte[] input, - int inOff) - { - return (int)((input[inOff + 3] << 24) & 0xff000000) + ((input[inOff + 2] << 16) & 0xff0000) - + ((input[inOff + 1] << 8) & 0xff00) + (input[inOff] & 0xff); - } - - //int to array of bytes - private static void intTobytes( - int num, - byte[] output, - int outOff) - { - output[outOff + 3] = (byte)(num >> 24); - output[outOff + 2] = (byte)(num >> 16); - output[outOff + 1] = (byte)(num >> 8); - output[outOff] = (byte)num; - } - - private static byte[] CM5func( - byte[] buf, - int bufOff, - byte[] mac) - { - byte[] sum = new byte[buf.Length - bufOff]; - - Array.Copy(buf, bufOff, sum, 0, mac.Length); - - for (int i = 0; i != mac.Length; i++) - { - sum[i] = (byte)(sum[i] ^ mac[i]); - } - - return sum; + Pack.UInt32_To_LE((uint)N1, output, outOff); + Pack.UInt32_To_LE((uint)N2, output, outOff + 4); } - public void Update( - byte input) + public void Update(byte input) { if (bufOff == buf.Length) { - byte[] sumbuf = new byte[buf.Length]; - Array.Copy(buf, 0, sumbuf, 0, mac.Length); - + byte[] sum = new byte[buf.Length]; if (firstStep) { firstStep = false; if (macIV != null) { - sumbuf = CM5func(buf, 0, macIV); + Cm5Func(buf, 0, macIV, sum); } - } + else + { + Array.Copy(buf, 0, sum, 0, mac.Length); + } + } else { - sumbuf = CM5func(buf, 0, mac); + Cm5Func(buf, 0, mac, sum); } - gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + Gost28147MacFunc(workingKey, sum, 0, mac, 0); bufOff = 0; } buf[bufOff++] = input; } - public void BlockUpdate( - byte[] input, - int inOff, - int len) + public void BlockUpdate(byte[] input, int inOff, int len) { if (len < 0) throw new ArgumentException("Can't have a negative input length!"); - int gapLen = blockSize - bufOff; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(inOff, len)); +#else + int gapLen = BlockSize - bufOff; if (len > gapLen) { Array.Copy(input, inOff, buf, bufOff, gapLen); - byte[] sumbuf = new byte[buf.Length]; - Array.Copy(buf, 0, sumbuf, 0, mac.Length); - + byte[] sum = new byte[buf.Length]; if (firstStep) { firstStep = false; if (macIV != null) { - sumbuf = CM5func(buf, 0, macIV); + Cm5Func(buf, 0, macIV, sum); } - } + else + { + Array.Copy(buf, 0, sum, 0, mac.Length); + } + } else { - sumbuf = CM5func(buf, 0, mac); + Cm5Func(buf, 0, mac, sum); } - gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + Gost28147MacFunc(workingKey, sum, 0, mac, 0); bufOff = 0; len -= gapLen; inOff += gapLen; - while (len > blockSize) + while (len > BlockSize) { - sumbuf = CM5func(input, inOff, mac); - gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + Cm5Func(input, inOff, mac, sum); + Gost28147MacFunc(workingKey, sum, 0, mac, 0); - len -= blockSize; - inOff += blockSize; + len -= BlockSize; + inOff += BlockSize; } } Array.Copy(input, inOff, buf, bufOff, len); bufOff += len; +#endif } - public int DoFinal( - byte[] output, - int outOff) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int gapLen = BlockSize - bufOff; + + if (input.Length > gapLen) + { + input[..gapLen].CopyTo(buf.AsSpan(bufOff)); + + byte[] sum = new byte[buf.Length]; + if (firstStep) + { + firstStep = false; + if (macIV != null) + { + Cm5Func(buf, macIV, sum); + } + else + { + Array.Copy(buf, 0, sum, 0, mac.Length); + } + } + else + { + Cm5Func(buf, mac, sum); + } + + Gost28147MacFunc(workingKey, sum, 0, mac, 0); + + bufOff = 0; + input = input[gapLen..]; + + while (input.Length > BlockSize) + { + Cm5Func(input, mac, sum); + Gost28147MacFunc(workingKey, sum, 0, mac, 0); + + input = input[BlockSize..]; + } + } + + input.CopyTo(buf.AsSpan(bufOff)); + + bufOff += input.Length; + } +#endif + + public int DoFinal(byte[] output, int outOff) { //padding with zero - while (bufOff < blockSize) + while (bufOff < BlockSize) { buf[bufOff++] = 0; } - byte[] sumbuf = new byte[buf.Length]; - Array.Copy(buf, 0, sumbuf, 0, mac.Length); - + byte[] sum = new byte[buf.Length]; if (firstStep) { firstStep = false; + Array.Copy(buf, 0, sum, 0, mac.Length); } else { - sumbuf = CM5func(buf, 0, mac); + Cm5Func(buf, 0, mac, sum); } - gost28147MacFunc(workingKey, sumbuf, 0, mac, 0); + Gost28147MacFunc(workingKey, sum, 0, mac, 0); - Array.Copy(mac, (mac.Length/2)-macSize, output, outOff, macSize); + Array.Copy(mac, (mac.Length/2)-MacSize, output, outOff, MacSize); Reset(); - return macSize; + return MacSize; } public void Reset() @@ -311,5 +317,23 @@ namespace Org.BouncyCastle.Crypto.Macs firstStep = true; } + + private static void Cm5Func(byte[] buf, int bufOff, byte[] mac, byte[] sum) + { + for (int i = 0; i < BlockSize; ++i) + { + sum[i] = (byte)(buf[bufOff + i] ^ mac[i]); + } + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private static void Cm5Func(ReadOnlySpan buffer, ReadOnlySpan mac, Span sum) + { + for (int i = 0; i < BlockSize; ++i) + { + sum[i] = (byte)(buffer[i] ^ mac[i]); + } + } +#endif } } diff --git a/crypto/src/crypto/macs/HMac.cs b/crypto/src/crypto/macs/HMac.cs index a717ce4f7..389c03a23 100644 --- a/crypto/src/crypto/macs/HMac.cs +++ b/crypto/src/crypto/macs/HMac.cs @@ -99,6 +99,13 @@ namespace Org.BouncyCastle.Crypto.Macs digest.BlockUpdate(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual void BlockUpdate(ReadOnlySpan input) + { + digest.BlockUpdate(input); + } +#endif + public virtual int DoFinal(byte[] output, int outOff) { digest.DoFinal(outputBuf, blockLength); diff --git a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs index 6fee619c1..f516e9b96 100644 --- a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs +++ b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs @@ -180,14 +180,14 @@ namespace Org.BouncyCastle.Crypto.Macs buf[bufOff++] = input; } - public void BlockUpdate( - byte[] input, - int inOff, - int len) + public void BlockUpdate(byte[] input, int inOff, int len) { if (len < 0) throw new ArgumentException("Can't have a negative input length!"); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(inOff, len)); +#else int blockSize = cipher.GetBlockSize(); int resultLen = 0; int gapLen = blockSize - bufOff; @@ -214,8 +214,38 @@ namespace Org.BouncyCastle.Crypto.Macs Array.Copy(input, inOff, buf, bufOff, len); bufOff += len; +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int blockSize = cipher.GetBlockSize(); + int resultLen = 0; + int gapLen = blockSize - bufOff; + + if (input.Length > gapLen) + { + input[..gapLen].CopyTo(buf.AsSpan(bufOff)); + + resultLen += cipher.ProcessBlock(buf, mac); + + bufOff = 0; + input = input[gapLen..]; + + while (input.Length > blockSize) + { + resultLen += cipher.ProcessBlock(input, mac); + input = input[blockSize..]; + } + } + + input.CopyTo(buf.AsSpan(bufOff)); + + bufOff += input.Length; + } +#endif + public int DoFinal( byte[] output, int outOff) diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs index 595d9b051..65fb8bf01 100644 --- a/crypto/src/crypto/macs/Poly1305.cs +++ b/crypto/src/crypto/macs/Poly1305.cs @@ -167,15 +167,22 @@ namespace Org.BouncyCastle.Crypto.Macs currentBlock[currentBlockOffset++] = input; if (currentBlockOffset == BlockSize) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ProcessBlock(currentBlock); +#else ProcessBlock(currentBlock, 0); +#endif currentBlockOffset = 0; } } public void BlockUpdate(byte[] input, int inOff, int len) { - // TODO Validity check on arguments + Check.DataLength(input, inOff, len, "input buffer too short"); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(inOff, len)); +#else int available = BlockSize - currentBlockOffset; if (len < available) { @@ -189,36 +196,107 @@ namespace Org.BouncyCastle.Crypto.Macs { Array.Copy(input, inOff, currentBlock, currentBlockOffset, available); pos = available; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ProcessBlock(currentBlock); +#else ProcessBlock(currentBlock, 0); +#endif } int remaining; while ((remaining = len - pos) >= BlockSize) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + ProcessBlock(input.AsSpan(inOff + pos)); +#else ProcessBlock(input, inOff + pos); +#endif pos += BlockSize; } Array.Copy(input, inOff + pos, currentBlock, 0, remaining); currentBlockOffset = remaining; +#endif } - private void ProcessBlock(byte[] buf, int off) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + int available = BlockSize - currentBlockOffset; + if (input.Length < available) + { + input.CopyTo(currentBlock.AsSpan(currentBlockOffset)); + currentBlockOffset += input.Length; + return; + } + + int pos = 0; + if (currentBlockOffset > 0) + { + input[..available].CopyTo(currentBlock.AsSpan(currentBlockOffset)); + pos = available; + ProcessBlock(currentBlock); + } + + int remaining; + while ((remaining = input.Length - pos) >= BlockSize) + { + ProcessBlock(input[pos..]); + pos += BlockSize; + } + + input[pos..].CopyTo(currentBlock); + currentBlockOffset = remaining; + } +#endif + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + private void ProcessBlock(ReadOnlySpan block) { #if NETCOREAPP3_0_OR_GREATER if (BitConverter.IsLittleEndian) { Span t = stackalloc uint[4]; - Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref t[0]), ref buf[off], 16); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref t[0]), ref Unsafe.AsRef(block[0]), 16); h0 += t[0] & 0x3ffffffU; h1 += ((t[1] << 6) | (t[0] >> 26)) & 0x3ffffffU; h2 += ((t[2] << 12) | (t[1] >> 20)) & 0x3ffffffU; h3 += ((t[3] << 18) | (t[2] >> 14)) & 0x3ffffffU; - h4 += (1 << 24) | (t[3] >> 8); + h4 += (1 << 24) | (t[3] >> 8); } else #endif + { + uint t0 = Pack.LE_To_UInt32(block); + uint t1 = Pack.LE_To_UInt32(block[4..]); + uint t2 = Pack.LE_To_UInt32(block[8..]); + uint t3 = Pack.LE_To_UInt32(block[12..]); + + h0 += t0 & 0x3ffffffU; + h1 += ((t1 << 6) | (t0 >> 26)) & 0x3ffffffU; + h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU; + h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU; + h4 += ( 1 << 24) | (t3 >> 8); + } + + ulong tp0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1; + ulong tp1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2; + ulong tp2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3; + ulong tp3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4; + ulong tp4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0; + + h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26); + h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26); + h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26); + h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26); + h4 = (uint)tp4 & 0x3ffffff; + h0 += (uint)(tp4 >> 26) * 5; + h1 += h0 >> 26; h0 &= 0x3ffffff; + } +#else + private void ProcessBlock(byte[] buf, int off) + { { uint t0 = Pack.LE_To_UInt32(buf, off + 0); uint t1 = Pack.LE_To_UInt32(buf, off + 4); @@ -246,10 +324,11 @@ namespace Org.BouncyCastle.Crypto.Macs h0 += (uint)(tp4 >> 26) * 5; h1 += h0 >> 26; h0 &= 0x3ffffff; } +#endif public int DoFinal(byte[] output, int outOff) { - Check.DataLength(output, outOff, BlockSize, "Output buffer is too short."); + Check.DataLength(output, outOff, BlockSize, "output buffer is too short."); if (currentBlockOffset > 0) { @@ -265,7 +344,11 @@ 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); diff --git a/crypto/src/crypto/macs/SipHash.cs b/crypto/src/crypto/macs/SipHash.cs index e1a19fa5b..fc0a66ed1 100644 --- a/crypto/src/crypto/macs/SipHash.cs +++ b/crypto/src/crypto/macs/SipHash.cs @@ -80,6 +80,9 @@ namespace Org.BouncyCastle.Crypto.Macs public virtual void BlockUpdate(byte[] input, int offset, int length) { +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + BlockUpdate(input.AsSpan(offset, length)); +#else int i = 0, fullWords = length & ~7; if (wordPos == 0) { @@ -115,8 +118,51 @@ namespace Org.BouncyCastle.Crypto.Macs } } } +#endif } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual void BlockUpdate(ReadOnlySpan input) + { + int length = input.Length; + int i = 0, fullWords = length & ~7; + if (wordPos == 0) + { + for (; i < fullWords; i += 8) + { + m = (long)Pack.LE_To_UInt64(input[i..]); + ProcessMessageWord(); + } + for (; i < length; ++i) + { + m = (long)(((ulong)m >> 8) | ((ulong)input[i] << 56)); + } + wordPos = length - fullWords; + } + else + { + int bits = wordPos << 3; + for (; i < fullWords; i += 8) + { + ulong n = Pack.LE_To_UInt64(input[i..]); + m = (long)((n << bits) | ((ulong)m >> -bits)); + ProcessMessageWord(); + m = (long)n; + } + for (; i < length; ++i) + { + m = (long)(((ulong)m >> 8) | ((ulong)input[i] << 56)); + + if (++wordPos == 8) + { + ProcessMessageWord(); + wordPos = 0; + } + } + } + } +#endif + public virtual long DoFinal() { // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0 diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs index 07eff24f4..6adc93ef9 100644 --- a/crypto/src/crypto/macs/SkeinMac.cs +++ b/crypto/src/crypto/macs/SkeinMac.cs @@ -106,13 +106,19 @@ namespace Org.BouncyCastle.Crypto.Macs public void BlockUpdate(byte[] input, int inOff, int len) { - engine.Update(input, inOff, len); + engine.BlockUpdate(input, inOff, len); } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void BlockUpdate(ReadOnlySpan input) + { + engine.BlockUpdate(input); + } +#endif + public int DoFinal(byte[] output, int outOff) { return engine.DoFinal(output, outOff); } - } } diff --git a/crypto/src/crypto/macs/VMPCMac.cs b/crypto/src/crypto/macs/VMPCMac.cs index 6f2da075c..76912f736 100644 --- a/crypto/src/crypto/macs/VMPCMac.cs +++ b/crypto/src/crypto/macs/VMPCMac.cs @@ -159,15 +159,24 @@ namespace Org.BouncyCastle.Crypto.Macs n = (byte) ((n + 1) & 0xff); } - public virtual void BlockUpdate(byte[] input, int inOff, int len) + public virtual void BlockUpdate(byte[] input, int inOff, int inLen) { - if ((inOff + len) > input.Length) - throw new DataLengthException("input buffer too short"); + Check.DataLength(input, inOff, inLen, "input buffer too short"); - for (int i = 0; i < len; i++) + for (int i = 0; i < inLen; i++) { Update(input[inOff + i]); } } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public virtual void BlockUpdate(ReadOnlySpan input) + { + for (int i = 0; i < input.Length; i++) + { + Update(input[i]); + } + } +#endif } } -- cgit 1.4.1