diff --git a/crypto/src/crypto/engines/ChaCha7539Engine.cs b/crypto/src/crypto/engines/ChaCha7539Engine.cs
index d1dd9755b..a438c0bfb 100644
--- a/crypto/src/crypto/engines/ChaCha7539Engine.cs
+++ b/crypto/src/crypto/engines/ChaCha7539Engine.cs
@@ -81,16 +81,24 @@ namespace Org.BouncyCastle.Crypto.Engines
while (inLen >= 128)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ProcessBlocks2(inBuf.AsSpan(inOff), outBuf.AsSpan(outOff));
+#else
ProcessBlocks2(inBuf, inOff, outBuf, outOff);
- inOff += 128;
+#endif
+ inOff += 128;
inLen -= 128;
outOff += 128;
}
if (inLen >= 64)
{
- ImplProcessBlock(inBuf, inOff, outBuf, outOff);
- inOff += 64;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ImplProcessBlock(inBuf.AsSpan(inOff), outBuf.AsSpan(outOff));
+#else
+ ImplProcessBlock(inBuf, inOff, outBuf, outOff);
+#endif
+ inOff += 64;
inLen -= 64;
outOff += 64;
}
@@ -111,7 +119,8 @@ namespace Org.BouncyCastle.Crypto.Engines
// TODO Prevent re-use if encrypting
}
- internal void ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal void ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -120,10 +129,10 @@ namespace Org.BouncyCastle.Crypto.Engines
Debug.Assert(index == 0);
- ImplProcessBlock(inBytes, inOff, outBytes, outOff);
+ ImplProcessBlock(input, output);
}
- internal void ProcessBlocks2(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ internal void ProcessBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
{
if (!initialised)
throw new InvalidOperationException(AlgorithmName + " not initialised");
@@ -135,18 +144,57 @@ namespace Org.BouncyCastle.Crypto.Engines
#if NETCOREAPP3_0_OR_GREATER
if (Avx2.IsSupported)
{
- ImplProcessBlocks2_X86_Avx2(rounds, engineState, inBytes.AsSpan(inOff), outBytes.AsSpan(outOff));
+ ImplProcessBlocks2_X86_Avx2(rounds, engineState, input, output);
return;
}
if (Sse2.IsSupported)
{
- ImplProcessBlocks2_X86_Sse2(rounds, engineState, inBytes.AsSpan(inOff), outBytes.AsSpan(outOff));
+ ImplProcessBlocks2_X86_Sse2(rounds, engineState, input, output);
return;
}
#endif
{
+ ImplProcessBlock(input, output);
+ ImplProcessBlock(input[64..], output[64..]);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void ImplProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ ChaChaEngine.ChachaCore(rounds, engineState, keyStream);
+ AdvanceCounter();
+
+ for (int i = 0; i < 64; ++i)
+ {
+ output[i] = (byte)(keyStream[i] ^ input[i]);
+ }
+ }
+#else
+ internal void ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if (LimitExceeded(64U))
+ throw new MaxBytesExceededException("2^38 byte limit per IV would be exceeded; Change IV");
+
+ Debug.Assert(index == 0);
+
+ ImplProcessBlock(inBytes, inOff, outBytes, outOff);
+ }
+
+ internal void ProcessBlocks2(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+ if (LimitExceeded(128U))
+ throw new MaxBytesExceededException("2^38 byte limit per IV would be exceeded; Change IV");
+
+ Debug.Assert(index == 0);
+
+ {
ImplProcessBlock(inBytes, inOff, outBytes, outOff);
ImplProcessBlock(inBytes, inOff + 64, outBytes, outOff + 64);
}
@@ -165,6 +213,7 @@ namespace Org.BouncyCastle.Crypto.Engines
outBuf[outOff + i] = (byte)(keyStream[i] ^ inBuf[inOff + i]);
}
}
+#endif
#if NETCOREAPP3_0_OR_GREATER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index 46e7b9c55..0a2adb57d 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -125,22 +125,23 @@ namespace Org.BouncyCastle.Crypto.Modes
}
#endif
- public virtual int ProcessByte(
- byte input,
- byte[] outBytes,
- int outOff)
+ public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
{
data.WriteByte(input);
return 0;
}
- public virtual int ProcessBytes(
- byte[] inBytes,
- int inOff,
- int inLen,
- byte[] outBytes,
- int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
+ {
+ data.WriteByte(input);
+
+ return 0;
+ }
+#endif
+
+ public virtual int ProcessBytes(byte[] inBytes, int inOff, int inLen, byte[] outBytes, int outOff)
{
Check.DataLength(inBytes, inOff, inLen, "input buffer too short");
@@ -149,6 +150,15 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ data.Write(input);
+
+ return 0;
+ }
+#endif
+
public virtual int DoFinal(byte[] outBytes, int outOff)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/src/crypto/modes/ChaCha20Poly1305.cs b/crypto/src/crypto/modes/ChaCha20Poly1305.cs
index 9e30dc510..299387cdf 100644
--- a/crypto/src/crypto/modes/ChaCha20Poly1305.cs
+++ b/crypto/src/crypto/modes/ChaCha20Poly1305.cs
@@ -234,7 +234,11 @@ namespace Org.BouncyCastle.Crypto.Modes
if (++mBufPos == mBuf.Length)
{
mPoly1305.BlockUpdate(mBuf, 0, BufSize);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ProcessBlock(mBuf, outBytes.AsSpan(outOff));
+#else
ProcessBlock(mBuf, 0, outBytes, outOff);
+#endif
Array.Copy(mBuf, BufSize, mBuf, 0, MacSize);
this.mBufPos = MacSize;
return BufSize;
@@ -247,7 +251,11 @@ namespace Org.BouncyCastle.Crypto.Modes
mBuf[mBufPos] = input;
if (++mBufPos == BufSize)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ProcessBlock(mBuf, outBytes.AsSpan(outOff));
+#else
ProcessBlock(mBuf, 0, outBytes, outOff);
+#endif
mPoly1305.BlockUpdate(outBytes, outOff, BufSize);
this.mBufPos = 0;
return BufSize;
@@ -260,6 +268,46 @@ namespace Org.BouncyCastle.Crypto.Modes
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
+ {
+ CheckData();
+
+ switch (mState)
+ {
+ case State.DecData:
+ {
+ mBuf[mBufPos] = input;
+ if (++mBufPos == mBuf.Length)
+ {
+ mPoly1305.BlockUpdate(mBuf.AsSpan(0, BufSize));
+ ProcessBlock(mBuf, output);
+ Array.Copy(mBuf, BufSize, mBuf, 0, MacSize);
+ this.mBufPos = MacSize;
+ return BufSize;
+ }
+
+ return 0;
+ }
+ case State.EncData:
+ {
+ mBuf[mBufPos] = input;
+ if (++mBufPos == BufSize)
+ {
+ ProcessBlock(mBuf, output);
+ mPoly1305.BlockUpdate(output[..BufSize]);
+ this.mBufPos = 0;
+ return BufSize;
+ }
+
+ return 0;
+ }
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+#endif
+
public virtual int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
{
if (null == inBytes)
@@ -280,6 +328,9 @@ namespace Org.BouncyCastle.Crypto.Modes
if (outOff < 0)
throw new ArgumentException("cannot be negative", "outOff");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
+#else
CheckData();
int resultLen = 0;
@@ -388,8 +439,120 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return resultLen;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ CheckData();
+
+ int resultLen = 0;
+
+ switch (mState)
+ {
+ case State.DecData:
+ {
+ int available = mBuf.Length - mBufPos;
+ if (input.Length < available)
+ {
+ input.CopyTo(mBuf.AsSpan(mBufPos));
+ mBufPos += input.Length;
+ break;
+ }
+
+ if (mBufPos >= BufSize)
+ {
+ mPoly1305.BlockUpdate(mBuf.AsSpan(0, BufSize));
+ ProcessBlock(mBuf, output);
+ Array.Copy(mBuf, BufSize, mBuf, 0, mBufPos -= BufSize);
+ resultLen = BufSize;
+
+ available += BufSize;
+ if (input.Length < available)
+ {
+ input.CopyTo(mBuf.AsSpan(mBufPos));
+ mBufPos += input.Length;
+ break;
+ }
+ }
+
+ int inLimit1 = mBuf.Length;
+ int inLimit2 = inLimit1 + BufSize;
+
+ available = BufSize - mBufPos;
+ input[..available].CopyTo(mBuf.AsSpan(mBufPos));
+ mPoly1305.BlockUpdate(mBuf.AsSpan(0, BufSize));
+ ProcessBlock(mBuf, output[resultLen..]);
+ input = input[available..];
+ resultLen += BufSize;
+
+ while (input.Length >= inLimit2)
+ {
+ mPoly1305.BlockUpdate(input[..(BufSize * 2)]);
+ ProcessBlocks2(input, output[resultLen..]);
+ input = input[(BufSize * 2)..];
+ resultLen += BufSize * 2;
+ }
+
+ if (input.Length >= inLimit1)
+ {
+ mPoly1305.BlockUpdate(input[..BufSize]);
+ ProcessBlock(input, output[resultLen..]);
+ input = input[BufSize..];
+ resultLen += BufSize;
+ }
+
+ mBufPos = input.Length;
+ input.CopyTo(mBuf);
+ break;
+ }
+ case State.EncData:
+ {
+ int available = BufSize - mBufPos;
+ if (input.Length < available)
+ {
+ input.CopyTo(mBuf.AsSpan(mBufPos));
+ mBufPos += input.Length;
+ break;
+ }
+
+ if (mBufPos > 0)
+ {
+ input[..available].CopyTo(mBuf.AsSpan(mBufPos));
+ ProcessBlock(mBuf, output);
+ input = input[available..];
+ resultLen = BufSize;
+ }
+
+ while (input.Length >= BufSize * 2)
+ {
+ ProcessBlocks2(input, output[resultLen..]);
+ input = input[(BufSize * 2)..];
+ resultLen += BufSize * 2;
+ }
+
+ if (input.Length >= BufSize)
+ {
+ ProcessBlock(input, output[resultLen..]);
+ input = input[BufSize..];
+ resultLen += BufSize;
+ }
+
+ mPoly1305.BlockUpdate(output[..resultLen]);
+
+ mBufPos = input.Length;
+ input.CopyTo(mBuf);
+ break;
+ }
+ default:
+ throw new InvalidOperationException();
+ }
+
+ return resultLen;
+ }
+#endif
+
public virtual int DoFinal(byte[] outBytes, int outOff)
{
if (null == outBytes)
@@ -621,25 +784,25 @@ namespace Org.BouncyCastle.Crypto.Modes
}
}
- private void ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- Check.OutputLength(outBytes, outOff, 64, "output buffer too short");
+ Check.OutputLength(output, 64, "output buffer too short");
- mChacha20.ProcessBlock(inBytes, inOff, outBytes, outOff);
+ mChacha20.ProcessBlock(input, output);
this.mDataCount = IncrementCount(mDataCount, 64U, DataLimit);
}
- private void ProcessBlocks2(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ private void ProcessBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
{
- Check.OutputLength(outBytes, outOff, 128, "output buffer too short");
+ Check.OutputLength(output, 128, "output buffer too short");
- mChacha20.ProcessBlocks2(inBytes, inOff, outBytes, outOff);
+ mChacha20.ProcessBlocks2(input, output);
this.mDataCount = IncrementCount(mDataCount, 128U, DataLimit);
}
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
private void ProcessData(ReadOnlySpan<byte> input, Span<byte> output)
{
Check.OutputLength(output, input.Length, "output buffer too short");
@@ -649,6 +812,24 @@ namespace Org.BouncyCastle.Crypto.Modes
this.mDataCount = IncrementCount(mDataCount, (uint)input.Length, DataLimit);
}
#else
+ private void ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ {
+ Check.OutputLength(outBytes, outOff, 64, "output buffer too short");
+
+ mChacha20.ProcessBlock(inBytes, inOff, outBytes, outOff);
+
+ this.mDataCount = IncrementCount(mDataCount, 64U, DataLimit);
+ }
+
+ private void ProcessBlocks2(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+ {
+ Check.OutputLength(outBytes, outOff, 128, "output buffer too short");
+
+ mChacha20.ProcessBlocks2(inBytes, inOff, outBytes, outOff);
+
+ this.mDataCount = IncrementCount(mDataCount, 128U, DataLimit);
+ }
+
private void ProcessData(byte[] inBytes, int inOff, int inLen, byte[] outBytes, int outOff)
{
Check.OutputLength(outBytes, outOff, inLen, "output buffer too short");
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index 440b5f439..e63826159 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -209,25 +209,33 @@ namespace Org.BouncyCastle.Crypto.Modes
}
#endif
- public virtual int ProcessByte(
- byte input,
- byte[] outBytes,
- int outOff)
+ public virtual int ProcessByte(byte input, byte[] outBytes, int outOff)
{
InitCipher();
- return Process(input, outBytes, outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Process(input, Spans.FromNullable(outBytes, outOff));
+#else
+ return Process(input, outBytes, outOff);
+#endif
}
- public virtual int ProcessBytes(
- byte[] inBytes,
- int inOff,
- int len,
- byte[] outBytes,
- int outOff)
- {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
+ {
InitCipher();
+ return Process(input, output);
+ }
+#endif
+
+ public virtual int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff)
+ {
+ InitCipher();
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessBytes(inBytes.AsSpan(inOff, len), Spans.FromNullable(outBytes, outOff));
+#else
int resultLen = 0;
for (int i = 0; i != len; i++)
@@ -236,9 +244,27 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return resultLen;
+#endif
}
- public virtual int DoFinal(byte[] outBytes, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ InitCipher();
+
+ int len = input.Length;
+ int resultLen = 0;
+
+ for (int i = 0; i != len; i++)
+ {
+ resultLen += Process(input[i], output[resultLen..]);
+ }
+
+ return resultLen;
+ }
+#endif
+
+ public virtual int DoFinal(byte[] outBytes, int outOff)
{
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
return DoFinal(outBytes.AsSpan(outOff));
@@ -389,12 +415,49 @@ namespace Org.BouncyCastle.Crypto.Modes
return totalData < macSize ? 0 : totalData - macSize;
}
- private int Process(
- byte b,
- byte[] outBytes,
- int outOff)
- {
- bufBlock[bufOff++] = b;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private int Process(byte b, Span<byte> output)
+ {
+ bufBlock[bufOff++] = b;
+
+ if (bufOff == bufBlock.Length)
+ {
+ Check.OutputLength(output, blockSize, "output buffer too short");
+
+ // TODO Could move the ProcessByte(s) calls to here
+ //InitCipher();
+
+ int size;
+
+ if (forEncryption)
+ {
+ size = cipher.ProcessBlock(bufBlock, output);
+
+ mac.BlockUpdate(output[..blockSize]);
+ }
+ else
+ {
+ mac.BlockUpdate(bufBlock.AsSpan(0, blockSize));
+
+ size = cipher.ProcessBlock(bufBlock, output);
+ }
+
+ bufOff = 0;
+ if (!forEncryption)
+ {
+ Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
+
+ return size;
+ }
+
+ return 0;
+ }
+#else
+ private int Process(byte b, byte[] outBytes, int outOff)
+ {
+ bufBlock[bufOff++] = b;
if (bufOff == bufBlock.Length)
{
@@ -430,8 +493,9 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
+#endif
- private bool VerifyMac(byte[] mac, int off)
+ private bool VerifyMac(byte[] mac, int off)
{
int nonEqual = 0;
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index c2b2cf86d..2cc7ff62d 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -379,12 +379,20 @@ namespace Org.BouncyCastle.Crypto.Modes
{
if (forEncryption)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ EncryptBlock(bufBlock, output.AsSpan(outOff));
+#else
EncryptBlock(bufBlock, 0, output, outOff);
+#endif
bufOff = 0;
}
else
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ DecryptBlock(bufBlock, output.AsSpan(outOff));
+#else
DecryptBlock(bufBlock, 0, output, outOff);
+#endif
Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
bufOff = macSize;
}
@@ -393,12 +401,40 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
+ {
+ CheckStatus();
+
+ bufBlock[bufOff] = input;
+ if (++bufOff == bufBlock.Length)
+ {
+ if (forEncryption)
+ {
+ EncryptBlock(bufBlock, output);
+ bufOff = 0;
+ }
+ else
+ {
+ DecryptBlock(bufBlock, output);
+ Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
+ return BlockSize;
+ }
+ return 0;
+ }
+#endif
+
public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
CheckStatus();
Check.DataLength(input, inOff, len, "input buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessBytes(input.AsSpan(inOff, len), Spans.FromNullable(output, outOff));
+#else
int resultLen = 0;
if (forEncryption)
@@ -495,7 +531,108 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return resultLen;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ CheckStatus();
+
+ int resultLen = 0;
+
+ if (forEncryption)
+ {
+ if (bufOff > 0)
+ {
+ int available = BlockSize - bufOff;
+ if (input.Length < available)
+ {
+ input.CopyTo(bufBlock.AsSpan(bufOff));
+ bufOff += input.Length;
+ return 0;
+ }
+
+ input[..available].CopyTo(bufBlock.AsSpan(bufOff));
+ EncryptBlock(bufBlock, output);
+ input = input[available..];
+ resultLen = BlockSize;
+ //bufOff = 0;
+ }
+
+ while (input.Length >= BlockSize * 2)
+ {
+ EncryptBlocks2(input, output[resultLen..]);
+ input = input[(BlockSize * 2)..];
+ resultLen += BlockSize * 2;
+ }
+
+ if (input.Length >= BlockSize)
+ {
+ EncryptBlock(input, output[resultLen..]);
+ input = input[BlockSize..];
+ resultLen += BlockSize;
+ }
+
+ bufOff = input.Length;
+ input.CopyTo(bufBlock);
+ }
+ else
+ {
+ int available = bufBlock.Length - bufOff;
+ if (input.Length < available)
+ {
+ input.CopyTo(bufBlock.AsSpan(bufOff));
+ bufOff += input.Length;
+ return 0;
+ }
+
+ if (bufOff >= BlockSize)
+ {
+ DecryptBlock(bufBlock, output);
+ Array.Copy(bufBlock, BlockSize, bufBlock, 0, bufOff -= BlockSize);
+ resultLen = BlockSize;
+
+ available += BlockSize;
+ if (input.Length < available)
+ {
+ input.CopyTo(bufBlock.AsSpan(bufOff));
+ bufOff += input.Length;
+ return resultLen;
+ }
+ }
+
+ int inLimit1 = bufBlock.Length;
+ int inLimit2 = inLimit1 + BlockSize;
+
+ available = BlockSize - bufOff;
+ input[..available].CopyTo(bufBlock.AsSpan(bufOff));
+ DecryptBlock(bufBlock, output[resultLen..]);
+ input = input[available..];
+ resultLen += BlockSize;
+ //bufOff = 0;
+
+ while (input.Length >= inLimit2)
+ {
+ DecryptBlocks2(input, output[resultLen..]);
+ input = input[(BlockSize * 2)..];
+ resultLen += BlockSize * 2;
+ }
+
+ if (input.Length >= inLimit1)
+ {
+ DecryptBlock(input, output[resultLen..]);
+ input = input[BlockSize..];
+ resultLen += BlockSize;
+ }
+
+ bufOff = input.Length;
+ input.CopyTo(bufBlock);
+ }
+
+ return resultLen;
}
+#endif
public int DoFinal(byte[] output, int outOff)
{
@@ -670,29 +807,30 @@ namespace Org.BouncyCastle.Crypto.Modes
}
}
- private void DecryptBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- Check.OutputLength(outBuf, outOff, BlockSize, "Output buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
if (totalLength == 0)
{
InitCipher();
}
- byte[] ctrBlock = new byte[BlockSize];
+ Span<byte> ctrBlock = stackalloc byte[BlockSize];
GetNextCtrBlock(ctrBlock);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
{
- var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref inBuf[inOff]);
+ var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
t1 = Sse2.Xor(t1, t0);
t2 = Sse2.Xor(t2, t0);
- Unsafe.WriteUnaligned(ref outBuf[outOff], t1);
+ Unsafe.WriteUnaligned(ref output[0], t1);
Unsafe.WriteUnaligned(ref S[0], t2);
}
else
@@ -700,20 +838,20 @@ namespace Org.BouncyCastle.Crypto.Modes
{
for (int i = 0; i < BlockSize; i += 4)
{
- byte c0 = inBuf[inOff + i + 0];
- byte c1 = inBuf[inOff + i + 1];
- byte c2 = inBuf[inOff + i + 2];
- byte c3 = inBuf[inOff + i + 3];
+ byte c0 = input[i + 0];
+ byte c1 = input[i + 1];
+ byte c2 = input[i + 2];
+ byte c3 = input[i + 3];
S[i + 0] ^= c0;
S[i + 1] ^= c1;
S[i + 2] ^= c2;
S[i + 3] ^= c3;
- outBuf[outOff + i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
- outBuf[outOff + i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
- outBuf[outOff + i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
- outBuf[outOff + i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
+ output[i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
+ output[i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
+ output[i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
+ output[i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
}
}
multiplier.MultiplyH(S);
@@ -721,29 +859,29 @@ namespace Org.BouncyCastle.Crypto.Modes
totalLength += BlockSize;
}
- private void DecryptBlocks2(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ private void DecryptBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
{
- Check.OutputLength(outBuf, outOff, BlockSize * 2, "Output buffer too short");
+ Check.OutputLength(output, BlockSize * 2, "output buffer too short");
if (totalLength == 0)
{
InitCipher();
}
- byte[] ctrBlock = new byte[BlockSize];
+ Span<byte> ctrBlock = stackalloc byte[BlockSize];
GetNextCtrBlock(ctrBlock);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
{
- var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref inBuf[inOff]);
+ var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
t1 = Sse2.Xor(t1, t0);
t2 = Sse2.Xor(t2, t0);
- Unsafe.WriteUnaligned(ref outBuf[outOff], t1);
+ Unsafe.WriteUnaligned(ref output[0], t1);
Unsafe.WriteUnaligned(ref S[0], t2);
}
else
@@ -751,39 +889,39 @@ namespace Org.BouncyCastle.Crypto.Modes
{
for (int i = 0; i < BlockSize; i += 4)
{
- byte c0 = inBuf[inOff + i + 0];
- byte c1 = inBuf[inOff + i + 1];
- byte c2 = inBuf[inOff + i + 2];
- byte c3 = inBuf[inOff + i + 3];
+ byte c0 = input[i + 0];
+ byte c1 = input[i + 1];
+ byte c2 = input[i + 2];
+ byte c3 = input[i + 3];
S[i + 0] ^= c0;
S[i + 1] ^= c1;
S[i + 2] ^= c2;
S[i + 3] ^= c3;
- outBuf[outOff + i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
- outBuf[outOff + i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
- outBuf[outOff + i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
- outBuf[outOff + i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
+ output[i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
+ output[i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
+ output[i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
+ output[i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
}
}
multiplier.MultiplyH(S);
- inOff += BlockSize;
- outOff += BlockSize;
+ input = input[BlockSize..];
+ output = output[BlockSize..];
GetNextCtrBlock(ctrBlock);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
{
- var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref inBuf[inOff]);
+ var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
t1 = Sse2.Xor(t1, t0);
t2 = Sse2.Xor(t2, t0);
- Unsafe.WriteUnaligned(ref outBuf[outOff], t1);
+ Unsafe.WriteUnaligned(ref output[0], t1);
Unsafe.WriteUnaligned(ref S[0], t2);
}
else
@@ -791,20 +929,20 @@ namespace Org.BouncyCastle.Crypto.Modes
{
for (int i = 0; i < BlockSize; i += 4)
{
- byte c0 = inBuf[inOff + i + 0];
- byte c1 = inBuf[inOff + i + 1];
- byte c2 = inBuf[inOff + i + 2];
- byte c3 = inBuf[inOff + i + 3];
+ byte c0 = input[i + 0];
+ byte c1 = input[i + 1];
+ byte c2 = input[i + 2];
+ byte c3 = input[i + 3];
S[i + 0] ^= c0;
S[i + 1] ^= c1;
S[i + 2] ^= c2;
S[i + 3] ^= c3;
- outBuf[outOff + i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
- outBuf[outOff + i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
- outBuf[outOff + i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
- outBuf[outOff + i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
+ output[i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
+ output[i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
+ output[i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
+ output[i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
}
}
multiplier.MultiplyH(S);
@@ -812,29 +950,29 @@ namespace Org.BouncyCastle.Crypto.Modes
totalLength += BlockSize * 2;
}
- private void EncryptBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
- Check.OutputLength(outBuf, outOff, BlockSize, "Output buffer too short");
+ Check.OutputLength(output, BlockSize, "output buffer too short");
if (totalLength == 0)
{
InitCipher();
}
- byte[] ctrBlock = new byte[BlockSize];
+ Span<byte> ctrBlock = stackalloc byte[BlockSize];
GetNextCtrBlock(ctrBlock);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
{
- var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref inBuf[inOff]);
+ var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
t1 = Sse2.Xor(t1, t0);
t2 = Sse2.Xor(t2, t1);
- Unsafe.WriteUnaligned(ref outBuf[outOff], t1);
+ Unsafe.WriteUnaligned(ref output[0], t1);
Unsafe.WriteUnaligned(ref S[0], t2);
}
else
@@ -842,20 +980,20 @@ namespace Org.BouncyCastle.Crypto.Modes
{
for (int i = 0; i < BlockSize; i += 4)
{
- byte c0 = (byte)(ctrBlock[i + 0] ^ inBuf[inOff + i + 0]);
- byte c1 = (byte)(ctrBlock[i + 1] ^ inBuf[inOff + i + 1]);
- byte c2 = (byte)(ctrBlock[i + 2] ^ inBuf[inOff + i + 2]);
- byte c3 = (byte)(ctrBlock[i + 3] ^ inBuf[inOff + i + 3]);
+ byte c0 = (byte)(ctrBlock[i + 0] ^ input[i + 0]);
+ byte c1 = (byte)(ctrBlock[i + 1] ^ input[i + 1]);
+ byte c2 = (byte)(ctrBlock[i + 2] ^ input[i + 2]);
+ byte c3 = (byte)(ctrBlock[i + 3] ^ input[i + 3]);
S[i + 0] ^= c0;
S[i + 1] ^= c1;
S[i + 2] ^= c2;
S[i + 3] ^= c3;
- outBuf[outOff + i + 0] = c0;
- outBuf[outOff + i + 1] = c1;
- outBuf[outOff + i + 2] = c2;
- outBuf[outOff + i + 3] = c3;
+ output[i + 0] = c0;
+ output[i + 1] = c1;
+ output[i + 2] = c2;
+ output[i + 3] = c3;
}
}
multiplier.MultiplyH(S);
@@ -863,29 +1001,29 @@ namespace Org.BouncyCastle.Crypto.Modes
totalLength += BlockSize;
}
- private void EncryptBlocks2(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ private void EncryptBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
{
- Check.OutputLength(outBuf, outOff, BlockSize * 2, "Output buffer too short");
+ Check.OutputLength(output, BlockSize * 2, "Output buffer too short");
if (totalLength == 0)
{
InitCipher();
}
- byte[] ctrBlock = new byte[BlockSize];
+ Span<byte> ctrBlock = stackalloc byte[BlockSize];
GetNextCtrBlock(ctrBlock);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
{
- var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref inBuf[inOff]);
+ var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
t1 = Sse2.Xor(t1, t0);
t2 = Sse2.Xor(t2, t1);
- Unsafe.WriteUnaligned(ref outBuf[outOff], t1);
+ Unsafe.WriteUnaligned(ref output[0], t1);
Unsafe.WriteUnaligned(ref S[0], t2);
}
else
@@ -893,39 +1031,39 @@ namespace Org.BouncyCastle.Crypto.Modes
{
for (int i = 0; i < BlockSize; i += 4)
{
- byte c0 = (byte)(ctrBlock[i + 0] ^ inBuf[inOff + i + 0]);
- byte c1 = (byte)(ctrBlock[i + 1] ^ inBuf[inOff + i + 1]);
- byte c2 = (byte)(ctrBlock[i + 2] ^ inBuf[inOff + i + 2]);
- byte c3 = (byte)(ctrBlock[i + 3] ^ inBuf[inOff + i + 3]);
+ byte c0 = (byte)(ctrBlock[i + 0] ^ input[i + 0]);
+ byte c1 = (byte)(ctrBlock[i + 1] ^ input[i + 1]);
+ byte c2 = (byte)(ctrBlock[i + 2] ^ input[i + 2]);
+ byte c3 = (byte)(ctrBlock[i + 3] ^ input[i + 3]);
S[i + 0] ^= c0;
S[i + 1] ^= c1;
S[i + 2] ^= c2;
S[i + 3] ^= c3;
- outBuf[outOff + i + 0] = c0;
- outBuf[outOff + i + 1] = c1;
- outBuf[outOff + i + 2] = c2;
- outBuf[outOff + i + 3] = c3;
+ output[i + 0] = c0;
+ output[i + 1] = c1;
+ output[i + 2] = c2;
+ output[i + 3] = c3;
}
}
multiplier.MultiplyH(S);
- inOff += BlockSize;
- outOff += BlockSize;
+ input = input[BlockSize..];
+ output = output[BlockSize..];
GetNextCtrBlock(ctrBlock);
#if NETCOREAPP3_0_OR_GREATER
if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
{
- var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref inBuf[inOff]);
+ var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
t1 = Sse2.Xor(t1, t0);
t2 = Sse2.Xor(t2, t1);
- Unsafe.WriteUnaligned(ref outBuf[outOff], t1);
+ Unsafe.WriteUnaligned(ref output[0], t1);
Unsafe.WriteUnaligned(ref S[0], t2);
}
else
@@ -933,6 +1071,212 @@ namespace Org.BouncyCastle.Crypto.Modes
{
for (int i = 0; i < BlockSize; i += 4)
{
+ byte c0 = (byte)(ctrBlock[i + 0] ^ input[i + 0]);
+ byte c1 = (byte)(ctrBlock[i + 1] ^ input[i + 1]);
+ byte c2 = (byte)(ctrBlock[i + 2] ^ input[i + 2]);
+ byte c3 = (byte)(ctrBlock[i + 3] ^ input[i + 3]);
+
+ S[i + 0] ^= c0;
+ S[i + 1] ^= c1;
+ S[i + 2] ^= c2;
+ S[i + 3] ^= c3;
+
+ output[i + 0] = c0;
+ output[i + 1] = c1;
+ output[i + 2] = c2;
+ output[i + 3] = c3;
+ }
+ }
+ multiplier.MultiplyH(S);
+
+ totalLength += BlockSize * 2;
+ }
+
+ private void GetNextCtrBlock(Span<byte> block)
+ {
+ if (blocksRemaining == 0)
+ throw new InvalidOperationException("Attempt to process too many blocks");
+
+ blocksRemaining--;
+
+ Pack.UInt32_To_BE(++counter32, counter, 12);
+
+ cipher.ProcessBlock(counter, block);
+ }
+#else
+ private void DecryptBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ {
+ Check.OutputLength(outBuf, outOff, BlockSize, "Output buffer too short");
+
+ if (totalLength == 0)
+ {
+ InitCipher();
+ }
+
+ byte[] ctrBlock = new byte[BlockSize];
+
+ GetNextCtrBlock(ctrBlock);
+ {
+ for (int i = 0; i < BlockSize; i += 4)
+ {
+ byte c0 = inBuf[inOff + i + 0];
+ byte c1 = inBuf[inOff + i + 1];
+ byte c2 = inBuf[inOff + i + 2];
+ byte c3 = inBuf[inOff + i + 3];
+
+ S[i + 0] ^= c0;
+ S[i + 1] ^= c1;
+ S[i + 2] ^= c2;
+ S[i + 3] ^= c3;
+
+ outBuf[outOff + i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
+ outBuf[outOff + i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
+ outBuf[outOff + i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
+ outBuf[outOff + i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
+ }
+ }
+ multiplier.MultiplyH(S);
+
+ totalLength += BlockSize;
+ }
+
+ private void DecryptBlocks2(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ {
+ Check.OutputLength(outBuf, outOff, BlockSize * 2, "Output buffer too short");
+
+ if (totalLength == 0)
+ {
+ InitCipher();
+ }
+
+ byte[] ctrBlock = new byte[BlockSize];
+
+ GetNextCtrBlock(ctrBlock);
+ {
+ for (int i = 0; i < BlockSize; i += 4)
+ {
+ byte c0 = inBuf[inOff + i + 0];
+ byte c1 = inBuf[inOff + i + 1];
+ byte c2 = inBuf[inOff + i + 2];
+ byte c3 = inBuf[inOff + i + 3];
+
+ S[i + 0] ^= c0;
+ S[i + 1] ^= c1;
+ S[i + 2] ^= c2;
+ S[i + 3] ^= c3;
+
+ outBuf[outOff + i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
+ outBuf[outOff + i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
+ outBuf[outOff + i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
+ outBuf[outOff + i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
+ }
+ }
+ multiplier.MultiplyH(S);
+
+ inOff += BlockSize;
+ outOff += BlockSize;
+
+ GetNextCtrBlock(ctrBlock);
+ {
+ for (int i = 0; i < BlockSize; i += 4)
+ {
+ byte c0 = inBuf[inOff + i + 0];
+ byte c1 = inBuf[inOff + i + 1];
+ byte c2 = inBuf[inOff + i + 2];
+ byte c3 = inBuf[inOff + i + 3];
+
+ S[i + 0] ^= c0;
+ S[i + 1] ^= c1;
+ S[i + 2] ^= c2;
+ S[i + 3] ^= c3;
+
+ outBuf[outOff + i + 0] = (byte)(c0 ^ ctrBlock[i + 0]);
+ outBuf[outOff + i + 1] = (byte)(c1 ^ ctrBlock[i + 1]);
+ outBuf[outOff + i + 2] = (byte)(c2 ^ ctrBlock[i + 2]);
+ outBuf[outOff + i + 3] = (byte)(c3 ^ ctrBlock[i + 3]);
+ }
+ }
+ multiplier.MultiplyH(S);
+
+ totalLength += BlockSize * 2;
+ }
+
+ private void EncryptBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ {
+ Check.OutputLength(outBuf, outOff, BlockSize, "Output buffer too short");
+
+ if (totalLength == 0)
+ {
+ InitCipher();
+ }
+
+ byte[] ctrBlock = new byte[BlockSize];
+
+ GetNextCtrBlock(ctrBlock);
+ {
+ for (int i = 0; i < BlockSize; i += 4)
+ {
+ byte c0 = (byte)(ctrBlock[i + 0] ^ inBuf[inOff + i + 0]);
+ byte c1 = (byte)(ctrBlock[i + 1] ^ inBuf[inOff + i + 1]);
+ byte c2 = (byte)(ctrBlock[i + 2] ^ inBuf[inOff + i + 2]);
+ byte c3 = (byte)(ctrBlock[i + 3] ^ inBuf[inOff + i + 3]);
+
+ S[i + 0] ^= c0;
+ S[i + 1] ^= c1;
+ S[i + 2] ^= c2;
+ S[i + 3] ^= c3;
+
+ outBuf[outOff + i + 0] = c0;
+ outBuf[outOff + i + 1] = c1;
+ outBuf[outOff + i + 2] = c2;
+ outBuf[outOff + i + 3] = c3;
+ }
+ }
+ multiplier.MultiplyH(S);
+
+ totalLength += BlockSize;
+ }
+
+ private void EncryptBlocks2(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+ {
+ Check.OutputLength(outBuf, outOff, BlockSize * 2, "Output buffer too short");
+
+ if (totalLength == 0)
+ {
+ InitCipher();
+ }
+
+ byte[] ctrBlock = new byte[BlockSize];
+
+ GetNextCtrBlock(ctrBlock);
+ {
+ for (int i = 0; i < BlockSize; i += 4)
+ {
+ byte c0 = (byte)(ctrBlock[i + 0] ^ inBuf[inOff + i + 0]);
+ byte c1 = (byte)(ctrBlock[i + 1] ^ inBuf[inOff + i + 1]);
+ byte c2 = (byte)(ctrBlock[i + 2] ^ inBuf[inOff + i + 2]);
+ byte c3 = (byte)(ctrBlock[i + 3] ^ inBuf[inOff + i + 3]);
+
+ S[i + 0] ^= c0;
+ S[i + 1] ^= c1;
+ S[i + 2] ^= c2;
+ S[i + 3] ^= c3;
+
+ outBuf[outOff + i + 0] = c0;
+ outBuf[outOff + i + 1] = c1;
+ outBuf[outOff + i + 2] = c2;
+ outBuf[outOff + i + 3] = c3;
+ }
+ }
+ multiplier.MultiplyH(S);
+
+ inOff += BlockSize;
+ outOff += BlockSize;
+
+ GetNextCtrBlock(ctrBlock);
+ {
+ for (int i = 0; i < BlockSize; i += 4)
+ {
byte c0 = (byte)(ctrBlock[i + 0] ^ inBuf[inOff + i + 0]);
byte c1 = (byte)(ctrBlock[i + 1] ^ inBuf[inOff + i + 1]);
byte c2 = (byte)(ctrBlock[i + 2] ^ inBuf[inOff + i + 2]);
@@ -954,6 +1298,19 @@ namespace Org.BouncyCastle.Crypto.Modes
totalLength += BlockSize * 2;
}
+ private void GetNextCtrBlock(byte[] block)
+ {
+ if (blocksRemaining == 0)
+ throw new InvalidOperationException("Attempt to process too many blocks");
+
+ blocksRemaining--;
+
+ Pack.UInt32_To_BE(++counter32, counter, 12);
+
+ cipher.ProcessBlock(counter, 0, block, 0);
+ }
+#endif
+
private void ProcessPartial(byte[] buf, int off, int len, byte[] output, int outOff)
{
byte[] ctrBlock = new byte[BlockSize];
@@ -1009,18 +1366,6 @@ namespace Org.BouncyCastle.Crypto.Modes
multiplier.MultiplyH(Y);
}
- private void GetNextCtrBlock(byte[] block)
- {
- if (blocksRemaining == 0)
- throw new InvalidOperationException("Attempt to process too many blocks");
-
- blocksRemaining--;
-
- Pack.UInt32_To_BE(++counter32, counter, 12);
-
- cipher.ProcessBlock(counter, 0, block, 0);
- }
-
private void CheckStatus()
{
if (!initialised)
diff --git a/crypto/src/crypto/modes/GcmSivBlockCipher.cs b/crypto/src/crypto/modes/GcmSivBlockCipher.cs
index d2f17809d..2abe5eece 100644
--- a/crypto/src/crypto/modes/GcmSivBlockCipher.cs
+++ b/crypto/src/crypto/modes/GcmSivBlockCipher.cs
@@ -290,7 +290,7 @@ namespace Org.BouncyCastle.Crypto.Modes
CheckAeadStatus(1);
/* Process the aead */
- theAEADHasher.updateHash(pByte);
+ theAEADHasher.UpdateHash(pByte);
}
public virtual void ProcessAadBytes(byte[] pData, int pOffset, int pLen)
@@ -304,7 +304,7 @@ namespace Org.BouncyCastle.Crypto.Modes
CheckAeadStatus(pLen);
/* Process the aead */
- theAEADHasher.updateHash(pData, pOffset, pLen);
+ theAEADHasher.UpdateHash(pData, pOffset, pLen);
#endif
}
@@ -315,7 +315,7 @@ namespace Org.BouncyCastle.Crypto.Modes
CheckAeadStatus(input.Length);
/* Process the aead */
- theAEADHasher.updateHash(input);
+ theAEADHasher.UpdateHash(input);
}
#endif
@@ -328,7 +328,7 @@ namespace Org.BouncyCastle.Crypto.Modes
if (forEncryption)
{
thePlain.WriteByte(pByte);
- theDataHasher.updateHash(pByte);
+ theDataHasher.UpdateHash(pByte);
}
else
{
@@ -339,18 +339,43 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
- public virtual int ProcessBytes(byte[] pData, int pOffset, int pLen, byte[] pOutput, int pOutOffset)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
{
/* Check that we have initialised */
- CheckStatus(pLen);
+ CheckStatus(1);
+ /* Store the data */
+ if (forEncryption)
+ {
+ thePlain.WriteByte(input);
+ theDataHasher.UpdateHash(input);
+ }
+ else
+ {
+ theEncData.WriteByte(input);
+ }
+
+ /* No data returned */
+ return 0;
+ }
+#endif
+
+ public virtual int ProcessBytes(byte[] pData, int pOffset, int pLen, byte[] pOutput, int pOutOffset)
+ {
Check.DataLength(pData, pOffset, pLen, "input buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessBytes(pData.AsSpan(pOffset, pLen), Spans.FromNullable(pOutput, pOutOffset));
+#else
+ /* Check that we have initialised */
+ CheckStatus(pLen);
+
/* Store the data */
if (forEncryption)
{
thePlain.Write(pData, pOffset, pLen);
- theDataHasher.updateHash(pData, pOffset, pLen);
+ theDataHasher.UpdateHash(pData, pOffset, pLen);
}
else
{
@@ -359,8 +384,31 @@ namespace Org.BouncyCastle.Crypto.Modes
/* No data returned */
return 0;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ /* Check that we have initialised */
+ CheckStatus(input.Length);
+
+ /* Store the data */
+ if (forEncryption)
+ {
+ thePlain.Write(input);
+ theDataHasher.UpdateHash(input);
+ }
+ else
+ {
+ theEncData.Write(input);
+ }
+
+ /* No data returned */
+ return 0;
+ }
+#endif
+
public virtual int DoFinal(byte[] pOutput, int pOffset)
{
Check.OutputLength(pOutput, pOffset, GetOutputSize(0), "output buffer too short");
@@ -500,7 +548,7 @@ namespace Org.BouncyCastle.Crypto.Modes
Arrays.Fill(theGHash, (byte)0);
if (theInitialAEAD != null)
{
- theAEADHasher.updateHash(theInitialAEAD, 0, theInitialAEAD.Length);
+ theAEADHasher.UpdateHash(theInitialAEAD, 0, theInitialAEAD.Length);
}
}
@@ -619,7 +667,7 @@ namespace Org.BouncyCastle.Crypto.Modes
/* Write data to plain dataStream */
thePlain.Write(myMask, 0, myLen);
- theDataHasher.updateHash(myMask, 0, myLen);
+ theDataHasher.UpdateHash(myMask, 0, myLen);
/* Adjust counters */
myRemaining -= myLen;
@@ -911,10 +959,10 @@ namespace Org.BouncyCastle.Crypto.Modes
* update hash.
* @param pByte the byte
*/
- internal void updateHash(byte pByte)
+ internal void UpdateHash(byte pByte)
{
theByte[0] = pByte;
- updateHash(theByte, 0, 1);
+ UpdateHash(theByte, 0, 1);
}
/**
@@ -923,7 +971,7 @@ namespace Org.BouncyCastle.Crypto.Modes
* @param pOffset the offset within the buffer
* @param pLen the length of data
*/
- internal void updateHash(byte[] pBuffer, int pOffset, int pLen)
+ internal void UpdateHash(byte[] pBuffer, int pOffset, int pLen)
{
/* If we should process the cache */
int mySpace = BUFLEN - numActive;
@@ -967,7 +1015,7 @@ namespace Org.BouncyCastle.Crypto.Modes
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
- internal void updateHash(ReadOnlySpan<byte> buffer)
+ internal void UpdateHash(ReadOnlySpan<byte> buffer)
{
int pLen = buffer.Length;
diff --git a/crypto/src/crypto/modes/IAeadCipher.cs b/crypto/src/crypto/modes/IAeadCipher.cs
index f80f3a247..5e92c78f3 100644
--- a/crypto/src/crypto/modes/IAeadCipher.cs
+++ b/crypto/src/crypto/modes/IAeadCipher.cs
@@ -59,6 +59,10 @@ namespace Org.BouncyCastle.Crypto.Modes
*/
int ProcessByte(byte input, byte[] outBytes, int outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int ProcessByte(byte input, Span<byte> output);
+#endif
+
/**
* Process a block of bytes from in putting the result into out.
*
@@ -72,6 +76,10 @@ namespace Org.BouncyCastle.Crypto.Modes
*/
int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output);
+#endif
+
/**
* Finish the operation either appending or verifying the MAC at the end of the data.
*
diff --git a/crypto/src/crypto/modes/KCcmBlockCipher.cs b/crypto/src/crypto/modes/KCcmBlockCipher.cs
index db86cf890..493bf56e1 100644
--- a/crypto/src/crypto/modes/KCcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/KCcmBlockCipher.cs
@@ -7,7 +7,8 @@ using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Modes
{
- public class KCcmBlockCipher: IAeadBlockCipher
+ public class KCcmBlockCipher
+ : IAeadBlockCipher
{
private static readonly int BYTES_IN_INT = 4;
private static readonly int BITS_IN_BYTE = 8;
@@ -234,6 +235,15 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
+ {
+ data.WriteByte(input);
+
+ return 0;
+ }
+#endif
+
public virtual int ProcessBytes(byte[] input, int inOff, int inLen, byte[] output, int outOff)
{
Check.DataLength(input, inOff, inLen, "input buffer too short");
@@ -243,6 +253,15 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ data.Write(input);
+
+ return 0;
+ }
+#endif
+
public int ProcessPacket(byte[] input, int inOff, int len, byte[] output, int outOff)
{
Check.DataLength(input, inOff, len, "input buffer too short");
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index 8281c96c1..a4eaa08bd 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -312,8 +312,24 @@ namespace Org.BouncyCastle.Crypto.Modes
return 0;
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessByte(byte input, Span<byte> output)
+ {
+ mainBlock[mainBlockPos] = input;
+ if (++mainBlockPos == mainBlock.Length)
+ {
+ ProcessMainBlock(output);
+ return BLOCK_SIZE;
+ }
+ return 0;
+ }
+#endif
+
public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessBytes(input.AsSpan(inOff, len), Spans.FromNullable(output, outOff));
+#else
int resultLen = 0;
for (int i = 0; i < len; ++i)
@@ -327,7 +343,28 @@ namespace Org.BouncyCastle.Crypto.Modes
}
return resultLen;
+#endif
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+ {
+ int len = input.Length;
+ int resultLen = 0;
+
+ for (int i = 0; i < len; ++i)
+ {
+ mainBlock[mainBlockPos] = input[i];
+ if (++mainBlockPos == mainBlock.Length)
+ {
+ ProcessMainBlock(output[resultLen..]);
+ resultLen += BLOCK_SIZE;
+ }
+ }
+
+ return resultLen;
}
+#endif
public virtual int DoFinal(byte[] output, int outOff)
{
@@ -572,6 +609,38 @@ namespace Org.BouncyCastle.Crypto.Modes
}
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ protected virtual void ProcessMainBlock(Span<byte> output)
+ {
+ Check.DataLength(output, BLOCK_SIZE, "output buffer too short");
+
+ /*
+ * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
+ */
+
+ if (forEncryption)
+ {
+ Xor(Checksum, mainBlock);
+ mainBlockPos = 0;
+ }
+
+ Xor(OffsetMAIN, GetLSub(OCB_ntz(++mainBlockCount)));
+
+ Xor(mainBlock, OffsetMAIN);
+ mainCipher.ProcessBlock(mainBlock, 0, mainBlock, 0);
+ Xor(mainBlock, OffsetMAIN);
+
+ mainBlock.AsSpan(0, BLOCK_SIZE).CopyTo(output);
+
+ if (!forEncryption)
+ {
+ Xor(Checksum, mainBlock);
+ Array.Copy(mainBlock, BLOCK_SIZE, mainBlock, 0, macSize);
+ mainBlockPos = macSize;
+ }
+ }
+#endif
+
protected virtual void Reset(bool clearMac)
{
hashCipher.Reset();
diff --git a/crypto/src/util/Spans.cs b/crypto/src/util/Spans.cs
new file mode 100644
index 000000000..5e1b3737c
--- /dev/null
+++ b/crypto/src/util/Spans.cs
@@ -0,0 +1,18 @@
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System;
+using System.Runtime.CompilerServices;
+
+#nullable enable
+
+namespace Org.BouncyCastle.Utilities
+{
+ internal static class Spans
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static Span<T> FromNullable<T>(T[]? array, int start)
+ {
+ return array == null ? Span<T>.Empty : array.AsSpan(start);
+ }
+ }
+}
+#endif
|