summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-03-07 21:11:22 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-03-07 21:11:22 +0700
commit476b6fdf325b34933a1cb39c6c75121de7a780fa (patch)
treeed2d6af692f8c3d93e2d2cbf8ee8adccc3632fd9
parentTighten ChangeCipherSpec ordering checks (diff)
downloadBouncyCastle.NET-ed25519-476b6fdf325b34933a1cb39c6c75121de7a780fa.tar.xz
Various updates from Java build
-rw-r--r--crypto/crypto.csproj10
-rw-r--r--crypto/src/crypto/BufferedBlockCipher.cs22
-rw-r--r--crypto/src/crypto/Check.cs25
-rw-r--r--crypto/src/crypto/OutputLengthException.cs28
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs25
-rw-r--r--crypto/src/crypto/engines/AesFastEngine.cs25
-rw-r--r--crypto/src/crypto/engines/AesLightEngine.cs25
-rw-r--r--crypto/src/crypto/engines/BlowfishEngine.cs15
-rw-r--r--crypto/src/crypto/engines/CamelliaEngine.cs21
-rw-r--r--crypto/src/crypto/engines/CamelliaLightEngine.cs21
-rw-r--r--crypto/src/crypto/engines/Cast5Engine.cs11
-rw-r--r--crypto/src/crypto/engines/ChaChaEngine.cs3
-rw-r--r--crypto/src/crypto/engines/DesEdeEngine.cs7
-rw-r--r--crypto/src/crypto/engines/DesEdeWrapEngine.cs8
-rw-r--r--crypto/src/crypto/engines/DesEngine.cs11
-rw-r--r--crypto/src/crypto/engines/ElGamalEngine.cs10
-rw-r--r--crypto/src/crypto/engines/GOST28147Engine.cs27
-rw-r--r--crypto/src/crypto/engines/HC128Engine.cs19
-rw-r--r--crypto/src/crypto/engines/HC256Engine.cs19
-rw-r--r--crypto/src/crypto/engines/ISAACEngine.cs17
-rw-r--r--crypto/src/crypto/engines/IdeaEngine.cs26
-rw-r--r--crypto/src/crypto/engines/IesEngine.cs4
-rw-r--r--crypto/src/crypto/engines/NaccacheSternEngine.cs16
-rw-r--r--crypto/src/crypto/engines/NoekeonEngine.cs21
-rw-r--r--crypto/src/crypto/engines/NullEngine.cs21
-rw-r--r--crypto/src/crypto/engines/RC2Engine.cs22
-rw-r--r--crypto/src/crypto/engines/RC2WrapEngine.cs8
-rw-r--r--crypto/src/crypto/engines/RC4Engine.cs25
-rw-r--r--crypto/src/crypto/engines/RC532Engine.cs13
-rw-r--r--crypto/src/crypto/engines/RC564Engine.cs13
-rw-r--r--crypto/src/crypto/engines/RC6Engine.cs22
-rw-r--r--crypto/src/crypto/engines/RFC3211WrapEngine.cs8
-rw-r--r--crypto/src/crypto/engines/RFC3394WrapEngine.cs8
-rw-r--r--crypto/src/crypto/engines/RSABlindedEngine.cs10
-rw-r--r--crypto/src/crypto/engines/RSABlindingEngine.cs10
-rw-r--r--crypto/src/crypto/engines/RSACoreEngine.cs12
-rw-r--r--crypto/src/crypto/engines/RijndaelEngine.cs30
-rw-r--r--crypto/src/crypto/engines/RsaEngine.cs10
-rw-r--r--crypto/src/crypto/engines/SEEDEngine.cs21
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs27
-rw-r--r--crypto/src/crypto/engines/SerpentEngine.cs22
-rw-r--r--crypto/src/crypto/engines/SkipjackEngine.cs26
-rw-r--r--crypto/src/crypto/engines/TEAEngine.cs21
-rw-r--r--crypto/src/crypto/engines/ThreefishEngine.cs12
-rw-r--r--crypto/src/crypto/engines/TwofishEngine.cs9
-rw-r--r--crypto/src/crypto/engines/VMPCEngine.cs11
-rw-r--r--crypto/src/crypto/engines/XSalsa20Engine.cs2
-rw-r--r--crypto/src/crypto/engines/XTEAEngine.cs21
-rw-r--r--crypto/src/crypto/generators/RsaKeyPairGenerator.cs173
-rw-r--r--crypto/src/crypto/modes/CcmBlockCipher.cs127
-rw-r--r--crypto/src/crypto/modes/EAXBlockCipher.cs55
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs13
-rw-r--r--crypto/src/crypto/modes/OCBBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs23
-rw-r--r--crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs7
-rw-r--r--crypto/test/src/crypto/test/CCMTest.cs47
56 files changed, 666 insertions, 584 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index fdd5c152b..3f713e1c0 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -2964,6 +2964,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\Check.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\CipherKeyGenerator.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -3069,6 +3074,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\OutputLengthException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\PBEParametersGenerator.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/crypto/BufferedBlockCipher.cs b/crypto/src/crypto/BufferedBlockCipher.cs
index 3a98798a2..9684ed93e 100644
--- a/crypto/src/crypto/BufferedBlockCipher.cs
+++ b/crypto/src/crypto/BufferedBlockCipher.cs
@@ -223,13 +223,10 @@ namespace Org.BouncyCastle.Crypto
 
 			if (outLength > 0)
 			{
-				if ((outOff + outLength) > output.Length)
-				{
-					throw new DataLengthException("output buffer too short");
-				}
+                Check.OutputLength(output, outOff, outLength, "output buffer too short");
 			}
 
-			int resultLen = 0;
+            int resultLen = 0;
 			int gapLen = buf.Length - bufOff;
 			if (length > gapLen)
 			{
@@ -339,17 +336,10 @@ namespace Org.BouncyCastle.Crypto
 			{
 				if (bufOff != 0)
 				{
-					if (!cipher.IsPartialBlockOkay)
-					{
-						throw new DataLengthException("data not block size aligned");
-					}
-	
-					if (outOff + bufOff > output.Length)
-					{
-						throw new DataLengthException("output buffer too short for DoFinal()");
-					}
-	
-					// NB: Can't copy directly, or we may write too much output
+                    Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
+                    Check.OutputLength(output, outOff, bufOff, "output buffer too short for DoFinal()");
+
+                    // NB: Can't copy directly, or we may write too much output
 					cipher.ProcessBlock(buf, 0, buf, 0);
 					Array.Copy(buf, 0, output, outOff, bufOff);
 				}
diff --git a/crypto/src/crypto/Check.cs b/crypto/src/crypto/Check.cs
new file mode 100644
index 000000000..96a05c64b
--- /dev/null
+++ b/crypto/src/crypto/Check.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    internal class Check
+    {
+        internal static void DataLength(bool condition, string msg)
+        {
+            if (condition)
+                throw new DataLengthException(msg);
+        }
+
+        internal static void DataLength(byte[] buf, int off, int len, string msg)
+        {
+            if (off + len > buf.Length)
+                throw new DataLengthException(msg);
+        }
+
+        internal static void OutputLength(byte[] buf, int off, int len, string msg)
+        {
+            if (off + len > buf.Length)
+                throw new OutputLengthException(msg);
+        }
+    }
+}
diff --git a/crypto/src/crypto/OutputLengthException.cs b/crypto/src/crypto/OutputLengthException.cs
new file mode 100644
index 000000000..e1cf44925
--- /dev/null
+++ b/crypto/src/crypto/OutputLengthException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class OutputLengthException
+        : DataLengthException
+    {
+        public OutputLengthException()
+        {
+        }
+
+        public OutputLengthException(
+            string message)
+            : base(message)
+        {
+        }
+
+        public OutputLengthException(
+            string message,
+            Exception exception)
+            : base(message, exception)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 0cdd868fa..9d7f76c05 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -363,7 +363,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -377,41 +377,32 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.forEncryption = forEncryption;
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "AES"; }
         }
 
-        public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
         {
             get { return false; }
         }
 
-        public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
             int		outOff)
         {
             if (WorkingKey == null)
-            {
                 throw new InvalidOperationException("AES engine not initialised");
-            }
 
-            if ((inOff + (32 / 2)) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-
-            if ((outOff + (32 / 2)) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, 16, "input buffer too short");
+            Check.OutputLength(output, outOff, 16, "output buffer too short");
 
             UnPackBlock(input, inOff);
 
@@ -429,7 +420,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BLOCK_SIZE;
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
         }
 
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index 38d3a5841..a1b544568 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -695,7 +695,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -709,41 +709,32 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.forEncryption = forEncryption;
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "AES"; }
         }
 
-        public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
         {
             get { return false; }
         }
 
-        public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[] input,
             int inOff,
             byte[] output,
             int outOff)
         {
             if (WorkingKey == null)
-            {
                 throw new InvalidOperationException("AES engine not initialised");
-            }
 
-            if ((inOff + (32 / 2)) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-
-            if ((outOff + (32 / 2)) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, 16, "input buffer too short");
+            Check.OutputLength(output, outOff, 16, "output buffer too short");
 
             UnPackBlock(input, inOff);
 
@@ -761,7 +752,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BLOCK_SIZE;
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
         }
 
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index 54f2d2e88..a6b9e3bd4 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -258,7 +258,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -272,41 +272,32 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.forEncryption = forEncryption;
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "AES"; }
         }
 
-        public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
         {
             get { return false; }
         }
 
