diff --git a/crypto/src/crypto/modes/KCcmBlockCipher.cs b/crypto/src/crypto/modes/KCcmBlockCipher.cs
index afa68a794..db86cf890 100644
--- a/crypto/src/crypto/modes/KCcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/KCcmBlockCipher.cs
@@ -248,6 +248,9 @@ namespace Org.BouncyCastle.Crypto.Modes
Check.DataLength(input, inOff, len, "input buffer too short");
Check.OutputLength(output, outOff, len, "output buffer too short");
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return ProcessPacket(input.AsSpan(inOff, len), output.AsSpan(outOff));
+#else
if (associatedText.Length > 0)
{
byte[] aad = associatedText.GetBuffer();
@@ -268,7 +271,7 @@ namespace Org.BouncyCastle.Crypto.Modes
int totalLength = len;
while (totalLength > 0)
{
- ProcessBlock(input, inOff, len, output, outOff);
+ ProcessBlock(input, inOff, output, outOff);
totalLength -= engine.GetBlockSize();
inOff += engine.GetBlockSize();
outOff += engine.GetBlockSize();
@@ -302,7 +305,7 @@ namespace Org.BouncyCastle.Crypto.Modes
for (int blockNum = 0; blockNum<blocks; blockNum++)
{
- ProcessBlock(input, inOff, len, output, outOff);
+ ProcessBlock(input, inOff, output, outOff);
inOff += engine.GetBlockSize();
outOff += engine.GetBlockSize();
@@ -350,43 +353,190 @@ namespace Org.BouncyCastle.Crypto.Modes
return len - macSize;
}
+#endif
}
- private void ProcessBlock(byte[] input, int inOff, int len, byte[] output, int outOff)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public int ProcessPacket(ReadOnlySpan<byte> input, Span<byte> output)
{
+ int len = input.Length;
+ Check.OutputLength(output, len, "output buffer too short");
+
+ if (associatedText.Length > 0)
+ {
+ byte[] aad = associatedText.GetBuffer();
+ int aadLen = Convert.ToInt32(associatedText.Length);
+
+ int dataLen = Convert.ToInt32(data.Length) - (forEncryption ? 0 : macSize);
+
+ ProcessAAD(aad, 0, aadLen, dataLen);
+ }
+
+ int blockSize = engine.GetBlockSize(), index = 0;
+ if (forEncryption)
+ {
+ Check.DataLength(len % blockSize != 0, "partial blocks not supported");
+
+ CalculateMac(input);
+ engine.ProcessBlock(nonce, s);
+
+ int totalLength = len;
+ while (totalLength > 0)
+ {
+ ProcessBlock(input[index..], output[index..]);
+ totalLength -= blockSize;
+ index += blockSize;
+ }
+
+ for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
+ {
+ s[byteIndex] += counter[byteIndex];
+ }
+
+ engine.ProcessBlock(s, buffer);
+
+ for (int byteIndex = 0; byteIndex < macSize; byteIndex++)
+ {
+ output[index + byteIndex] = (byte)(buffer[byteIndex] ^ macBlock[byteIndex]);
+ }
+
+ Array.Copy(macBlock, 0, mac, 0, macSize);
+
+ Reset();
+
+ return len + macSize;
+ }
+ else
+ {
+ Check.DataLength((len - macSize) % blockSize != 0, "partial blocks not supported");
+
+ engine.ProcessBlock(nonce, 0, s, 0);
+
+ int blocks = len / engine.GetBlockSize();
+
+ for (int blockNum = 0; blockNum < blocks; blockNum++)
+ {
+ ProcessBlock(input[index..], output[index..]);
+ index += blockSize;
+ }
+
+ if (len > index)
+ {
+ for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
+ {
+ s[byteIndex] += counter[byteIndex];
+ }
+
+ engine.ProcessBlock(s, buffer);
+
+ for (int byteIndex = 0; byteIndex < macSize; byteIndex++)
+ {
+ output[index + byteIndex] = (byte)(buffer[byteIndex] ^ input[index + byteIndex]);
+ }
+ index += macSize;
+ }
+
+ for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
+ {
+ s[byteIndex] += counter[byteIndex];
+ }
+
+ engine.ProcessBlock(s, buffer);
+
+ output[(index - macSize)..index].CopyTo(buffer);
+ CalculateMac(output[..(index - macSize)]);
+
+ Array.Copy(macBlock, 0, mac, 0, macSize);
+
+ Span<byte> calculatedMac = stackalloc byte[macSize];
+
+ buffer.AsSpan(0, macSize).CopyTo(calculatedMac);
+
+ if (!Arrays.ConstantTimeAreEqual(mac.AsSpan(0, macSize), calculatedMac))
+ throw new InvalidCipherTextException("mac check failed");
+
+ Reset();
+
+ return len - macSize;
+ }
+ }
+#endif
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ private void CalculateMac(ReadOnlySpan<byte> authText)
+ {
+ int blockSize = engine.GetBlockSize();
+
+ while (!authText.IsEmpty)
+ {
+ for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
+ {
+ macBlock[byteIndex] ^= authText[byteIndex];
+ }
+
+ engine.ProcessBlock(macBlock, macBlock);
+
+ authText = authText[blockSize..];
+ }
+ }
+
+ private void ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+ {
for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
{
s[byteIndex] += counter[byteIndex];
}
- engine.ProcessBlock(s, 0, buffer, 0);
+ engine.ProcessBlock(s, buffer);
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ int blockSize = engine.GetBlockSize();
+ for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
{
- output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ input[inOff + byteIndex]);
+ output[byteIndex] = (byte)(buffer[byteIndex] ^ input[byteIndex]);
}
}
-
+#else
private void CalculateMac(byte[] authText, int authOff, int len)
{
+ int blockSize = engine.GetBlockSize();
int totalLen = len;
while (totalLen > 0)
{
- for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
{
macBlock[byteIndex] ^= authText[authOff + byteIndex];
}
engine.ProcessBlock(macBlock, 0, macBlock, 0);
- totalLen -= engine.GetBlockSize();
- authOff += engine.GetBlockSize();
+ totalLen -= blockSize;
+ authOff += blockSize;
}
}
+ private void ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+
+ for (int byteIndex = 0; byteIndex < counter.Length; byteIndex++)
+ {
+ s[byteIndex] += counter[byteIndex];
+ }
+
+ engine.ProcessBlock(s, 0, buffer, 0);
+
+ for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ {
+ output[outOff + byteIndex] = (byte)(buffer[byteIndex] ^ input[inOff + byteIndex]);
+ }
+ }
+#endif
+
public virtual int DoFinal(byte[] output, int outOff)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return DoFinal(output.AsSpan(outOff));
+#else
byte[] buf = data.GetBuffer();
int bufLen = Convert.ToInt32(data.Length);
@@ -395,8 +545,23 @@ namespace Org.BouncyCastle.Crypto.Modes
Reset();
return len;
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public virtual int DoFinal(Span<byte> output)
+ {
+ byte[] buf = data.GetBuffer();
+ int bufLen = Convert.ToInt32(data.Length);
+
+ int len = ProcessPacket(buf.AsSpan(0, bufLen), output);
+
+ Reset();
+
+ return len;
+ }
+#endif
+
public virtual byte[] GetMac()
{
return Arrays.Clone(mac);
|