diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2017-10-18 00:39:44 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2017-10-18 00:39:44 +0700 |
commit | f8d638b86b87db904fea276064652b9be0492a06 (patch) | |
tree | 28128ea34aedeb1131e6a9faf7a09048991657b7 | |
parent | Fix test for .NET 1.1 (diff) | |
download | BouncyCastle.NET-ed25519-f8d638b86b87db904fea276064652b9be0492a06.tar.xz |
Perf. opts. in GCMBlockCipher
- avoid double-copying for long encryption inputs
-rw-r--r-- | crypto/src/crypto/modes/GCMBlockCipher.cs | 134 | ||||
-rw-r--r-- | crypto/src/crypto/modes/gcm/GcmUtilities.cs | 34 |
2 files changed, 127 insertions, 41 deletions
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs index a6cd00401..b5919aead 100644 --- a/crypto/src/crypto/modes/GCMBlockCipher.cs +++ b/crypto/src/crypto/modes/GCMBlockCipher.cs @@ -306,7 +306,16 @@ namespace Org.BouncyCastle.Crypto.Modes bufBlock[bufOff] = input; if (++bufOff == bufBlock.Length) { - OutputBlock(output, outOff); + ProcessBlock(bufBlock, 0, output, outOff); + if (forEncryption) + { + bufOff = 0; + } + else + { + Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize); + bufOff = macSize; + } return BlockSize; } return 0; @@ -321,41 +330,58 @@ namespace Org.BouncyCastle.Crypto.Modes { CheckStatus(); - if (input.Length < (inOff + len)) - throw new DataLengthException("Input buffer too short"); + Check.DataLength(input, inOff, len, "input buffer too short"); int resultLen = 0; - for (int i = 0; i < len; ++i) + if (forEncryption) { - bufBlock[bufOff] = input[inOff + i]; - if (++bufOff == bufBlock.Length) + if (bufOff != 0) { - OutputBlock(output, outOff + resultLen); - resultLen += BlockSize; + while (len > 0) + { + --len; + bufBlock[bufOff] = input[inOff++]; + if (++bufOff == BlockSize) + { + ProcessBlock(bufBlock, 0, output, outOff); + bufOff = 0; + resultLen += BlockSize; + break; + } + } } - } - return resultLen; - } + while (len >= BlockSize) + { + ProcessBlock(input, inOff, output, outOff + resultLen); + inOff += BlockSize; + len -= BlockSize; + resultLen += BlockSize; + } - private void OutputBlock(byte[] output, int offset) - { - Check.OutputLength(output, offset, BlockSize, "Output buffer too short"); - if (totalLength == 0) - { - InitCipher(); - } - gCTRBlock(bufBlock, output, offset); - if (forEncryption) - { - bufOff = 0; + if (len > 0) + { + Array.Copy(input, inOff, bufBlock, 0, len); + bufOff = len; + } } else { - Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize); - bufOff = macSize; + for (int i = 0; i < len; ++i) + { + bufBlock[bufOff] = input[inOff + i]; + if (++bufOff == bufBlock.Length) + { + ProcessBlock(bufBlock, 0, output, outOff + resultLen); + Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize); + bufOff = macSize; + resultLen += BlockSize; + } + } } + + return resultLen; } public int DoFinal(byte[] output, int outOff) @@ -385,7 +411,7 @@ namespace Org.BouncyCastle.Crypto.Modes if (extra > 0) { - gCTRPartial(bufBlock, 0, extra, output, outOff); + ProcessPartial(bufBlock, 0, extra, output, outOff); } atLength += (uint)atBlockPos; @@ -515,27 +541,50 @@ namespace Org.BouncyCastle.Crypto.Modes } } - private void gCTRBlock(byte[] block, byte[] output, int outOff) + private void ProcessBlock(byte[] buf, int bufOff, byte[] output, int outOff) { - byte[] tmp = GetNextCounterBlock(); + Check.OutputLength(output, outOff, BlockSize, "Output buffer too short"); - GcmUtilities.Xor(tmp, block); - Array.Copy(tmp, 0, output, outOff, BlockSize); + if (totalLength == 0) + { + InitCipher(); + } + + byte[] ctrBlock = new byte[BlockSize]; + GetNextCtrBlock(ctrBlock); - gHASHBlock(S, forEncryption ? tmp : block); + if (forEncryption) + { + GcmUtilities.Xor(ctrBlock, buf, bufOff); + gHASHBlock(S, ctrBlock); + Array.Copy(ctrBlock, 0, output, outOff, BlockSize); + } + else + { + gHASHBlock(S, buf, bufOff); + GcmUtilities.Xor(ctrBlock, 0, buf, bufOff, output, outOff); + } totalLength += BlockSize; } - private void gCTRPartial(byte[] buf, int off, int len, byte[] output, int outOff) + private void ProcessPartial(byte[] buf, int off, int len, byte[] output, int outOff) { - byte[] tmp = GetNextCounterBlock(); + byte[] ctrBlock = new byte[BlockSize]; + GetNextCtrBlock(ctrBlock); - GcmUtilities.Xor(tmp, buf, off, len); - Array.Copy(tmp, 0, output, outOff, len); - - gHASHPartial(S, forEncryption ? tmp : buf, 0, len); + if (forEncryption) + { + GcmUtilities.Xor(buf, off, ctrBlock, 0, len); + gHASHPartial(S, buf, off, len); + } + else + { + gHASHPartial(S, buf, off, len); + GcmUtilities.Xor(buf, off, ctrBlock, 0, len); + } + Array.Copy(buf, off, output, outOff, len); totalLength += (uint)len; } @@ -554,13 +603,19 @@ namespace Org.BouncyCastle.Crypto.Modes multiplier.MultiplyH(Y); } + private void gHASHBlock(byte[] Y, byte[] b, int off) + { + GcmUtilities.Xor(Y, b, off); + multiplier.MultiplyH(Y); + } + private void gHASHPartial(byte[] Y, byte[] b, int off, int len) { GcmUtilities.Xor(Y, b, off, len); multiplier.MultiplyH(Y); } - private byte[] GetNextCounterBlock() + private void GetNextCtrBlock(byte[] block) { if (blocksRemaining == 0) throw new InvalidOperationException("Attempt to process too many blocks"); @@ -573,10 +628,7 @@ namespace Org.BouncyCastle.Crypto.Modes c += counter[13]; counter[13] = (byte)c; c >>= 8; c += counter[12]; counter[12] = (byte)c; - byte[] tmp = new byte[BlockSize]; - // TODO Sure would be nice if ciphers could operate on int[] - cipher.ProcessBlock(counter, 0, tmp, 0); - return tmp; + cipher.ProcessBlock(counter, 0, block, 0); } private void CheckStatus() diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs index d8ab2ca73..22e0067a5 100644 --- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs +++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs @@ -267,6 +267,32 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm while (i < 16); } + internal static void Xor(byte[] x, byte[] y, int yOff) + { + int i = 0; + do + { + x[i] ^= y[yOff + i]; ++i; + x[i] ^= y[yOff + i]; ++i; + x[i] ^= y[yOff + i]; ++i; + x[i] ^= y[yOff + i]; ++i; + } + while (i < 16); + } + + internal static void Xor(byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff) + { + int i = 0; + do + { + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); ++i; + } + while (i < 16); + } + internal static void Xor(byte[] x, byte[] y, int yOff, int yLen) { while (--yLen >= 0) @@ -275,6 +301,14 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm } } + internal static void Xor(byte[] x, int xOff, byte[] y, int yOff, int len) + { + while (--len >= 0) + { + x[xOff + len] ^= y[yOff + len]; + } + } + internal static void Xor(byte[] x, byte[] y, byte[] z) { int i = 0; |