-        public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
             int		outOff)
         {
             if (WorkingKey == null)
-            {
                 throw new InvalidOperationException("AES engine not initialised");
-            }
 
-            if ((inOff + (32 / 2)) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-
-            if ((outOff + (32 / 2)) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, 16, "input buffer too short");
+            Check.OutputLength(output, outOff, 16, "output buffer too short");
 
             UnPackBlock(input, inOff);
 
@@ -324,7 +315,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BLOCK_SIZE;
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
         }
 
diff --git a/crypto/src/crypto/engines/BlowfishEngine.cs b/crypto/src/crypto/engines/BlowfishEngine.cs
index 8f80f712e..7b50e832f 100644
--- a/crypto/src/crypto/engines/BlowfishEngine.cs
+++ b/crypto/src/crypto/engines/BlowfishEngine.cs
@@ -296,7 +296,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         //====================================
 
         private static readonly int    ROUNDS = 16;
-        private const int    BLOCK_SIZE = 8;  // bytes = 64 bits
+        private const int              BLOCK_SIZE = 8;  // bytes = 64 bits
         private static readonly int    SBOX_SK = 256;
         private static readonly int    P_SZ = ROUNDS+2;
 
@@ -353,19 +353,10 @@ namespace Org.BouncyCastle.Crypto.Engines
             int		outOff)
         {
             if (workingKey == null)
-            {
                 throw new InvalidOperationException("Blowfish not initialised");
-            }
 
-            if ((inOff + BLOCK_SIZE) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-
-            if ((outOff + BLOCK_SIZE) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
 
             if (encrypting)
             {
diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs
index 8f4a442e9..71bd1b0dc 100644
--- a/crypto/src/crypto/engines/CamelliaEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaEngine.cs
@@ -611,7 +611,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 		}
 
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -623,22 +623,22 @@ namespace Org.BouncyCastle.Crypto.Engines
 			initialised = true;
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Camellia"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return BLOCK_SIZE;
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	input,
 			int		inOff,
 			byte[]	output,
@@ -646,12 +646,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (!initialised)
 				throw new InvalidOperationException("Camellia engine not initialised");
-			if ((inOff + BLOCK_SIZE) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + BLOCK_SIZE) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			if (_keyIs128)
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            if (_keyIs128)
 			{
 				return processBlock128(input, inOff, output, outOff);
 			}
@@ -661,7 +660,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 			// nothing
 		}
diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs
index a301eb55e..a132227c5 100644
--- a/crypto/src/crypto/engines/CamelliaLightEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -524,22 +524,22 @@ namespace Org.BouncyCastle.Crypto.Engines
 			initialised = false;
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Camellia"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return BLOCK_SIZE;
 		}
 
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -551,7 +551,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			initialised = true;
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	input,
 			int		inOff,
             byte[]	output,
@@ -559,12 +559,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (!initialised)
 				throw new InvalidOperationException("Camellia engine not initialised");
-			if ((inOff + BLOCK_SIZE) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + BLOCK_SIZE) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			if (_keyis128)
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            if (_keyis128)
 			{
 				return processBlock128(input, inOff, output, outOff);
 			}
@@ -574,7 +573,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 	}
diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs
index 4c3f84a55..1af30a335 100644
--- a/crypto/src/crypto/engines/Cast5Engine.cs
+++ b/crypto/src/crypto/engines/Cast5Engine.cs
@@ -329,7 +329,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -360,12 +360,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 			int blockSize = GetBlockSize();
             if (_workingKey == null)
                 throw new InvalidOperationException(AlgorithmName + " not initialised");
-            if ((inOff + blockSize) > input.Length)
-                throw new DataLengthException("Input buffer too short");
-            if ((outOff + blockSize) > output.Length)
-                throw new DataLengthException("Output buffer too short");
 
-			if (_encrypting)
+            Check.DataLength(input, inOff, blockSize, "input buffer too short");
+            Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+            if (_encrypting)
             {
                 return EncryptBlock(input, inOff, output, outOff);
             }
diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs
index f4a7b8fe1..46b59ed2e 100644
--- a/crypto/src/crypto/engines/ChaChaEngine.cs
+++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -162,7 +162,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 				x09 += x14; x04 = R(x04 ^ x09, 12);
 				x03 += x04; x14 = R(x14 ^ x03, 8);
 				x09 += x14; x04 = R(x04 ^ x09, 7);
-
 			}
 
 			x[ 0] = x00 + input[ 0];
@@ -182,8 +181,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			x[14] = x14 + input[14];
 			x[15] = x15 + input[15];
 		}
-
 	}
-
 }
 
diff --git a/crypto/src/crypto/engines/DesEdeEngine.cs b/crypto/src/crypto/engines/DesEdeEngine.cs
index eec4ec59d..bc40b56a8 100644
--- a/crypto/src/crypto/engines/DesEdeEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeEngine.cs
@@ -70,10 +70,9 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (workingKey1 == null)
                 throw new InvalidOperationException("DESede engine not initialised");
-            if ((inOff + BLOCK_SIZE) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + BLOCK_SIZE) > output.Length)
-                throw new DataLengthException("output buffer too short");
+
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
 
             byte[] temp = new byte[BLOCK_SIZE];
 
diff --git a/crypto/src/crypto/engines/DesEdeWrapEngine.cs b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
index fdc71687f..43100a9bd 100644
--- a/crypto/src/crypto/engines/DesEdeWrapEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -52,7 +52,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @param forWrapping
         * @param param
         */
-        public void Init(
+        public virtual void Init(
 			bool				forWrapping,
 			ICipherParameters	parameters)
         {
@@ -103,7 +103,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         *
         * @return
         */
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "DESede"; }
         }
@@ -116,7 +116,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @param inLen
         * @return
         */
-        public byte[] Wrap(
+        public virtual byte[] Wrap(
 			byte[]	input,
 			int		inOff,
 			int		length)
@@ -185,7 +185,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @return
         * @throws InvalidCipherTextException
         */
-        public byte[] Unwrap(
+        public virtual byte[] Unwrap(
 			byte[]	input,
 			int		inOff,
 			int		length)
diff --git a/crypto/src/crypto/engines/DesEngine.cs b/crypto/src/crypto/engines/DesEngine.cs
index 067cf45e3..a6d580bb6 100644
--- a/crypto/src/crypto/engines/DesEngine.cs
+++ b/crypto/src/crypto/engines/DesEngine.cs
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "DES"; }
         }
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
@@ -59,12 +59,11 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (workingKey == null)
                 throw new InvalidOperationException("DES engine not initialised");
-			if ((inOff + BLOCK_SIZE) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + BLOCK_SIZE) > output.Length)
-                throw new DataLengthException("output buffer too short");
 
-			DesFunc(workingKey, input, inOff, output, outOff);
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            DesFunc(workingKey, input, inOff, output, outOff);
 
 			return BLOCK_SIZE;
         }
diff --git a/crypto/src/crypto/engines/ElGamalEngine.cs b/crypto/src/crypto/engines/ElGamalEngine.cs
index 3d256a087..197d7bc15 100644
--- a/crypto/src/crypto/engines/ElGamalEngine.cs
+++ b/crypto/src/crypto/engines/ElGamalEngine.cs
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		private bool forEncryption;
 		private int bitSize;
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "ElGamal"; }
 		}
@@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param forEncryption true if we are encrypting, false otherwise.
 		* @param param the necessary ElGamal key parameters.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return maximum size for an input block.
 		*/
-		public int GetInputBlockSize()
+        public virtual int GetInputBlockSize()
 		{
 			if (forEncryption)
 			{
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return maximum size for an output block.
 		*/
-		public int GetOutputBlockSize()
+        public virtual int GetOutputBlockSize()
 		{
 			if (forEncryption)
 			{
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return the result of the ElGamal process.
 		* @exception DataLengthException the input block is too large.
 		*/
-		public byte[] ProcessBlock(
+        public virtual byte[] ProcessBlock(
 			byte[]	input,
 			int		inOff,
 			int		length)
diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs
index 8eb6f36b5..e37ddaefd 100644
--- a/crypto/src/crypto/engines/GOST28147Engine.cs
+++ b/crypto/src/crypto/engines/GOST28147Engine.cs
@@ -150,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param parameters the parameters required to set up the cipher.
 		* @exception ArgumentException if the parameters argument is inappropriate.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -187,48 +187,39 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Gost28147"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return BlockSize;
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	input,
 			int		inOff,
 			byte[]	output,
 			int		outOff)
 		{
 			if (workingKey == null)
-			{
 				throw new InvalidOperationException("Gost28147 engine not initialised");
-			}
 
-			if ((inOff + BlockSize) > input.Length)
-			{
-				throw new DataLengthException("input buffer too short");
-			}
-
-			if ((outOff + BlockSize) > output.Length)
-			{
-				throw new DataLengthException("output buffer too short");
-			}
+            Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+            Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
 
-			Gost28147Func(workingKey, input, inOff, output, outOff);
+            Gost28147Func(workingKey, input, inOff, output, outOff);
 
 			return BlockSize;
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 
diff --git a/crypto/src/crypto/engines/HC128Engine.cs b/crypto/src/crypto/engines/HC128Engine.cs
index a2d099f87..40c7a4e17 100644
--- a/crypto/src/crypto/engines/HC128Engine.cs
+++ b/crypto/src/crypto/engines/HC128Engine.cs
@@ -142,7 +142,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			cnt = 0;
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "HC-128"; }
 		}
@@ -156,7 +156,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @throws ArgumentException if the params argument is
 		*                                  inappropriate (ie. the key is not 128 bit long).
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -201,7 +201,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return ret;
 		}
 
-		public void ProcessBytes(
+        public virtual void ProcessBytes(
 			byte[]	input,
 			int		inOff,
 			int		len,
@@ -210,24 +210,23 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (!initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
-			if ((inOff + len) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + len) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			for (int i = 0; i < len; i++)
+            Check.DataLength(input, inOff, len, "input buffer too short");
+            Check.OutputLength(output, outOff, len, "output buffer too short");
+
+            for (int i = 0; i < len; i++)
 			{
 				output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
 			}
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 			idx = 0;
 			Init();
 		}
 
-		public byte ReturnByte(byte input)
+        public virtual byte ReturnByte(byte input)
 		{
 			return (byte)(input ^ GetByte());
 		}
diff --git a/crypto/src/crypto/engines/HC256Engine.cs b/crypto/src/crypto/engines/HC256Engine.cs
index da717dab7..6eb360711 100644
--- a/crypto/src/crypto/engines/HC256Engine.cs
+++ b/crypto/src/crypto/engines/HC256Engine.cs
@@ -126,7 +126,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			cnt = 0;
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "HC-256"; }
 		}
@@ -140,7 +140,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @throws ArgumentException if the params argument is
 		*                                  inappropriate (ie. the key is not 256 bit long).
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -185,7 +185,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return ret;
 		}
 
-		public void ProcessBytes(
+        public virtual void ProcessBytes(
 			byte[]	input,
 			int		inOff,
 			int		len,
@@ -194,24 +194,23 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (!initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
-			if ((inOff + len) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + len) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			for (int i = 0; i < len; i++)
+            Check.DataLength(input, inOff, len, "input buffer too short");
+            Check.OutputLength(output, outOff, len, "output buffer too short");
+
+            for (int i = 0; i < len; i++)
 			{
 				output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
 			}
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 			idx = 0;
 			Init();
 		}
 
-		public byte ReturnByte(byte input)
+        public virtual byte ReturnByte(byte input)
 		{
 			return (byte)(input ^ GetByte());
 		}
diff --git a/crypto/src/crypto/engines/ISAACEngine.cs b/crypto/src/crypto/engines/ISAACEngine.cs
index 9c58678a0..f25577130 100644
--- a/crypto/src/crypto/engines/ISAACEngine.cs
+++ b/crypto/src/crypto/engines/ISAACEngine.cs
@@ -35,7 +35,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the params argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption, 
             ICipherParameters	parameters)
         {
@@ -53,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             setKey(p.GetKey());
         }
 
-        public byte ReturnByte(
+        public virtual byte ReturnByte(
             byte input)
         {
             if (index == 0) 
@@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return output;
         }
 
-        public void ProcessBytes(
+        public virtual void ProcessBytes(
             byte[]	input, 
             int		inOff, 
             int		len, 
@@ -77,10 +77,9 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (!initialised)
                 throw new InvalidOperationException(AlgorithmName + " not initialised");
-            if ((inOff + len) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + len) > output.Length)
-                throw new DataLengthException("output buffer too short");
+
+            Check.DataLength(input, inOff, len, "input buffer too short");
+            Check.OutputLength(output, outOff, len, "output buffer too short");
 
             for (int i = 0; i < len; i++)
             {
@@ -94,12 +93,12 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "ISAAC"; }
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
             setKey(workingKey);
         }
diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index 46b5a787c..4909510ac 100644
--- a/crypto/src/crypto/engines/IdeaEngine.cs
+++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -47,7 +47,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -58,43 +58,37 @@ namespace Org.BouncyCastle.Crypto.Engines
                 ((KeyParameter)parameters).GetKey());
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "IDEA"; }
         }
 
