summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs41
1 files changed, 28 insertions, 13 deletions
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 9ab3a8e8c..26b590ef9 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -1084,14 +1084,14 @@ namespace Org.BouncyCastle.Crypto.Modes
                 InitCipher();
             }
 
-            Span<byte> ctrBlock = stackalloc byte[BlockSize];
+            Span<byte> ctrBlocks = stackalloc byte[BlockSize * 2];
+            GetNextCtrBlocks2(ctrBlocks);
 
-            GetNextCtrBlock(ctrBlock);
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
                 var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
-                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlocks);
                 var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
@@ -1105,10 +1105,10 @@ 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]);
+                    byte c0 = (byte)(ctrBlocks[i + 0] ^ input[i + 0]);
+                    byte c1 = (byte)(ctrBlocks[i + 1] ^ input[i + 1]);
+                    byte c2 = (byte)(ctrBlocks[i + 2] ^ input[i + 2]);
+                    byte c3 = (byte)(ctrBlocks[i + 3] ^ input[i + 3]);
 
                     S[i + 0] ^= c0;
                     S[i + 1] ^= c1;
@@ -1125,13 +1125,13 @@ namespace Org.BouncyCastle.Crypto.Modes
 
             input = input[BlockSize..];
             output = output[BlockSize..];
+            ctrBlocks = ctrBlocks[BlockSize..];
 
-            GetNextCtrBlock(ctrBlock);
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
                 var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
-                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlocks);
                 var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
@@ -1145,10 +1145,10 @@ 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]);
+                    byte c0 = (byte)(ctrBlocks[i + 0] ^ input[i + 0]);
+                    byte c1 = (byte)(ctrBlocks[i + 1] ^ input[i + 1]);
+                    byte c2 = (byte)(ctrBlocks[i + 2] ^ input[i + 2]);
+                    byte c3 = (byte)(ctrBlocks[i + 3] ^ input[i + 3]);
 
                     S[i + 0] ^= c0;
                     S[i + 1] ^= c1;
@@ -1179,6 +1179,21 @@ namespace Org.BouncyCastle.Crypto.Modes
             cipher.ProcessBlock(counter, block);
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private void GetNextCtrBlocks2(Span<byte> blocks)
+        {
+            if (blocksRemaining < 2)
+                throw new InvalidOperationException("Attempt to process too many blocks");
+
+            blocksRemaining -= 2;
+
+            Pack.UInt32_To_BE(++counter32, counter, 12);
+            cipher.ProcessBlock(counter, blocks);
+
+            Pack.UInt32_To_BE(++counter32, counter, 12);
+            cipher.ProcessBlock(counter, blocks[BlockSize..]);
+        }
+
         private void ProcessPartial(Span<byte> partialBlock, Span<byte> output)
         {
             Span<byte> ctrBlock = stackalloc byte[BlockSize];