-        public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
         {
             get { return false; }
         }
 
-        public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[] input,
             int inOff,
             byte[] output,
             int outOff)
         {
             if (workingKey == null)
-            {
                 throw new InvalidOperationException("IDEA engine not initialised");
-            }
-            if ((inOff + BLOCK_SIZE) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-            if ((outOff + BLOCK_SIZE) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
             IdeaFunc(workingKey, input, inOff, output, outOff);
             return BLOCK_SIZE;
         }
-        public void Reset()
+        public virtual void Reset()
         {
         }
         private static readonly int    MASK = 0xffff;
diff --git a/crypto/src/crypto/engines/IesEngine.cs b/crypto/src/crypto/engines/IesEngine.cs
index 70df3077c..961e3b038 100644
--- a/crypto/src/crypto/engines/IesEngine.cs
+++ b/crypto/src/crypto/engines/IesEngine.cs
@@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @param pubParam the recipient's/sender's public key parameters
         * @param param encoding and derivation parameters.
         */
-        public void Init(
+        public virtual void Init(
             bool                     forEncryption,
             ICipherParameters            privParameters,
             ICipherParameters            pubParameters,
@@ -213,7 +213,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return buf;
         }
 
-        public byte[] ProcessBlock(
+        public virtual byte[] ProcessBlock(
             byte[]  input,
             int     inOff,
             int     inLen)
diff --git a/crypto/src/crypto/engines/NaccacheSternEngine.cs b/crypto/src/crypto/engines/NaccacheSternEngine.cs
index 9ca092351..e547e0caf 100644
--- a/crypto/src/crypto/engines/NaccacheSternEngine.cs
+++ b/crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
 		*      org.bouncycastle.crypto.CipherParameters)
 		*/
-		public void Init(
+		public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public bool Debug
+        public virtual bool Debug
 		{
 			set { this.debug = value; }
 		}
@@ -93,7 +93,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
 		*/
-		public int GetInputBlockSize()
+        public virtual int GetInputBlockSize()
 		{
 			if (forEncryption)
 			{
@@ -113,7 +113,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
 		*/
-		public int GetOutputBlockSize()
+        public virtual int GetOutputBlockSize()
 		{
 			if (forEncryption)
 			{
@@ -134,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
 		*      int, int)
 		*/
-		public byte[] ProcessBlock(
+        public virtual byte[] ProcessBlock(
 			byte[]	inBytes,
 			int		inOff,
 			int		length)
@@ -245,7 +245,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return The byte[] representation of the encrypted BigInteger (i.e.
 		*         crypted.toByteArray())
 		*/
-		public byte[] Encrypt(
+        public virtual byte[] Encrypt(
 			BigInteger plain)
 		{
 			// Always return modulus size values 0-padded at the beginning
@@ -273,7 +273,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return encrypt((block1 + block2) mod sigma)
 		* @throws InvalidCipherTextException
 		*/
-		public byte[] AddCryptedBlocks(
+        public virtual byte[] AddCryptedBlocks(
 			byte[] block1,
 			byte[] block2)
 		{
@@ -329,7 +329,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return the data after it went through the NaccacheSternEngine.
 		* @throws InvalidCipherTextException
 		*/
-		public byte[] ProcessData(
+        public virtual byte[] ProcessData(
 			byte[] data)
 		{
 			if (debug)
diff --git a/crypto/src/crypto/engines/NoekeonEngine.cs b/crypto/src/crypto/engines/NoekeonEngine.cs
index b73e696a9..dd78a4ea5 100644
--- a/crypto/src/crypto/engines/NoekeonEngine.cs
+++ b/crypto/src/crypto/engines/NoekeonEngine.cs
@@ -42,17 +42,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 			_initialised = false;
 		}
 
-		public string AlgorithmName
+		public virtual string AlgorithmName
 		{
 			get { return "Noekeon"; }
 		}
 
-		public bool IsPartialBlockOkay
+		public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return GenericSize;
 		}
@@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @exception ArgumentException if the params argument is
 		* inappropriate.
 		*/
-		public void Init(
+		public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -80,7 +80,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			setKey(p.GetKey());
 		}
 
-		public int ProcessBlock(
+		public virtual int ProcessBlock(
 			byte[]	input,
 			int		inOff,
 			byte[]	output,
@@ -88,17 +88,16 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (!_initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
-			if ((inOff + GenericSize) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + GenericSize) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			return _forEncryption
+            Check.DataLength(input, inOff, GenericSize, "input buffer too short");
+            Check.OutputLength(output, outOff, GenericSize, "output buffer too short");
+
+            return _forEncryption
 				?	encryptBlock(input, inOff, output, outOff)
 				:	decryptBlock(input, inOff, output, outOff);
 		}
 
-		public void Reset()
+		public virtual void Reset()
 		{
 			// TODO This should do something in case the encryption is aborted
 		}
diff --git a/crypto/src/crypto/engines/NullEngine.cs b/crypto/src/crypto/engines/NullEngine.cs
index 407b8ccc6..f883b7c29 100644
--- a/crypto/src/crypto/engines/NullEngine.cs
+++ b/crypto/src/crypto/engines/NullEngine.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 		}
 
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -26,22 +26,22 @@ namespace Org.BouncyCastle.Crypto.Engines
 			initialised = true;
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Null"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return true; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return BlockSize;
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	input,
 			int		inOff,
 			byte[]	output,
@@ -49,12 +49,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (!initialised)
 				throw new InvalidOperationException("Null engine not initialised");
-			if ((inOff + BlockSize) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + BlockSize) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			for (int i = 0; i < BlockSize; ++i)
+            Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+            Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+            for (int i = 0; i < BlockSize; ++i)
 			{
 				output[outOff + i] = input[inOff + i];
 			}
@@ -62,7 +61,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return BlockSize;
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 			// nothing needs to be done
 		}
diff --git a/crypto/src/crypto/engines/RC2Engine.cs b/crypto/src/crypto/engines/RC2Engine.cs
index aaf8c714c..b56953de5 100644
--- a/crypto/src/crypto/engines/RC2Engine.cs
+++ b/crypto/src/crypto/engines/RC2Engine.cs
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -139,26 +139,26 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-		public void Reset()
+        public virtual void Reset()
         {
         }
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "RC2"; }
         }
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-        public  int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
@@ -166,12 +166,11 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (workingKey == null)
                 throw new InvalidOperationException("RC2 engine not initialised");
-            if ((inOff + BLOCK_SIZE) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + BLOCK_SIZE) > output.Length)
-                throw new DataLengthException("output buffer too short");
 
-			if (encrypting)
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            if (encrypting)
             {
                 EncryptBlock(input, inOff, output, outOff);
             }
@@ -308,5 +307,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             outBytes[outOff + 7] = (byte)(x76 >> 8);
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
index 238c9f76a..5742aa8b7 100644
--- a/crypto/src/crypto/engines/RC2WrapEngine.cs
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -51,7 +51,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			* @param forWrapping
 			* @param param
 			*/
-		public void Init(
+        public virtual void Init(
 			bool				forWrapping,
 			ICipherParameters	parameters)
 		{
@@ -101,7 +101,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return
 		*/
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "RC2"; }
 		}
@@ -114,7 +114,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param inLen
 		* @return
 		*/
-		public byte[] Wrap(
+        public virtual byte[] Wrap(
 			byte[]	input,
 			int		inOff,
 			int		length)
@@ -215,7 +215,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return
 		* @throws InvalidCipherTextException
 		*/
-		public byte[] Unwrap(
+        public virtual byte[] Unwrap(
 			byte[]	input,
 			int		inOff,
 			int		length)
diff --git a/crypto/src/crypto/engines/RC4Engine.cs b/crypto/src/crypto/engines/RC4Engine.cs
index c65468d93..fd84b7d23 100644
--- a/crypto/src/crypto/engines/RC4Engine.cs
+++ b/crypto/src/crypto/engines/RC4Engine.cs
@@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -47,12 +47,12 @@ namespace Org.BouncyCastle.Crypto.Engines
             throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString());
         }
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "RC4"; }
         }
 
-		public byte ReturnByte(
+        public virtual byte ReturnByte(
 			byte input)
         {
             x = (x + 1) & 0xff;
@@ -67,23 +67,15 @@ namespace Org.BouncyCastle.Crypto.Engines
             return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
         }
 
-        public void ProcessBytes(
+        public virtual void ProcessBytes(
             byte[]	input,
             int		inOff,
             int		length,
             byte[]	output,
-            int		outOff
-        )
+            int		outOff)
         {
-            if ((inOff + length) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-
-            if ((outOff + length) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, length, "input buffer too short");
+            Check.OutputLength(output, outOff, length, "output buffer too short");
 
             for (int i = 0; i < length ; i++)
             {
@@ -101,7 +93,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
             SetKey(workingKey);
         }
@@ -143,5 +135,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/RC532Engine.cs b/crypto/src/crypto/engines/RC532Engine.cs
index 1661707ef..169a60b98 100644
--- a/crypto/src/crypto/engines/RC532Engine.cs
+++ b/crypto/src/crypto/engines/RC532Engine.cs
@@ -48,17 +48,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 //            _S            = null;
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "RC5-32"; }
         }
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return 2 * 4;
         }
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -97,7 +97,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.forEncryption = forEncryption;
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
@@ -108,7 +108,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 				:	DecryptBlock(input, inOff, output, outOff);
         }
 
-		public void Reset()
+        public virtual void Reset()
         {
         }
 
@@ -290,5 +290,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             dst[dstOff + 3] = (byte)(word >> 24);
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/RC564Engine.cs b/crypto/src/crypto/engines/RC564Engine.cs
index 5c69d40ff..ddcce0fa8 100644
--- a/crypto/src/crypto/engines/RC564Engine.cs
+++ b/crypto/src/crypto/engines/RC564Engine.cs
@@ -51,17 +51,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 //            _S            = null;
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "RC5-64"; }
         }
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return 2 * bytesPerWord;
         }
@@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool             forEncryption,
             ICipherParameters    parameters)
         {
@@ -92,7 +92,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             SetKey(p.GetKey());
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]  input,
             int     inOff,
             byte[]  output,
@@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Engines
                                         : DecryptBlock(input, inOff, output, outOff);
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
         }
 
@@ -291,5 +291,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/RC6Engine.cs b/crypto/src/crypto/engines/RC6Engine.cs
index d72cc2f7b..196bd8394 100644
--- a/crypto/src/crypto/engines/RC6Engine.cs
+++ b/crypto/src/crypto/engines/RC6Engine.cs
@@ -48,17 +48,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 //            _S            = null;
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "RC6"; }
         }
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return 4 * bytesPerWord;
         }
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -84,7 +84,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			SetKey(p.GetKey());
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
@@ -93,17 +93,16 @@ namespace Org.BouncyCastle.Crypto.Engines
 			int blockSize = GetBlockSize();
 			if (_S == null)
 				throw new InvalidOperationException("RC6 engine not initialised");
-			if ((inOff + blockSize) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + blockSize) > output.Length)
-				throw new DataLengthException("output buffer too short");
 
-			return (forEncryption)
+            Check.DataLength(input, inOff, blockSize, "input buffer too short");
+            Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+            return (forEncryption)
 				?	EncryptBlock(input, inOff, output, outOff)
 				:	DecryptBlock(input, inOff, output, outOff);
         }
 
-		public void Reset()
+        public virtual void Reset()
         {
         }
 
@@ -358,5 +357,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index e520075f9..4e3af5227 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			this.engine = new CbcBlockCipher(engine);
 		}
 
-		public void Init(
+        public virtual void Init(
 			bool				forWrapping,
 			ICipherParameters	param)
 		{
@@ -48,12 +48,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
 		}
 
-		public byte[] Wrap(
+        public virtual byte[] Wrap(
 			byte[]	inBytes,
 			int		inOff,
 			int		inLen)
@@ -99,7 +99,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return cekBlock;
 		}
 
-		public byte[] Unwrap(
+        public virtual byte[] Unwrap(
 			byte[]	inBytes,
 			int		inOff,
 			int		inLen)
diff --git a/crypto/src/crypto/engines/RFC3394WrapEngine.cs b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
index 5615a63e5..4bb0e2114 100644
--- a/crypto/src/crypto/engines/RFC3394WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			this.engine = engine;
 		}
 
-		public void Init(
+        public virtual void Init(
 			bool				forWrapping,
 			ICipherParameters	parameters)
 		{
@@ -64,12 +64,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return engine.AlgorithmName; }
 		}
 
-		public byte[] Wrap(
+        public virtual byte[] Wrap(
 			byte[]	input,
 			int		inOff,
 			int		inLen)
@@ -119,7 +119,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return block;
 		}
 
-		public byte[] Unwrap(
+        public virtual byte[] Unwrap(
 			byte[]  input,
 			int     inOff,
 			int     inLen)
diff --git a/crypto/src/crypto/engines/RSABlindedEngine.cs b/crypto/src/crypto/engines/RSABlindedEngine.cs
index cdf69ddda..037abf7e9 100644
--- a/crypto/src/crypto/engines/RSABlindedEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		private RsaKeyParameters key;
 		private SecureRandom random;
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "RSA"; }
 		}
@@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		 * @param forEncryption true if we are encrypting, false otherwise.
 		 * @param param the necessary RSA key parameters.
 		 */
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	param)
 		{
@@ -55,7 +55,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		 *
 		 * @return maximum size for an input block.
 		 */
-		public int GetInputBlockSize()
+        public virtual int GetInputBlockSize()
 		{
 			return core.GetInputBlockSize();
 		}
@@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		 *
 		 * @return maximum size for an output block.
 		 */
-		public int GetOutputBlockSize()
+        public virtual int GetOutputBlockSize()
 		{
 			return core.GetOutputBlockSize();
 		}
@@ -81,7 +81,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		 * @return the result of the RSA process.
 		 * @exception DataLengthException the input block is too large.
 		 */
-		public byte[] ProcessBlock(
+        public virtual byte[] ProcessBlock(
 			byte[]	inBuf,
 			int		inOff,
 			int		inLen)
diff --git a/crypto/src/crypto/engines/RSABlindingEngine.cs b/crypto/src/crypto/engines/RSABlindingEngine.cs
index 76b57a3f7..c636627bf 100644
--- a/crypto/src/crypto/engines/RSABlindingEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindingEngine.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 		private bool forEncryption;
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "RSA"; }
 		}
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param forEncryption true if we are encrypting (blinding), false otherwise.
 		* @param param         the necessary RSA key parameters.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	param)
 		{
@@ -63,7 +63,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return maximum size for an input block.
 		*/
-		public int GetInputBlockSize()
+        public virtual int GetInputBlockSize()
 		{
 			return core.GetInputBlockSize();
 		}
@@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return maximum size for an output block.
 		*/
-		public int GetOutputBlockSize()
+        public virtual int GetOutputBlockSize()
 		{
 			return core.GetOutputBlockSize();
 		}
@@ -89,7 +89,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return the result of the RSA process.
 		* @throws DataLengthException the input block is too large.
 		*/
-		public byte[] ProcessBlock(
+        public virtual byte[] ProcessBlock(
 			byte[]	inBuf,
 			int		inOff,
 			int		inLen)
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
index 4e64d25d6..38326371f 100644
--- a/crypto/src/crypto/engines/RSACoreEngine.cs
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param forEncryption true if we are encrypting, false otherwise.
 		* @param param the necessary RSA key parameters.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -45,7 +45,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return maximum size for an input block.
 		*/
-		public int GetInputBlockSize()
+        public virtual int GetInputBlockSize()
 		{
 			if (forEncryption)
 			{
@@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		*
 		* @return maximum size for an output block.
 		*/
-		public int GetOutputBlockSize()
+        public virtual int GetOutputBlockSize()
 		{
 			if (forEncryption)
 			{
@@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return (bitSize - 1) / 8;
 		}
 
-		public BigInteger ConvertInput(
+        public virtual BigInteger ConvertInput(
 			byte[]	inBuf,
 			int		inOff,
 			int		inLen)
@@ -90,7 +90,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return input;
 		}
 
-		public byte[] ConvertOutput(
+        public virtual byte[] ConvertOutput(
 			BigInteger result)
 		{
 			byte[] output = result.ToByteArrayUnsigned();
@@ -112,7 +112,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return output;
 		}
 
-		public BigInteger ProcessBlock(
+        public virtual BigInteger ProcessBlock(
 			BigInteger input)
 		{
 			if (key is RsaPrivateCrtKeyParameters)
diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs
index df2e5baea..80f522353 100644
--- a/crypto/src/crypto/engines/RijndaelEngine.cs
+++ b/crypto/src/crypto/engines/RijndaelEngine.cs
@@ -571,7 +571,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @exception ArgumentException if the parameters argument is
 		* inappropriate.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool           forEncryption,
 			ICipherParameters  parameters)
 		{
@@ -585,43 +585,34 @@ namespace Org.BouncyCastle.Crypto.Engines
 			throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Rijndael"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return BC / 2;
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	input,
 			int		inOff,
 			byte[]	output,
 			int		outOff)
 		{
 			if (workingKey == null)
-			{
 				throw new InvalidOperationException("Rijndael engine not initialised");
-			}
-
-			if ((inOff + (BC / 2)) > input.Length)
-			{
-				throw new DataLengthException("input buffer too short");
-			}
 
-			if ((outOff + (BC / 2)) > output.Length)
-			{
-				throw new DataLengthException("output buffer too short");
-			}
+            Check.DataLength(input, inOff, (BC / 2), "input buffer too short");
+            Check.OutputLength(output, outOff, (BC / 2), "output buffer too short");
 
-			UnPackBlock(input, inOff);
+            UnPackBlock(input, inOff);
 
 			if (forEncryption)
 			{
@@ -637,11 +628,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return BC / 2;
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 
-		private  void UnPackBlock(
+		private void UnPackBlock(
 			byte[]      bytes,
 			int         off)
 		{
@@ -743,5 +734,4 @@ namespace Org.BouncyCastle.Crypto.Engines
 			KeyAddition(rk[0]);
 		}
 	}
-
 }
diff --git a/crypto/src/crypto/engines/RsaEngine.cs b/crypto/src/crypto/engines/RsaEngine.cs
index 7e6dfb163..4399b4409 100644
--- a/crypto/src/crypto/engines/RsaEngine.cs
+++ b/crypto/src/crypto/engines/RsaEngine.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Engines
     {
 		private RsaCoreEngine core;
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "RSA"; }
         }
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @param forEncryption true if we are encrypting, false otherwise.
         * @param param the necessary RSA key parameters.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         *
         * @return maximum size for an input block.
         */
-        public int GetInputBlockSize()
+        public virtual int GetInputBlockSize()
         {
 			return core.GetInputBlockSize();
         }
@@ -50,7 +50,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         *
         * @return maximum size for an output block.
         */
-        public int GetOutputBlockSize()
+        public virtual int GetOutputBlockSize()
         {
 			return core.GetOutputBlockSize();
         }
@@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @return the result of the RSA process.
         * @exception DataLengthException the input block is too large.
         */
-        public byte[] ProcessBlock(
+        public virtual byte[] ProcessBlock(
             byte[]	inBuf,
             int		inOff,
             int		inLen)
diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs
index efea0f1fe..f615b8476 100644
--- a/crypto/src/crypto/engines/SEEDEngine.cs
+++ b/crypto/src/crypto/engines/SEEDEngine.cs
@@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		private int[] wKey;
 		private bool forEncryption;
 
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -176,22 +176,22 @@ namespace Org.BouncyCastle.Crypto.Engines
 			wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "SEED"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return BlockSize;
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	inBuf,
 			int		inOff,
 			byte[]	outBuf,
@@ -199,12 +199,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (wKey == null)
 				throw new InvalidOperationException("SEED engine not initialised");
-			if (inOff + BlockSize > inBuf.Length)
-				throw new DataLengthException("input buffer too short");
-			if (outOff + BlockSize > outBuf.Length)
-				throw new DataLengthException("output buffer too short");
 
-			long l = bytesToLong(inBuf, inOff + 0);
+            Check.DataLength(inBuf, inOff, BlockSize, "input buffer too short");
+            Check.OutputLength(outBuf, outOff, BlockSize, "output buffer too short");
+
+            long l = bytesToLong(inBuf, inOff + 0);
 			long r = bytesToLong(inBuf, inOff + 8);
 
 			if (forEncryption)
@@ -234,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return BlockSize;
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 81884d603..9b27dc7b4 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			this.rounds = rounds;
 		}
 
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption, 
 			ICipherParameters	parameters)
 		{
@@ -108,7 +108,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public byte ReturnByte(
+        public virtual byte ReturnByte(
 			byte input)
 		{
 			if (LimitExceeded())
@@ -136,7 +136,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public void ProcessBytes(
+        public virtual void ProcessBytes(
 			byte[]	inBytes, 
 			int		inOff, 
 			int		len, 
@@ -144,26 +144,15 @@ namespace Org.BouncyCastle.Crypto.Engines
 			int		outOff)
 		{
 			if (!initialised)
-			{
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
-			}
 
-			if ((inOff + len) > inBytes.Length)
-			{
-				throw new DataLengthException("input buffer too short");
-			}
+            Check.DataLength(inBytes, inOff, len, "input buffer too short");
+            Check.OutputLength(outBytes, outOff, len, "output buffer too short");
 
-			if ((outOff + len) > outBytes.Length)
-			{
-				throw new DataLengthException("output buffer too short");
-			}
-
-			if (LimitExceeded((uint)len))
-			{
+            if (LimitExceeded((uint)len))
 				throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
-			}
 
-			for (int i = 0; i < len; i++)
+            for (int i = 0; i < len; i++)
 			{
 				if (index == 0)
 				{
@@ -175,7 +164,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 			index = 0;
 			ResetLimitCounter();
diff --git a/crypto/src/crypto/engines/SerpentEngine.cs b/crypto/src/crypto/engines/SerpentEngine.cs
index 92b25acc6..255c204ab 100644
--- a/crypto/src/crypto/engines/SerpentEngine.cs
+++ b/crypto/src/crypto/engines/SerpentEngine.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -48,17 +48,17 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
         }
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Serpent"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
@@ -76,7 +76,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception InvalidOperationException if the cipher isn't initialised.
         * @return the number of bytes processed and produced.
         */
-        public  int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]  input,
             int     inOff,
             byte[]  output,
@@ -84,12 +84,11 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (wKey == null)
                 throw new InvalidOperationException("Serpent not initialised");
-            if ((inOff + BLOCK_SIZE) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + BLOCK_SIZE) > output.Length)
-                throw new DataLengthException("output buffer too short");
 
-			if (encrypting)
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            if (encrypting)
             {
                 EncryptBlock(input, inOff, output, outOff);
             }
@@ -101,7 +100,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BLOCK_SIZE;
         }
 
-        public void Reset()
+        public virtual void Reset()
         {
         }
 
@@ -775,5 +774,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             X0 = RotateRight(x0, 13);
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs
index 3d2a781e6..a45dc9b24 100644
--- a/crypto/src/crypto/engines/SkipjackEngine.cs
+++ b/crypto/src/crypto/engines/SkipjackEngine.cs
@@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public void Init(
+        public virtual void Init(
             bool				forEncryption,
             ICipherParameters	parameters)
         {
@@ -71,22 +71,22 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return "SKIPJACK"; }
         }
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-        public int ProcessBlock(
+        public virtual int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
@@ -94,12 +94,11 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (key1 == null)
                 throw new InvalidOperationException("SKIPJACK engine not initialised");
-            if ((inOff + BLOCK_SIZE) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + BLOCK_SIZE) > output.Length)
-                throw new DataLengthException("output buffer too short");
 
-			if (encrypting)
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            if (encrypting)
             {
                 EncryptBlock(input, inOff, output, outOff);
             }
@@ -111,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return BLOCK_SIZE;
         }
 
-		public void Reset()
+        public virtual void Reset()
         {
         }
 
@@ -135,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return ((g5 << 8) + g6);
         }
 
-        public int EncryptBlock(
+        public virtual int EncryptBlock(
             byte[]      input,
             int         inOff,
             byte[]      outBytes,
@@ -203,7 +202,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return ((h6 << 8) + h5);
         }
 
-        public int DecryptBlock(
+        public virtual int DecryptBlock(
             byte[]      input,
             int         inOff,
             byte[]      outBytes,
@@ -251,5 +250,4 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BLOCK_SIZE;
         }
     }
-
 }
diff --git a/crypto/src/crypto/engines/TEAEngine.cs b/crypto/src/crypto/engines/TEAEngine.cs
index 582dd0f73..2e1a7002b 100644
--- a/crypto/src/crypto/engines/TEAEngine.cs
+++ b/crypto/src/crypto/engines/TEAEngine.cs
@@ -36,17 +36,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 			_initialised = false;
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "TEA"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return block_size;
 		}
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @exception ArgumentException if the params argument is
 		* inappropriate.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -77,7 +77,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			setKey(p.GetKey());
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]  inBytes,
 			int     inOff,
 			byte[]  outBytes,
@@ -86,18 +86,15 @@ namespace Org.BouncyCastle.Crypto.Engines
 			if (!_initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
 
-			if ((inOff + block_size) > inBytes.Length)
-				throw new DataLengthException("input buffer too short");
+            Check.DataLength(inBytes, inOff, block_size, "input buffer too short");
+            Check.OutputLength(outBytes, outOff, block_size, "output buffer too short");
 
-			if ((outOff + block_size) > outBytes.Length)
-				throw new DataLengthException("output buffer too short");
-
-			return _forEncryption
+            return _forEncryption
 				?	encryptBlock(inBytes, inOff, outBytes, outOff)
 				:	decryptBlock(inBytes, inOff, outBytes, outOff);
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
index 954470345..33ff3a421 100644
--- a/crypto/src/crypto/engines/ThreefishEngine.cs
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -155,7 +155,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
 		/// <param name="parameters">an instance of <see cref="TweakableBlockCipherParameters"/> or <see cref="KeyParameter"/> (to
 		///               use a 0 tweak)</param>
-		public void Init(bool forEncryption, ICipherParameters parameters)
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
 		{
 			byte[] keyBytes;
 			byte[] tweakBytes;
@@ -266,26 +266,26 @@ namespace Org.BouncyCastle.Crypto.Engines
 			t[4] = t[1];
 		}
 
-		public string AlgorithmName
+        public virtual string AlgorithmName
 		{
 			get { return "Threefish-" + (blocksizeBytes * 8); }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return blocksizeBytes;
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 
-		public int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+        public virtual int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
 		{
 			if ((outOff + blocksizeBytes) > outBytes.Length)
 			{
diff --git a/crypto/src/crypto/engines/TwofishEngine.cs b/crypto/src/crypto/engines/TwofishEngine.cs
index b983d9d31..04a579ced 100644
--- a/crypto/src/crypto/engines/TwofishEngine.cs
+++ b/crypto/src/crypto/engines/TwofishEngine.cs
@@ -293,12 +293,11 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             if (workingKey == null)
                 throw new InvalidOperationException("Twofish not initialised");
-            if ((inOff + BLOCK_SIZE) > input.Length)
-                throw new DataLengthException("input buffer too short");
-            if ((outOff + BLOCK_SIZE) > output.Length)
-                throw new DataLengthException("output buffer too short");
 
-			if (encrypting)
+            Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+            Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+            if (encrypting)
             {
                 EncryptBlock(input, inOff, output, outOff);
             }
diff --git a/crypto/src/crypto/engines/VMPCEngine.cs b/crypto/src/crypto/engines/VMPCEngine.cs
index 1c2802a80..852901e36 100644
--- a/crypto/src/crypto/engines/VMPCEngine.cs
+++ b/crypto/src/crypto/engines/VMPCEngine.cs
@@ -92,15 +92,8 @@ namespace Org.BouncyCastle.Crypto.Engines
             byte[]	output,
             int		outOff)
         {
-            if ((inOff + len) > input.Length)
-            {
-                throw new DataLengthException("input buffer too short");
-            }
-
-            if ((outOff + len) > output.Length)
-            {
-                throw new DataLengthException("output buffer too short");
-            }
+            Check.DataLength(input, inOff, len, "input buffer too short");
+            Check.OutputLength(output, outOff, len, "output buffer too short");
 
             for (int i = 0; i < len; i++)
             {
diff --git a/crypto/src/crypto/engines/XSalsa20Engine.cs b/crypto/src/crypto/engines/XSalsa20Engine.cs
index fc6630905..2898b46c8 100644
--- a/crypto/src/crypto/engines/XSalsa20Engine.cs
+++ b/crypto/src/crypto/engines/XSalsa20Engine.cs
@@ -13,7 +13,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 	public class XSalsa20Engine 
 		: Salsa20Engine
 	{
-
 		public override string AlgorithmName
 		{
 			get { return "XSalsa20"; }
@@ -65,7 +64,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			// Counter reset
 			ResetCounter();
 		}
-
 	}
 }
 
diff --git a/crypto/src/crypto/engines/XTEAEngine.cs b/crypto/src/crypto/engines/XTEAEngine.cs
index eb9291775..40d81fbe6 100644
--- a/crypto/src/crypto/engines/XTEAEngine.cs
+++ b/crypto/src/crypto/engines/XTEAEngine.cs
@@ -34,17 +34,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 			_initialised = false;
 		}
 
-		public string AlgorithmName
+		public virtual string AlgorithmName
 		{
 			get { return "XTEA"; }
 		}
 
-		public bool IsPartialBlockOkay
+        public virtual bool IsPartialBlockOkay
 		{
 			get { return false; }
 		}
 
-		public int GetBlockSize()
+        public virtual int GetBlockSize()
 		{
 			return block_size;
 		}
@@ -57,7 +57,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @exception ArgumentException if the params argument is
 		* inappropriate.
 		*/
-		public void Init(
+        public virtual void Init(
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
@@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			setKey(p.GetKey());
 		}
 
-		public int ProcessBlock(
+        public virtual int ProcessBlock(
 			byte[]	inBytes,
 			int		inOff,
 			byte[]	outBytes,
@@ -84,18 +84,15 @@ namespace Org.BouncyCastle.Crypto.Engines
 			if (!_initialised)
 				throw new InvalidOperationException(AlgorithmName + " not initialised");
 
-			if ((inOff + block_size) > inBytes.Length)
-				throw new DataLengthException("input buffer too short");
+            Check.DataLength(inBytes, inOff, block_size, "input buffer too short");
+            Check.OutputLength(outBytes, outOff, block_size, "output buffer too short");
 
-			if ((outOff + block_size) > outBytes.Length)
-				throw new DataLengthException("output buffer too short");
-
-			return _forEncryption
+            return _forEncryption
 				?	encryptBlock(inBytes, inOff, outBytes, outOff)
 				:	decryptBlock(inBytes, inOff, outBytes, outOff);
 		}
 
-		public void Reset()
+        public virtual void Reset()
 		{
 		}
 
diff --git a/crypto/src/crypto/generators/RsaKeyPairGenerator.cs b/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
index e870f1c08..c46865991 100644
--- a/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
@@ -11,117 +11,130 @@ namespace Org.BouncyCastle.Crypto.Generators
      * an RSA key pair generator.
      */
     public class RsaKeyPairGenerator
-        : IAsymmetricCipherKeyPairGenerator
+        :   IAsymmetricCipherKeyPairGenerator
     {
-        private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
-        private const int DefaultTests = 12;
+        protected static readonly BigInteger One = BigInteger.One;
+        protected static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+        protected const int DefaultTests = 100;
 
-        private RsaKeyGenerationParameters param;
+        protected RsaKeyGenerationParameters parameters;
 
-        public void Init(
+        public virtual void Init(
             KeyGenerationParameters parameters)
         {
             if (parameters is RsaKeyGenerationParameters)
             {
-                this.param = (RsaKeyGenerationParameters)parameters;
+                this.parameters = (RsaKeyGenerationParameters)parameters;
             }
             else
             {
-                this.param = new RsaKeyGenerationParameters(
+                this.parameters = new RsaKeyGenerationParameters(
                     DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
             }
         }
 
-        public AsymmetricCipherKeyPair GenerateKeyPair()
+        public virtual AsymmetricCipherKeyPair GenerateKeyPair()
         {
-            BigInteger p, q, n, d, e, pSub1, qSub1, phi;
-
-            //
-            // p and q values should have a length of half the strength in bits
-            //
-            int strength = param.Strength;
-            int qBitlength = strength >> 1;
-            int pBitlength = strength - qBitlength;
-            int mindiffbits = strength / 3;
-            int minWeight = strength >> 2;
-
-            e = param.PublicExponent;
+            for (;;)
+            {
+                //
+                // p and q values should have a length of half the strength in bits
+                //
+                int strength = parameters.Strength;
+                int pbitlength = (strength + 1) / 2;
+                int qbitlength = strength - pbitlength;
+                int mindiffbits = strength / 3;
+                int minWeight = strength >> 2;
 
-            // TODO Consider generating safe primes for p, q (see DHParametersHelper.GenerateSafePrimes)
-            // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+                //// d lower bound is 2^(strength / 2)
+                //BigInteger dLowerBound = BigInteger.Two.Pow(strength / 2);
 
-            p = ChooseRandomPrime(pBitlength, e);
+                BigInteger e = parameters.PublicExponent;
 
-            //
-            // Generate a modulus of the required length
-            //
-            for (;;)
-            {
-                q = ChooseRandomPrime(qBitlength, e);
+                // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
+                // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
 
-                // p and q should not be too close together (or equal!)
-                BigInteger diff = q.Subtract(p).Abs();
-                if (diff.BitLength < mindiffbits)
-                    continue;
+                BigInteger p = ChooseRandomPrime(pbitlength, e);
+                BigInteger q, n;
 
                 //
-                // calculate the modulus
+                // generate a modulus of the required length
                 //
-                n = p.Multiply(q);
-
-                if (n.BitLength != strength)
+                for (;;)
                 {
+                    q = ChooseRandomPrime(qbitlength, e);
+
+                    // p and q should not be too close together (or equal!)
+                    BigInteger diff = q.Subtract(p).Abs();
+                    if (diff.BitLength < mindiffbits)
+                        continue;
+
                     //
-                    // if we get here our primes aren't big enough, make the largest
-                    // of the two p and try again
+                    // calculate the modulus
                     //
-                    p = p.Max(q);
-                    continue;
+                    n = p.Multiply(q);
+
+                    if (n.BitLength != strength)
+                    {
+                        //
+                        // if we get here our primes aren't big enough, make the largest
+                        // of the two p and try again
+                        //
+                        p = p.Max(q);
+                        continue;
+                    }
+
+                    /*
+	                 * Require a minimum weight of the NAF representation, since low-weight composites may
+	                 * be weak against a version of the number-field-sieve for factoring.
+	                 *
+	                 * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+	                 */
+                    if (WNafUtilities.GetNafWeight(n) < minWeight)
+                    {
+                        p = ChooseRandomPrime(pbitlength, e);
+                        continue;
+                    }
+
+                    break;
                 }
 
-                /*
-                 * Require a minimum weight of the NAF representation, since low-weight composites may
-                 * be weak against a version of the number-field-sieve for factoring.
-                 * 
-                 * See "The number field sieve for integers of low weight", Oliver Schirokauer.
-                 */
-                if (WNafUtilities.GetNafWeight(n) < minWeight)
+                if (p.CompareTo(q) < 0)
                 {
-                    p = ChooseRandomPrime(pBitlength, e);
-                    continue;
+                    BigInteger tmp = p;
+                    p = q;
+                    q = tmp;
                 }
 
-                break;
-            }
-
-            if (p.CompareTo(q) < 0)
-            {
-                phi = p;
-                p = q;
-                q = phi;
-            }
+                BigInteger pSub1 = p.Subtract(One);
+                BigInteger qSub1 = q.Subtract(One);
+                BigInteger phi = pSub1.Multiply(qSub1);
+                //BigInteger lcm = phi.Divide(pSub1.Gcd(qSub1));
 
-            pSub1 = p.Subtract(BigInteger.One);
-            qSub1 = q.Subtract(BigInteger.One);
-            phi = pSub1.Multiply(qSub1);
+                //
+                // calculate the private exponent
+                //
+                //BigInteger d = e.ModInverse(lcm);
+                BigInteger d = e.ModInverse(phi);
 
-            //
-            // calculate the private exponent
-            //
-            d = e.ModInverse(phi);
+                // if d is less than or equal to dLowerBound, we need to start over
+                // also, for backward compatibility, if d is not the same as
+                // e.modInverse(phi), we need to start over
 
-            //
-            // calculate the CRT factors
-            //
-            BigInteger dP, dQ, qInv;
+                if (d.BitLength <= qbitlength)// || !d.Multiply(e).Mod(phi).Equals(One))
+                    continue;
 
-            dP = d.Remainder(pSub1);
-            dQ = d.Remainder(qSub1);
-            qInv = q.ModInverse(p);
+                //
+                // calculate the CRT factors
+                //
+                BigInteger dP = d.Remainder(pSub1);
+                BigInteger dQ = d.Remainder(qSub1);
+                BigInteger qInv = q.ModInverse(p);
 
-            return new AsymmetricCipherKeyPair(
-                new RsaKeyParameters(false, n, e),
-                new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+                return new AsymmetricCipherKeyPair(
+                    new RsaKeyParameters(false, n, e),
+                    new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+            }
         }
 
         /// <summary>Choose a random prime value for use with RSA</summary>
@@ -132,15 +145,15 @@ namespace Org.BouncyCastle.Crypto.Generators
         {
             for (;;)
             {
-                BigInteger p = new BigInteger(bitlength, 1, param.Random);
+                BigInteger p = new BigInteger(bitlength, 1, parameters.Random);
 
-                if (p.Mod(e).Equals(BigInteger.One))
+                if (p.Mod(e).Equals(One))
                     continue;
 
-                if (!p.IsProbablePrime(param.Certainty))
+                if (!p.IsProbablePrime(parameters.Certainty))
                     continue;
 
-                if (!e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One))
+                if (!e.Gcd(p.Subtract(One)).Equals(One))
                     continue;
 
                 return p;
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index 653d75cb9..e0b1e6b54 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -61,6 +61,7 @@ namespace Org.BouncyCastle.Crypto.Modes
         {
             this.forEncryption = forEncryption;
 
+            ICipherParameters cipherParameters;
             if (parameters is AeadParameters)
             {
                 AeadParameters param = (AeadParameters) parameters;
@@ -68,7 +69,7 @@ namespace Org.BouncyCastle.Crypto.Modes
                 nonce = param.GetNonce();
                 initialAssociatedText = param.GetAssociatedText();
                 macSize = param.MacSize / 8;
-                keyParam = param.Key;
+                cipherParameters = param.Key;
             }
             else if (parameters is ParametersWithIV)
             {
@@ -77,17 +78,25 @@ namespace Org.BouncyCastle.Crypto.Modes
                 nonce = param.GetIV();
                 initialAssociatedText = null;
                 macSize = macBlock.Length / 2;
-                keyParam = param.Parameters;
+                cipherParameters = param.Parameters;
             }
             else
             {
                 throw new ArgumentException("invalid parameters passed to CCM");
             }
 
+            // NOTE: Very basic support for key re-use, but no performance gain from it
+            if (cipherParameters != null)
+            {
+                keyParam = cipherParameters;
+            }
+
             if (nonce == null || nonce.Length < 7 || nonce.Length > 13)
             {
                 throw new ArgumentException("nonce must have length from 7 to 13 octets");
             }
+
+            Reset();
         }
 
         public virtual string AlgorithmName
@@ -128,6 +137,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             byte[]	outBytes,
             int		outOff)
         {
+            Check.DataLength(inBytes, inOff, inLen, "Input buffer too short");
+
             data.Write(inBytes, inOff, inLen);
 
             return 0;
@@ -137,13 +148,11 @@ namespace Org.BouncyCastle.Crypto.Modes
             byte[]	outBytes,
             int		outOff)
         {
-            byte[] enc = ProcessPacket(data.GetBuffer(), 0, (int)data.Position);
-
-            Array.Copy(enc, 0, outBytes, outOff, enc.Length);
+            int len = ProcessPacket(data.GetBuffer(), 0, (int)data.Position, outBytes, outOff);
 
             Reset();
 
-            return enc.Length;
+            return len;
         }
 
         public virtual void Reset()
@@ -161,11 +170,7 @@ namespace Org.BouncyCastle.Crypto.Modes
         */
         public virtual byte[] GetMac()
         {
-            byte[] mac = new byte[macSize];
-
-            Array.Copy(macBlock, 0, mac, 0, mac.Length);
-
-            return mac;
+            return Arrays.CopyOfRange(macBlock, 0, macSize);
         }
 
         public virtual int GetUpdateOutputSize(
@@ -174,7 +179,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             return 0;
         }
 
-        public int GetOutputSize(
+        public virtual int GetOutputSize(
             int len)
         {
             int totalData = (int)data.Length + len;
@@ -187,10 +192,51 @@ namespace Org.BouncyCastle.Crypto.Modes
             return totalData < macSize ? 0 : totalData - macSize;
         }
 
-        public byte[] ProcessPacket(
-            byte[]	input,
-            int		inOff,
-            int		inLen)
+        /**
+         * Process a packet of data for either CCM decryption or encryption.
+         *
+         * @param in data for processing.
+         * @param inOff offset at which data starts in the input array.
+         * @param inLen length of the data in the input array.
+         * @return a byte array containing the processed input..
+         * @throws IllegalStateException if the cipher is not appropriately set up.
+         * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+         */
+        public virtual byte[] ProcessPacket(byte[] input, int inOff, int inLen)
+        {
+            byte[] output;
+
+            if (forEncryption)
+            {
+                output = new byte[inLen + macSize];
+            }
+            else
+            {
+                if (inLen < macSize)
+                    throw new InvalidCipherTextException("data too short");
+
+                output = new byte[inLen - macSize];
+            }
+
+            ProcessPacket(input, inOff, inLen, output, 0);
+
+            return output;
+        }
+
+        /**
+         * Process a packet of data for either CCM decryption or encryption.
+         *
+         * @param in data for processing.
+         * @param inOff offset at which data starts in the input array.
+         * @param inLen length of the data in the input array.
+         * @param output output array.
+         * @param outOff offset into output array to start putting processed bytes.
+         * @return the number of bytes added to output.
+         * @throws IllegalStateException if the cipher is not appropriately set up.
+         * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+         * @throws DataLengthException if output buffer too short.
+         */
+        public virtual int ProcessPacket(byte[] input, int inOff, int inLen, byte[] output, int outOff)
         {
             // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
             // Need to keep the CTR and CBC Mac parts around and reset
@@ -213,42 +259,45 @@ namespace Org.BouncyCastle.Crypto.Modes
             IBlockCipher ctrCipher = new SicBlockCipher(cipher);
             ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
 
-            int index = inOff;
-            int outOff = 0;
-            byte[] output;
+            int outputLen;
+            int inIndex = inOff;
+            int outIndex = outOff;
 
             if (forEncryption)
             {
-                output = new byte[inLen + macSize];
+                outputLen = inLen + macSize;
+                Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
 
                 calculateMac(input, inOff, inLen, macBlock);
 
                 ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);   // S0
 
-                while (index < inLen - BlockSize)                   // S1...
+                while (inIndex < (inOff + inLen - BlockSize))                 // S1...
                 {
-                    ctrCipher.ProcessBlock(input, index, output, outOff);
-                    outOff += BlockSize;
-                    index += BlockSize;
+                    ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
+                    outIndex += BlockSize;
+                    inIndex += BlockSize;
                 }
 
                 byte[] block = new byte[BlockSize];
 
-                Array.Copy(input, index, block, 0, inLen - index);
+                Array.Copy(input, inIndex, block, 0, inLen + inOff - inIndex);
 
                 ctrCipher.ProcessBlock(block, 0, block, 0);
 
-                Array.Copy(block, 0, output, outOff, inLen - index);
+                Array.Copy(block, 0, output, outIndex, inLen + inOff - inIndex);
 
-                outOff += inLen - index;
-
-                Array.Copy(macBlock, 0, output, outOff, output.Length - outOff);
+                Array.Copy(macBlock, 0, output, outOff + inLen, macSize);
             }
             else
             {
-                output = new byte[inLen - macSize];
+                if (inLen < macSize)
+                    throw new InvalidCipherTextException("data too short");
 
-                Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize);
+                outputLen = inLen - macSize;
+                Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
+
+                Array.Copy(input, inOff + outputLen, macBlock, 0, macSize);
 
                 ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
 
@@ -257,30 +306,30 @@ namespace Org.BouncyCastle.Crypto.Modes
                     macBlock[i] = 0;
                 }
 
-                while (outOff < output.Length - BlockSize)
+                while (inIndex < (inOff + outputLen - BlockSize))
                 {
-                    ctrCipher.ProcessBlock(input, index, output, outOff);
-                    outOff += BlockSize;
-                    index += BlockSize;
+                    ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
+                    outIndex += BlockSize;
+                    inIndex += BlockSize;
                 }
 
                 byte[] block = new byte[BlockSize];
 
-                Array.Copy(input, index, block, 0, output.Length - outOff);
+                Array.Copy(input, inIndex, block, 0, outputLen - (inIndex - inOff));
 
                 ctrCipher.ProcessBlock(block, 0, block, 0);
 
-                Array.Copy(block, 0, output, outOff, output.Length - outOff);
+                Array.Copy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
 
                 byte[] calculatedMacBlock = new byte[BlockSize];
 
-                calculateMac(output, 0, output.Length, calculatedMacBlock);
+                calculateMac(output, outOff, outputLen, calculatedMacBlock);
 
                 if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
                     throw new InvalidCipherTextException("mac check in CCM failed");
             }
 
-            return output;
+            return outputLen;
         }
 
         private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index 5ccc69b66..624f385b5 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -54,7 +54,6 @@ namespace Org.BouncyCastle.Crypto.Modes
 			blockSize = cipher.GetBlockSize();
 			mac = new CMac(cipher);
 			macBlock = new byte[blockSize];
-			bufBlock = new byte[blockSize * 2];
 			associatedTextMac = new byte[mac.GetMacSize()];
 			nonceMac = new byte[mac.GetMacSize()];
 			this.cipher = new SicBlockCipher(cipher);
@@ -65,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 			get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
 		}
 
-		public IBlockCipher GetUnderlyingCipher()
+		public virtual IBlockCipher GetUnderlyingCipher()
 		{
 			return cipher;
 		}
@@ -107,6 +106,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 				throw new ArgumentException("invalid parameters passed to EAX");
 			}
 
+            bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
+
             byte[] tag = new byte[blockSize];
 
             // Key reuse implemented in CBC mode of underlying CMac
@@ -117,16 +118,10 @@ namespace Org.BouncyCastle.Crypto.Modes
             mac.BlockUpdate(nonce, 0, nonce.Length);
             mac.DoFinal(nonceMac, 0);
 
-            tag[blockSize - 1] = (byte)Tag.H;
-            mac.BlockUpdate(tag, 0, blockSize);
-
-            if (initialAssociatedText != null)
-            {
-                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
-            }
-
-            // Same BlockCipher underlies this and the mac, so reuse last key on cipher 
+            // Same BlockCipher underlies this and the mac, so reuse last key on cipher
             cipher.Init(true, new ParametersWithIV(null, nonceMac));
+
+            Reset();
 		}
 
         private void InitCipher()
@@ -191,16 +186,16 @@ namespace Org.BouncyCastle.Crypto.Modes
         {
             if (cipherInitialized)
             {
-                throw new InvalidOperationException("AAD data cannot be added after encryption/decription processing has begun.");
+                throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
             }
             mac.Update(input);
         }
 
-        public void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+        public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
         {
             if (cipherInitialized)
             {
-                throw new InvalidOperationException("AAD data cannot be added after encryption/decription processing has begun.");
+                throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
             }
             mac.BlockUpdate(inBytes, inOff, len);
         }
@@ -247,10 +242,11 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 			if (forEncryption)
 			{
-				cipher.ProcessBlock(bufBlock, 0, tmp, 0);
-				cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
+                Check.OutputLength(outBytes, outOff, extra + macSize, "Output buffer too short");
+
+                cipher.ProcessBlock(bufBlock, 0, tmp, 0);
 
-				Array.Copy(tmp, 0, outBytes, outOff, extra);
+                Array.Copy(tmp, 0, outBytes, outOff, extra);
 
 				mac.BlockUpdate(tmp, 0, extra);
 
@@ -264,14 +260,18 @@ namespace Org.BouncyCastle.Crypto.Modes
 			}
 			else
 			{
-				if (extra > macSize)
+                if (extra < macSize)
+                    throw new InvalidCipherTextException("data too short");
+
+                Check.OutputLength(outBytes, outOff, extra - macSize, "Output buffer too short");
+
+                if (extra > macSize)
 				{
 					mac.BlockUpdate(bufBlock, 0, extra - macSize);
 
 					cipher.ProcessBlock(bufBlock, 0, tmp, 0);
-					cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
 
-					Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
+                    Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
 				}
 
 				CalculateMac();
@@ -331,6 +331,11 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 			if (bufOff == bufBlock.Length)
 			{
+                Check.OutputLength(outBytes, outOff, blockSize, "Output buffer is too short");
+
+                // TODO Could move the ProcessByte(s) calls to here
+//                InitCipher();
+
 				int size;
 
 				if (forEncryption)
@@ -346,10 +351,14 @@ namespace Org.BouncyCastle.Crypto.Modes
 					size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
 				}
 
-				bufOff = blockSize;
-				Array.Copy(bufBlock, blockSize, bufBlock, 0, blockSize);
+                bufOff = 0;
+                if (!forEncryption)
+                {
+                    Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
+                    bufOff = macSize;
+                }
 
-				return size;
+                return size;
 			}
 
 			return 0;
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 2e2ac2eca..8e6120eef 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -284,6 +284,9 @@ namespace Org.BouncyCastle.Crypto.Modes
             byte[]	output,
             int		outOff)
         {
+            if (input.Length < (inOff + len))
+                throw new DataLengthException("Input buffer too short");
+
             int resultLen = 0;
 
             for (int i = 0; i < len; ++i)
@@ -301,6 +304,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         private void OutputBlock(byte[] output, int offset)
         {
+            Check.OutputLength(output, offset, BlockSize, "Output buffer too short");
             if (totalLength == 0)
             {
                 InitCipher();
@@ -325,12 +329,19 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
 
             int extra = bufOff;
-            if (!forEncryption)
+
+            if (forEncryption)
+            {
+                Check.OutputLength(output, outOff, extra + macSize, "Output buffer too short");
+            }
+            else
             {
                 if (extra < macSize)
                     throw new InvalidCipherTextException("data too short");
 
                 extra -= macSize;
+
+                Check.OutputLength(output, outOff, extra, "Output buffer too short");
             }
 
             if (extra > 0)
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index 54359dfe8..e7dc466e6 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -355,6 +355,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
                 Xor(mainBlock, Pad);
 
+                Check.OutputLength(output, outOff, mainBlockPos, "Output buffer too short");
                 Array.Copy(mainBlock, 0, output, outOff, mainBlockPos);
 
                 if (!forEncryption)
@@ -382,6 +383,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 
             if (forEncryption)
             {
+                Check.OutputLength(output, outOff, resultLen + macSize, "Output buffer too short");
+
                 // Append tag to the message
                 Array.Copy(macBlock, 0, output, outOff + resultLen, macSize);
                 resultLen += macSize;
@@ -431,6 +434,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         protected virtual void ProcessMainBlock(byte[] output, int outOff)
         {
+            Check.DataLength(output, outOff, BLOCK_SIZE, "Output buffer too short");
+
             /*
              * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
              */
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 0f241035f..de41d88f4 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -106,6 +106,29 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             x[3] = r13;
         }
 
+        internal static void Multiply(ulong[] x, ulong[] y)
+        {
+            ulong r00 = x[0], r01 = x[1], r10 = 0, r11 = 0;
+
+            for (int i = 0; i < 2; ++i)
+            {
+                long bits = (long)y[i];
+                for (int j = 0; j < 64; ++j)
+                {
+                    ulong m1 = (ulong)(bits >> 63); bits <<= 1;
+                    r10 ^= (r00 & m1);
+                    r11 ^= (r01 & m1);
+
+                    ulong m2 = (r01 << 63) >> 8;
+                    r01 = (r01 >> 1) | (r00 << 63);
+                    r00 = (r00 >> 1) ^ (m2 & E1L);
+                }
+            }
+
+            x[0] = r10;
+            x[1] = r11;
+        }
+
         // P is the value with only bit i=1 set
         internal static void MultiplyP(uint[] x)
         {
diff --git a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
index fb8a92ba3..c291e4814 100644
--- a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
+++ b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
@@ -178,10 +178,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 
 			if (outLength > 0)
 			{
-				if ((outOff + outLength) > output.Length)
-				{
-					throw new DataLengthException("output buffer too short");
-				}
+                Check.OutputLength(output, outOff, outLength, "output buffer too short");
 			}
 
 			int resultLen = 0;
@@ -242,7 +239,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 					{
 						Reset();
 
-						throw new DataLengthException("output buffer too short");
+						throw new OutputLengthException("output buffer too short");
 					}
 
 					resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
diff --git a/crypto/test/src/crypto/test/CCMTest.cs b/crypto/test/src/crypto/test/CCMTest.cs
index 4a54fb4f9..8c46e11e7 100644
--- a/crypto/test/src/crypto/test/CCMTest.cs
+++ b/crypto/test/src/crypto/test/CCMTest.cs
@@ -81,7 +81,38 @@ namespace Org.BouncyCastle.Crypto.Tests
 			//
 			checkVectors(4, ccm, K4, 112, N4, A4, A4, T5, C5);
 
-			//
+            // decryption with output specified, non-zero offset.
+            ccm.Init(false, new AeadParameters(new KeyParameter(K2), 48, N2, A2));
+
+            byte[] inBuf = new byte[C2.Length + 10];
+            byte[] outBuf = new byte[ccm.GetOutputSize(C2.Length) + 10];
+
+            Array.Copy(C2, 0, inBuf, 10, C2.Length);
+
+            int len = ccm.ProcessPacket(inBuf, 10, C2.Length, outBuf, 10);
+            byte[] output = ccm.ProcessPacket(C2, 0, C2.Length);
+
+            if (len != output.Length || !isEqual(output, outBuf, 10))
+            {
+                Fail("decryption output incorrect");
+            }
+
+            // encryption with output specified, non-zero offset.
+            ccm.Init(true, new AeadParameters(new KeyParameter(K2), 48, N2, A2));
+
+            int inLen = len;
+            inBuf = outBuf;
+            outBuf = new byte[ccm.GetOutputSize(inLen) + 10];
+
+            len = ccm.ProcessPacket(inBuf, 10, inLen, outBuf, 10);
+            output = ccm.ProcessPacket(inBuf, 10, inLen);
+
+            if (len != output.Length || !isEqual(output, outBuf, 10))
+            {
+                Fail("encryption output incorrect");
+            }
+
+            //
 			// exception tests
 			//
 
@@ -121,6 +152,17 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 		}
 
+        private bool isEqual(byte[] exp, byte[] other, int off)
+        {
+            for (int i = 0; i != exp.Length; i++)
+            {
+                if (exp[i] != other[off + i])
+                    return false;
+            }
+
+            return true;
+        }
+
 		private void checkVectors(
 			int count,
 			CcmBlockCipher ccm,
@@ -203,7 +245,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 			if (!AreEqual(p, dec))
 			{
-                Fail("decrypted stream fails to match in test " + count + " with " + additionalDataType);
+                Fail("decrypted stream fails to match in test " + count + " with " + additionalDataType,
+                    Hex.ToHexString(p), Hex.ToHexString(dec));
             }
 
 			if (!AreEqual(t, ccm.GetMac()))