summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-09-12 13:37:38 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-09-12 13:37:38 +0700
commit1298385506df2df9f8fd9c1ceacfaf952e02fd5d (patch)
tree5725137d5bdd744127a7cb91f7822949f85cbf7d
parentAdd basic support for JKS keystores (diff)
downloadBouncyCastle.NET-ed25519-1298385506df2df9f8fd9c1ceacfaf952e02fd5d.tar.xz
Separate out new IBlockCipherMode from IBlockCipher
-rw-r--r--crypto/src/crypto/BufferedBlockCipher.cs120
-rw-r--r--crypto/src/crypto/IBlockCipher.cs8
-rw-r--r--crypto/src/crypto/StreamBlockCipher.cs53
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs9
-rw-r--r--crypto/src/crypto/engines/AesEngine_X86.cs6
-rw-r--r--crypto/src/crypto/engines/AesLightEngine.cs9
-rw-r--r--crypto/src/crypto/engines/AriaEngine.cs10
-rw-r--r--crypto/src/crypto/engines/BlowfishEngine.cs9
-rw-r--r--crypto/src/crypto/engines/CamelliaEngine.cs10
-rw-r--r--crypto/src/crypto/engines/CamelliaLightEngine.cs9
-rw-r--r--crypto/src/crypto/engines/Cast5Engine.cs9
-rw-r--r--crypto/src/crypto/engines/Cast6Engine.cs4
-rw-r--r--crypto/src/crypto/engines/DesEdeEngine.cs4
-rw-r--r--crypto/src/crypto/engines/DesEngine.cs9
-rw-r--r--crypto/src/crypto/engines/Dstu7624Engine.cs14
-rw-r--r--crypto/src/crypto/engines/GOST28147Engine.cs9
-rw-r--r--crypto/src/crypto/engines/IdeaEngine.cs9
-rw-r--r--crypto/src/crypto/engines/NoekeonEngine.cs9
-rw-r--r--crypto/src/crypto/engines/NullEngine.cs80
-rw-r--r--crypto/src/crypto/engines/RC2Engine.cs9
-rw-r--r--crypto/src/crypto/engines/RC532Engine.cs9
-rw-r--r--crypto/src/crypto/engines/RC564Engine.cs9
-rw-r--r--crypto/src/crypto/engines/RC6Engine.cs9
-rw-r--r--crypto/src/crypto/engines/RFC3211WrapEngine.cs2
-rw-r--r--crypto/src/crypto/engines/RijndaelEngine.cs9
-rw-r--r--crypto/src/crypto/engines/SEEDEngine.cs9
-rw-r--r--crypto/src/crypto/engines/SM4Engine.cs9
-rw-r--r--crypto/src/crypto/engines/SerpentEngineBase.cs9
-rw-r--r--crypto/src/crypto/engines/SkipjackEngine.cs9
-rw-r--r--crypto/src/crypto/engines/TEAEngine.cs9
-rw-r--r--crypto/src/crypto/engines/ThreefishEngine.cs9
-rw-r--r--crypto/src/crypto/engines/TwofishEngine.cs13
-rw-r--r--crypto/src/crypto/engines/XTEAEngine.cs9
-rw-r--r--crypto/src/crypto/macs/CMac.cs34
-rw-r--r--crypto/src/crypto/macs/CbcBlockCipherMac.cs38
-rw-r--r--crypto/src/crypto/macs/CfbBlockCipherMac.cs8
-rw-r--r--crypto/src/crypto/macs/DSTU7624Mac.cs1
-rw-r--r--crypto/src/crypto/macs/ISO9797Alg3Mac.cs6
-rw-r--r--crypto/src/crypto/modes/CbcBlockCipher.cs9
-rw-r--r--crypto/src/crypto/modes/CcmBlockCipher.cs1
-rw-r--r--crypto/src/crypto/modes/CfbBlockCipher.cs9
-rw-r--r--crypto/src/crypto/modes/CtsBlockCipher.cs63
-rw-r--r--crypto/src/crypto/modes/EAXBlockCipher.cs2
-rw-r--r--crypto/src/crypto/modes/EcbBlockCipher.cs58
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/GOFBBlockCipher.cs13
-rw-r--r--crypto/src/crypto/modes/IBlockCipherMode.cs19
-rw-r--r--crypto/src/crypto/modes/KCtrBlockCipher.cs10
-rw-r--r--crypto/src/crypto/modes/OCBBlockCipher.cs3
-rw-r--r--crypto/src/crypto/modes/OfbBlockCipher.cs10
-rw-r--r--crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs11
-rw-r--r--crypto/src/crypto/modes/SicBlockCipher.cs8
-rw-r--r--crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs64
-rw-r--r--crypto/src/crypto/util/CipherFactory.cs2
-rw-r--r--crypto/src/security/CipherUtilities.cs32
-rw-r--r--crypto/test/src/crypto/io/test/CipherStreamTest.cs4
-rw-r--r--crypto/test/src/crypto/prng/test/CtrDrbgTest.cs10
-rw-r--r--crypto/test/src/crypto/test/NullTest.cs82
58 files changed, 302 insertions, 713 deletions
diff --git a/crypto/src/crypto/BufferedBlockCipher.cs b/crypto/src/crypto/BufferedBlockCipher.cs
index eaaae255e..788ab138b 100644
--- a/crypto/src/crypto/BufferedBlockCipher.cs
+++ b/crypto/src/crypto/BufferedBlockCipher.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Modes;
 using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto
@@ -16,10 +17,10 @@ namespace Org.BouncyCastle.Crypto
 	public class BufferedBlockCipher
 		: BufferedCipherBase
 	{
-		internal byte[]			buf;
-		internal int			bufOff;
-		internal bool			forEncryption;
-		internal IBlockCipher	cipher;
+        internal byte[] buf;
+		internal int bufOff;
+		internal bool forEncryption;
+		internal IBlockCipherMode m_cipherMode;
 
 		/**
 		* constructor for subclasses
@@ -28,26 +29,30 @@ namespace Org.BouncyCastle.Crypto
 		{
 		}
 
-		/**
+        public BufferedBlockCipher(IBlockCipher cipher)
+			: this(EcbBlockCipher.GetBlockCipherMode(cipher))
+        {
+        }
+
+        /**
 		* Create a buffered block cipher without padding.
 		*
 		* @param cipher the underlying block cipher this buffering object wraps.
 		* false otherwise.
 		*/
-		public BufferedBlockCipher(
-			IBlockCipher cipher)
+        public BufferedBlockCipher(IBlockCipherMode cipherMode)
 		{
-			if (cipher == null)
-				throw new ArgumentNullException("cipher");
+			if (cipherMode == null)
+				throw new ArgumentNullException(nameof(cipherMode));
 
-			this.cipher = cipher;
-			buf = new byte[cipher.GetBlockSize()];
+            m_cipherMode = cipherMode;
+			buf = new byte[cipherMode.GetBlockSize()];
 			bufOff = 0;
 		}
 
 		public override string AlgorithmName
 		{
-			get { return cipher.AlgorithmName; }
+			get { return m_cipherMode.AlgorithmName; }
 		}
 
 		/**
@@ -60,19 +65,18 @@ namespace Org.BouncyCastle.Crypto
 		* inappropriate.
 		*/
 		// Note: This doubles as the Init in the event that this cipher is being used as an IWrapper
-		public override void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+		public override void Init(bool forEncryption, ICipherParameters parameters)
 		{
 			this.forEncryption = forEncryption;
 
-            ParametersWithRandom pwr = parameters as ParametersWithRandom;
-            if (pwr != null)
-                parameters = pwr.Parameters;
+			if (parameters is ParametersWithRandom withRandom)
+			{
+				parameters = withRandom.Parameters;
+			}
 
             Reset();
 
-			cipher.Init(forEncryption, parameters);
+			m_cipherMode.Init(forEncryption, parameters);
 		}
 
 		/**
@@ -82,7 +86,7 @@ namespace Org.BouncyCastle.Crypto
 		*/
 		public override int GetBlockSize()
 		{
-			return cipher.GetBlockSize();
+			return m_cipherMode.GetBlockSize();
 		}
 
 		/**
@@ -93,8 +97,7 @@ namespace Org.BouncyCastle.Crypto
 		* @return the space required to accommodate a call to update
 		* with len bytes of input.
 		*/
-		public override int GetUpdateOutputSize(
-			int length)
+		public override int GetUpdateOutputSize(int length)
 		{
 			int total = length + bufOff;
 			int leftOver = total % buf.Length;
@@ -109,8 +112,7 @@ namespace Org.BouncyCastle.Crypto
 		* @return the space required to accommodate a call to update and doFinal
 		* with len bytes of input.
 		*/
-		public override int GetOutputSize(
-			int length)
+		public override int GetOutputSize(int length)
 		{
 			// Note: Can assume IsPartialBlockOkay is true for purposes of this calculation
 			return length + bufOff;
@@ -136,14 +138,13 @@ namespace Org.BouncyCastle.Crypto
 					throw new DataLengthException("output buffer too short");
 
 				bufOff = 0;
-				return cipher.ProcessBlock(buf, 0, output, outOff);
+				return m_cipherMode.ProcessBlock(buf, 0, output, outOff);
 			}
 
 			return 0;
 		}
 
-		public override byte[] ProcessByte(
-			byte input)
+		public override byte[] ProcessByte(byte input)
 		{
 			int outLength = GetUpdateOutputSize(1);
 
@@ -171,20 +172,17 @@ namespace Org.BouncyCastle.Crypto
 				Check.OutputLength(output, buf.Length, "output buffer too short");
 
                 bufOff = 0;
-                return cipher.ProcessBlock(buf, output);
+                return m_cipherMode.ProcessBlock(buf, output);
             }
 
             return 0;
         }
 #endif
 
-        public override byte[] ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		length)
-		{
-			if (input == null)
-				throw new ArgumentNullException("input");
+        public override byte[] ProcessBytes(byte[] input, int inOff, int length)
+        {
+            if (input == null)
+				throw new ArgumentNullException(nameof(input));
 			if (length < 1)
 				return null;
 
@@ -204,7 +202,7 @@ namespace Org.BouncyCastle.Crypto
 			return outBytes;
 		}
 
-		/**
+        /**
 		* process an array of bytes, producing output if necessary.
 		*
 		* @param in the input byte array.
@@ -216,14 +214,9 @@ namespace Org.BouncyCastle.Crypto
 		* @exception DataLengthException if there isn't enough space in out.
 		* @exception InvalidOperationException if the cipher isn't initialised.
 		*/
-		public override int ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		length,
-			byte[]	output,
-			int		outOff)
-		{
-			if (length < 1)
+        public override int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff)
+        {
+            if (length < 1)
 			{
 				if (length < 0)
 					throw new ArgumentException("Can't have a negative input length!");
@@ -244,13 +237,13 @@ namespace Org.BouncyCastle.Crypto
 			if (length >= gapLen)
 			{
 				Array.Copy(input, inOff, buf, bufOff, gapLen);
-				resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+				resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
 				bufOff = 0;
 				length -= gapLen;
 				inOff += gapLen;
 				while (length >= buf.Length)
 				{
-					resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+					resultLen += m_cipherMode.ProcessBlock(input, inOff, output, outOff + resultLen);
 					length -= blockSize;
 					inOff += blockSize;
 				}
@@ -279,12 +272,12 @@ namespace Org.BouncyCastle.Crypto
             if (input.Length >= gapLen)
             {
 				input[..gapLen].CopyTo(buf.AsSpan(bufOff));
-                resultLen = cipher.ProcessBlock(buf, output);
+                resultLen = m_cipherMode.ProcessBlock(buf, output);
                 bufOff = 0;
 				input = input[gapLen..];
                 while (input.Length >= buf.Length)
                 {
-                    resultLen += cipher.ProcessBlock(input, output[resultLen..]);
+                    resultLen += m_cipherMode.ProcessBlock(input, output[resultLen..]);
 					input = input[blockSize..];
                 }
             }
@@ -319,13 +312,10 @@ namespace Org.BouncyCastle.Crypto
 			return outBytes;
 		}
 
-		public override byte[] DoFinal(
-			byte[]	input,
-			int		inOff,
-			int		inLen)
-		{
-			if (input == null)
-				throw new ArgumentNullException("input");
+        public override byte[] DoFinal(byte[] input, int inOff, int inLen)
+        {
+            if (input == null)
+				throw new ArgumentNullException(nameof(input));
 
 			int length = GetOutputSize(inLen);
 
@@ -356,7 +346,7 @@ namespace Org.BouncyCastle.Crypto
 			return outBytes;
 		}
 
-		/**
+        /**
 		* Process the last block in the buffer.
 		*
 		* @param out the array the block currently being held is copied into.
@@ -370,19 +360,17 @@ namespace Org.BouncyCastle.Crypto
 		* @exception DataLengthException if the input is not block size
 		* aligned.
 		*/
-		public override int DoFinal(
-			byte[]	output,
-			int		outOff)
-		{
-			try
+        public override int DoFinal(byte[] output, int outOff)
+        {
+            try
 			{
 				if (bufOff != 0)
 				{
-                    Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
+                    Check.DataLength(!m_cipherMode.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);
+                    m_cipherMode.ProcessBlock(buf, 0, buf, 0);
 					Array.Copy(buf, 0, output, outOff, bufOff);
 				}
 
@@ -401,11 +389,11 @@ namespace Org.BouncyCastle.Crypto
             {
                 if (bufOff != 0)
                 {
-                    Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
+                    Check.DataLength(!m_cipherMode.IsPartialBlockOkay, "data not block size aligned");
                     Check.OutputLength(output, bufOff, "output buffer too short for DoFinal()");
 
                     // NB: Can't copy directly, or we may write too much output
-                    cipher.ProcessBlock(buf, buf);
+                    m_cipherMode.ProcessBlock(buf, buf);
 					buf.AsSpan(0, bufOff).CopyTo(output);
                 }
 
@@ -427,7 +415,7 @@ namespace Org.BouncyCastle.Crypto
 			Array.Clear(buf, 0, buf.Length);
 			bufOff = 0;
 
-			cipher.Reset();
+            m_cipherMode.Reset();
 		}
 	}
 }
diff --git a/crypto/src/crypto/IBlockCipher.cs b/crypto/src/crypto/IBlockCipher.cs
index b26aaa49f..36f10d3e8 100644
--- a/crypto/src/crypto/IBlockCipher.cs
+++ b/crypto/src/crypto/IBlockCipher.cs
@@ -16,9 +16,6 @@ namespace Org.BouncyCastle.Crypto
 		/// <returns>The block size for this cipher, in bytes.</returns>
 		int GetBlockSize();
 
-		/// <summary>Indicates whether this cipher can handle partial blocks.</summary>
-		bool IsPartialBlockOkay { get; }
-
 		/// <summary>Process a block.</summary>
 		/// <param name="inBuf">The input buffer.</param>
 		/// <param name="inOff">The offset into <paramref>inBuf</paramref> that the input block begins.</param>
@@ -37,10 +34,5 @@ namespace Org.BouncyCastle.Crypto
 		/// <returns>The number of bytes processed and produced.</returns>
 		int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output);
 #endif
-
-        /// <summary>
-        /// Reset the cipher to the same state as it was after the last init (if there was one).
-        /// </summary>
-        void Reset();
     }
 }
diff --git a/crypto/src/crypto/StreamBlockCipher.cs b/crypto/src/crypto/StreamBlockCipher.cs
index 0cd9d110a..f7e76e6cf 100644
--- a/crypto/src/crypto/StreamBlockCipher.cs
+++ b/crypto/src/crypto/StreamBlockCipher.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Modes;
+
 namespace Org.BouncyCastle.Crypto
 {
 	/**
@@ -9,7 +11,7 @@ namespace Org.BouncyCastle.Crypto
 	public class StreamBlockCipher
 		: IStreamCipher
 	{
-		private readonly IBlockCipher cipher;
+		private readonly IBlockCipherMode m_cipherMode;
 		private readonly byte[] oneByte = new byte[1];
 
 		/**
@@ -19,28 +21,25 @@ namespace Org.BouncyCastle.Crypto
 		 * @exception ArgumentException if the cipher has a block size other than
 		 * one.
 		 */
-		public StreamBlockCipher(
-			IBlockCipher cipher)
+		public StreamBlockCipher(IBlockCipherMode cipherMode)
 		{
-			if (cipher == null)
-				throw new ArgumentNullException("cipher");
-			if (cipher.GetBlockSize() != 1)
-				throw new ArgumentException("block cipher block size != 1.", "cipher");
+			if (cipherMode == null)
+				throw new ArgumentNullException(nameof(cipherMode));
+			if (cipherMode.GetBlockSize() != 1)
+				throw new ArgumentException("block cipher block size != 1.", nameof(cipherMode));
 
-			this.cipher = cipher;
+            m_cipherMode = cipherMode;
 		}
 
-		/**
+        /**
 		 * initialise the underlying cipher.
 		 *
 		 * @param forEncryption true if we are setting up for encryption, false otherwise.
 		 * @param param the necessary parameters for the underlying cipher to be initialised.
 		 */
-		public void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			cipher.Init(forEncryption, parameters);
+        public void Init(bool forEncryption, ICipherParameters parameters)
+        {
+            m_cipherMode.Init(forEncryption, parameters);
 		}
 
 		/**
@@ -50,7 +49,7 @@ namespace Org.BouncyCastle.Crypto
 		*/
 		public string AlgorithmName
 		{
-			get { return cipher.AlgorithmName; }
+			get { return m_cipherMode.AlgorithmName; }
 		}
 
 		/**
@@ -59,17 +58,16 @@ namespace Org.BouncyCastle.Crypto
 		* @param in the byte to be processed.
 		* @return the result of processing the input byte.
 		*/
-		public byte ReturnByte(
-			byte input)
+		public byte ReturnByte(byte input)
 		{
 			oneByte[0] = input;
 
-			cipher.ProcessBlock(oneByte, 0, oneByte, 0);
+            m_cipherMode.ProcessBlock(oneByte, 0, oneByte, 0);
 
 			return oneByte[0];
 		}
 
-		/**
+        /**
 		* process a block of bytes from in putting the result into out.
 		*
 		* @param in the input byte array.
@@ -79,19 +77,14 @@ namespace Org.BouncyCastle.Crypto
 		* @param outOff the offset into the output byte array the processed data stars at.
 		* @exception DataLengthException if the output buffer is too small.
 		*/
-		public void ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		length,
-			byte[]	output,
-			int		outOff)
-		{
-			Check.DataLength(input, inOff, length, "input buffer too short");
+        public void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff)
+        {
+            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++)
 			{
-				cipher.ProcessBlock(input, inOff + i, output, outOff + i);
+                m_cipherMode.ProcessBlock(input, inOff + i, output, outOff + i);
 			}
 		}
 
@@ -102,7 +95,7 @@ namespace Org.BouncyCastle.Crypto
 
             for (int i = 0; i != input.Length; i++)
             {
-				cipher.ProcessBlock(input[i..], output[i..]);
+                m_cipherMode.ProcessBlock(input[i..], output[i..]);
             }
         }
 #endif
@@ -113,7 +106,7 @@ namespace Org.BouncyCastle.Crypto
 		*/
         public void Reset()
 		{
-			cipher.Reset();
+            m_cipherMode.Reset();
 		}
 	}
 }
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 21daf06d8..8ccadf1bf 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -468,11 +468,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "AES"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
         public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
@@ -531,10 +526,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
         {
diff --git a/crypto/src/crypto/engines/AesEngine_X86.cs b/crypto/src/crypto/engines/AesEngine_X86.cs
index cc362ff52..aeaf9317c 100644
--- a/crypto/src/crypto/engines/AesEngine_X86.cs
+++ b/crypto/src/crypto/engines/AesEngine_X86.cs
@@ -152,8 +152,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public string AlgorithmName => "AES";
 
-        public bool IsPartialBlockOkay => false;
-
         public int GetBlockSize() => 16;
 
         public void Init(bool forEncryption, ICipherParameters parameters)
@@ -219,10 +217,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             return 64;
         }
 
-        public void Reset()
-        {
-        }
-
         [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
         private void ImplRounds(ref Vector128<byte> state)
         {
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index f34901fac..6ce714fde 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -362,11 +362,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "AES"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
         public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
@@ -425,10 +420,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output, uint[][] KW)
         {
diff --git a/crypto/src/crypto/engines/AriaEngine.cs b/crypto/src/crypto/engines/AriaEngine.cs
index 75af84320..c52fd30bf 100644
--- a/crypto/src/crypto/engines/AriaEngine.cs
+++ b/crypto/src/crypto/engines/AriaEngine.cs
@@ -157,11 +157,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "ARIA"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
         public virtual int GetBlockSize()
         {
             return BlockSize;
@@ -225,11 +220,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-            // Empty
-        }
-
         protected static void A(byte[] z)
         {
             byte x0 = z[0], x1 = z[1], x2 = z[2], x3 = z[3], x4 = z[4], x5 = z[5], x6 = z[6], x7 = z[7], x8 = z[8],
diff --git a/crypto/src/crypto/engines/BlowfishEngine.cs b/crypto/src/crypto/engines/BlowfishEngine.cs
index aa323581a..1152e3d78 100644
--- a/crypto/src/crypto/engines/BlowfishEngine.cs
+++ b/crypto/src/crypto/engines/BlowfishEngine.cs
@@ -342,11 +342,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "Blowfish"; }
         }
 
-		public bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
 		public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
         {
             if (workingKey == null)
@@ -400,10 +395,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public void Reset()
-        {
-        }
-
         public int GetBlockSize()
         {
             return BLOCK_SIZE;
diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs
index 512448a27..80d15ad99 100644
--- a/crypto/src/crypto/engines/CamelliaEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaEngine.cs
@@ -653,11 +653,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "Camellia"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return BLOCK_SIZE;
@@ -711,10 +706,5 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 #endif
-
-		public virtual void Reset()
-		{
-			// nothing
-		}
 	}
 }
diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs
index 03611f137..3111a8ddf 100644
--- a/crypto/src/crypto/engines/CamelliaLightEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -554,11 +554,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "Camellia"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return BLOCK_SIZE;
@@ -624,9 +619,5 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 		}
 #endif
-
-		public virtual void Reset()
-		{
-		}
 	}
 }
diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs
index 93288a237..c53c8909a 100644
--- a/crypto/src/crypto/engines/Cast5Engine.cs
+++ b/crypto/src/crypto/engines/Cast5Engine.cs
@@ -347,11 +347,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "CAST5"; }
         }
 
-		public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
 		public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
         {
             if (_workingKey == null)
@@ -403,10 +398,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
diff --git a/crypto/src/crypto/engines/Cast6Engine.cs b/crypto/src/crypto/engines/Cast6Engine.cs
index c3f379fcf..b73398191 100644
--- a/crypto/src/crypto/engines/Cast6Engine.cs
+++ b/crypto/src/crypto/engines/Cast6Engine.cs
@@ -46,10 +46,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "CAST6"; }
         }
 
-		public override void Reset()
-        {
-        }
-
 		public override int GetBlockSize()
         {
             return BLOCK_SIZE;
diff --git a/crypto/src/crypto/engines/DesEdeEngine.cs b/crypto/src/crypto/engines/DesEdeEngine.cs
index ffb18d753..a9185d295 100644
--- a/crypto/src/crypto/engines/DesEdeEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeEngine.cs
@@ -125,9 +125,5 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BLOCK_SIZE;
         }
 #endif
-
-        public override void Reset()
-        {
-        }
     }
 }
diff --git a/crypto/src/crypto/engines/DesEngine.cs b/crypto/src/crypto/engines/DesEngine.cs
index 25f559652..084fa1049 100644
--- a/crypto/src/crypto/engines/DesEngine.cs
+++ b/crypto/src/crypto/engines/DesEngine.cs
@@ -42,11 +42,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "DES"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
 		public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
@@ -92,10 +87,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         /**
         * what follows is mainly taken from "Applied Cryptography", by
         * Bruce Schneier, however it also bears great resemblance to Richard
diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs
index a0ff8ebd4..26c3ee586 100644
--- a/crypto/src/crypto/engines/Dstu7624Engine.cs
+++ b/crypto/src/crypto/engines/Dstu7624Engine.cs
@@ -292,6 +292,7 @@ namespace Org.BouncyCastle.Crypto.Engines
                     }
                     AddRoundKey(roundsAmount);
                     Pack.UInt64_To_LE(internalState, output, outOff);
+                    Array.Clear(internalState, 0, internalState.Length);
                     break;
                 }
                 }
@@ -327,6 +328,7 @@ namespace Org.BouncyCastle.Crypto.Engines
                     }
                     SubRoundKey(0);
                     Pack.UInt64_To_LE(internalState, output, outOff);
+                    Array.Clear(internalState, 0, internalState.Length);
                     break;
                 }
                 }
@@ -371,6 +373,7 @@ namespace Org.BouncyCastle.Crypto.Engines
                     }
                     AddRoundKey(roundsAmount);
                     Pack.UInt64_To_LE(internalState, output);
+                    Array.Clear(internalState, 0, internalState.Length);
                     break;
                 }
                 }
@@ -402,6 +405,7 @@ namespace Org.BouncyCastle.Crypto.Engines
                     }
                     SubRoundKey(0);
                     Pack.UInt64_To_LE(internalState, output);
+                    Array.Clear(internalState, 0, internalState.Length);
                     break;
                 }
                 }
@@ -1280,15 +1284,5 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             return wordsInBlock << 3;
         }
-
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
-        public virtual void Reset()
-        {
-            Array.Clear(internalState, 0, internalState.Length);
-        }
     }
 }
diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs
index ee5a1ba53..ef566618f 100644
--- a/crypto/src/crypto/engines/GOST28147Engine.cs
+++ b/crypto/src/crypto/engines/GOST28147Engine.cs
@@ -189,11 +189,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "Gost28147"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return BlockSize;
@@ -231,10 +226,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public virtual void Reset()
-		{
-		}
-
 		private int[] GenerateWorkingKey(bool forEncryption, byte[] userKey)
 		{
 			this.forEncryption = forEncryption;
diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index c5d3eb36f..a61ba03ab 100644
--- a/crypto/src/crypto/engines/IdeaEngine.cs
+++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -54,11 +54,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "IDEA"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
         public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
@@ -94,10 +89,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         private static readonly int MASK = 0xffff;
         private static readonly int BASE = 0x10001;
 
diff --git a/crypto/src/crypto/engines/NoekeonEngine.cs b/crypto/src/crypto/engines/NoekeonEngine.cs
index 2866d8d75..eca1ee04b 100644
--- a/crypto/src/crypto/engines/NoekeonEngine.cs
+++ b/crypto/src/crypto/engines/NoekeonEngine.cs
@@ -36,11 +36,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "Noekeon"; }
 		}
 
-		public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return Size;
@@ -126,10 +121,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public virtual void Reset()
-		{
-		}
-
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
 		private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
 		{
diff --git a/crypto/src/crypto/engines/NullEngine.cs b/crypto/src/crypto/engines/NullEngine.cs
deleted file mode 100644
index b79cfba93..000000000
--- a/crypto/src/crypto/engines/NullEngine.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-
-using Org.BouncyCastle.Crypto.Parameters;
-
-namespace Org.BouncyCastle.Crypto.Engines
-{
-	/**
-	* The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
-	* Provided for the sake of completeness.
-	*/
-	public class NullEngine
-		: IBlockCipher
-	{
-		private bool initialised;
-		private const int BlockSize = 1;
-
-		public NullEngine()
-		{
-		}
-
-        public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			// we don't mind any parameters that may come in
-			initialised = true;
-		}
-
-        public virtual string AlgorithmName
-		{
-			get { return "Null"; }
-		}
-
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return true; }
-		}
-
-        public virtual int GetBlockSize()
-		{
-			return BlockSize;
-		}
-
-        public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
-		{
-			if (!initialised)
-				throw new InvalidOperationException("Null engine not initialised");
-
-            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];
-			}
-
-			return BlockSize;
-		}
-
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-		public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
-		{
-			if (!initialised)
-				throw new InvalidOperationException("Null engine not initialised");
-
-            Check.DataLength(input, BlockSize, "input buffer too short");
-            Check.OutputLength(output, BlockSize, "output buffer too short");
-
-			input[..BlockSize].CopyTo(output);
-
-			return BlockSize;
-		}
-#endif
-
-		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 7fe1cbc3b..42b29c9b0 100644
--- a/crypto/src/crypto/engines/RC2Engine.cs
+++ b/crypto/src/crypto/engines/RC2Engine.cs
@@ -140,20 +140,11 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        public virtual void Reset()
-        {
-        }
-
         public virtual string AlgorithmName
         {
             get { return "RC2"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
diff --git a/crypto/src/crypto/engines/RC532Engine.cs b/crypto/src/crypto/engines/RC532Engine.cs
index aa3da5870..e3d0708a8 100644
--- a/crypto/src/crypto/engines/RC532Engine.cs
+++ b/crypto/src/crypto/engines/RC532Engine.cs
@@ -54,11 +54,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "RC5-32"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
         {
             return 2 * 4;
@@ -114,10 +109,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         /**
         * Re-key the cipher.
         *
diff --git a/crypto/src/crypto/engines/RC564Engine.cs b/crypto/src/crypto/engines/RC564Engine.cs
index 8d524f420..8dffc3f43 100644
--- a/crypto/src/crypto/engines/RC564Engine.cs
+++ b/crypto/src/crypto/engines/RC564Engine.cs
@@ -55,11 +55,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "RC5-64"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
         {
             return 16;
@@ -107,10 +102,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         /**
         * Re-key the cipher.
         *
diff --git a/crypto/src/crypto/engines/RC6Engine.cs b/crypto/src/crypto/engines/RC6Engine.cs
index 316bae65e..e6a3f8176 100644
--- a/crypto/src/crypto/engines/RC6Engine.cs
+++ b/crypto/src/crypto/engines/RC6Engine.cs
@@ -51,11 +51,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "RC6"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
         {
             return 16;
@@ -115,10 +110,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         /**
         * Re-key the cipher.
         *
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index 86480145c..3fc7b3191 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -53,7 +53,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public virtual string AlgorithmName
 		{
-			get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
+			get { return engine.UnderlyingCipher.AlgorithmName + "/RFC3211Wrap"; }
 		}
 
         public virtual byte[] Wrap(
diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs
index 2bd404973..422664ce0 100644
--- a/crypto/src/crypto/engines/RijndaelEngine.cs
+++ b/crypto/src/crypto/engines/RijndaelEngine.cs
@@ -591,11 +591,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "Rijndael"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return BC / 2;
@@ -659,10 +654,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public virtual void Reset()
-		{
-		}
-
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
 		private void UnPackBlock(ReadOnlySpan<byte> input)
 		{
diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs
index 6b511e4cc..07ffe06bb 100644
--- a/crypto/src/crypto/engines/SEEDEngine.cs
+++ b/crypto/src/crypto/engines/SEEDEngine.cs
@@ -181,11 +181,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "SEED"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return BlockSize;
@@ -269,10 +264,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public virtual void Reset()
-		{
-		}
-
 		private int[] CreateWorkingKey(byte[] inKey)
 		{
 			if (inKey.Length != 16)
diff --git a/crypto/src/crypto/engines/SM4Engine.cs b/crypto/src/crypto/engines/SM4Engine.cs
index 6a7206a01..ddfc76e51 100644
--- a/crypto/src/crypto/engines/SM4Engine.cs
+++ b/crypto/src/crypto/engines/SM4Engine.cs
@@ -143,11 +143,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "SM4"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
         public virtual int GetBlockSize()
         {
             return BlockSize;
@@ -212,9 +207,5 @@ namespace Org.BouncyCastle.Crypto.Engines
             return BlockSize;
         }
 #endif
-
-        public virtual void Reset()
-        {
-        }
     }
 }
diff --git a/crypto/src/crypto/engines/SerpentEngineBase.cs b/crypto/src/crypto/engines/SerpentEngineBase.cs
index 5d665fbbc..0ce3a0e4f 100644
--- a/crypto/src/crypto/engines/SerpentEngineBase.cs
+++ b/crypto/src/crypto/engines/SerpentEngineBase.cs
@@ -44,11 +44,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "Serpent"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-        {
-            get { return false; }
-        }
-
         public virtual int GetBlockSize()
         {
             return BlockSize;
@@ -120,10 +115,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         /*
          * The sboxes below are based on the work of Brian Gladman and
          * Sam Simpson, whose original notice appears below.
diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs
index e78111abd..4a5355963 100644
--- a/crypto/src/crypto/engines/SkipjackEngine.cs
+++ b/crypto/src/crypto/engines/SkipjackEngine.cs
@@ -77,11 +77,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "SKIPJACK"; }
         }
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
         {
             return BLOCK_SIZE;
@@ -140,10 +135,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public virtual void Reset()
-        {
-        }
-
         /**
         * The G permutation
         */
diff --git a/crypto/src/crypto/engines/TEAEngine.cs b/crypto/src/crypto/engines/TEAEngine.cs
index bb6ae6dcc..062fd7b7a 100644
--- a/crypto/src/crypto/engines/TEAEngine.cs
+++ b/crypto/src/crypto/engines/TEAEngine.cs
@@ -42,11 +42,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "TEA"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return block_size;
@@ -108,10 +103,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public virtual void Reset()
-		{
-		}
-
 		/**
 		* Re-key the cipher.
 		*
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
index c22691fc2..d1adb2e61 100644
--- a/crypto/src/crypto/engines/ThreefishEngine.cs
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -269,20 +269,11 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "Threefish-" + (blocksizeBytes * 8); }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return blocksizeBytes;
 		}
 
-        public virtual void Reset()
-		{
-		}
-
         public virtual int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
 		{
 			Check.DataLength(inBytes, inOff, blocksizeBytes, "input buffer too short");
diff --git a/crypto/src/crypto/engines/TwofishEngine.cs b/crypto/src/crypto/engines/TwofishEngine.cs
index cb3e35b0a..09c7114f2 100644
--- a/crypto/src/crypto/engines/TwofishEngine.cs
+++ b/crypto/src/crypto/engines/TwofishEngine.cs
@@ -294,11 +294,6 @@ namespace Org.BouncyCastle.Crypto.Engines
             get { return "Twofish"; }
         }
 
-		public bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
 		public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
         {
             if (workingKey == null)
@@ -352,14 +347,6 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 #endif
 
-        public void Reset()
-        {
-            if (this.workingKey != null)
-            {
-                SetKey(this.workingKey);
-            }
-        }
-
         public int GetBlockSize()
         {
             return BLOCK_SIZE;
diff --git a/crypto/src/crypto/engines/XTEAEngine.cs b/crypto/src/crypto/engines/XTEAEngine.cs
index e70498a5f..0f028e9dd 100644
--- a/crypto/src/crypto/engines/XTEAEngine.cs
+++ b/crypto/src/crypto/engines/XTEAEngine.cs
@@ -40,11 +40,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			get { return "XTEA"; }
 		}
 
-        public virtual bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
         public virtual int GetBlockSize()
 		{
 			return block_size;
@@ -110,10 +105,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 		}
 #endif
 
-		public virtual void Reset()
-		{
-		}
-
 		/**
 		* Re-key the cipher.
 		*
diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index 342dbd93d..dd4281f8f 100644
--- a/crypto/src/crypto/macs/CMac.cs
+++ b/crypto/src/crypto/macs/CMac.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         private byte[] buf;
         private int bufOff;
-        private IBlockCipher cipher;
+        private IBlockCipherMode m_cipherMode;
 
         private int macSize;
 
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Crypto.Macs
                     "Block size must be either 64 or 128 bits");
             }
 
-            this.cipher = new CbcBlockCipher(cipher);
+            m_cipherMode = new CbcBlockCipher(cipher);
             this.macSize = macSizeInBits / 8;
 
             mac = new byte[cipher.GetBlockSize()];
@@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
         public string AlgorithmName
         {
-            get { return cipher.AlgorithmName; }
+            get { return m_cipherMode.AlgorithmName; }
         }
 
         private static int ShiftLeft(byte[] block, byte[] output)
@@ -136,11 +136,11 @@ namespace Org.BouncyCastle.Crypto.Macs
         {
             if (parameters is KeyParameter)
             {
-                cipher.Init(true, parameters);
+                m_cipherMode.Init(true, parameters);
 
                 //initializes the L, Lu, Lu2 numbers
                 L = new byte[ZEROES.Length];
-                cipher.ProcessBlock(ZEROES, 0, L, 0);
+                m_cipherMode.ProcessBlock(ZEROES, 0, L, 0);
                 Lu = DoubleLu(L);
                 Lu2 = DoubleLu(Lu);
             }
@@ -162,7 +162,7 @@ namespace Org.BouncyCastle.Crypto.Macs
         {
             if (bufOff == buf.Length)
             {
-                cipher.ProcessBlock(buf, 0, mac, 0);
+                m_cipherMode.ProcessBlock(buf, 0, mac, 0);
                 bufOff = 0;
             }
 
@@ -177,14 +177,14 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             BlockUpdate(inBytes.AsSpan(inOff, len));
 #else
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
             if (len > gapLen)
             {
                 Array.Copy(inBytes, inOff, buf, bufOff, gapLen);
 
-                cipher.ProcessBlock(buf, 0, mac, 0);
+                m_cipherMode.ProcessBlock(buf, 0, mac, 0);
 
                 bufOff = 0;
                 len -= gapLen;
@@ -192,7 +192,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
                 while (len > blockSize)
                 {
-                    cipher.ProcessBlock(inBytes, inOff, mac, 0);
+                    m_cipherMode.ProcessBlock(inBytes, inOff, mac, 0);
 
                     len -= blockSize;
                     inOff += blockSize;
@@ -208,21 +208,21 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public void BlockUpdate(ReadOnlySpan<byte> input)
         {
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
             if (input.Length > gapLen)
             {
                 input[..gapLen].CopyTo(buf.AsSpan(bufOff));
 
-                cipher.ProcessBlock(buf, mac);
+                m_cipherMode.ProcessBlock(buf, mac);
 
                 bufOff = 0;
                 input = input[gapLen..];
 
                 while (input.Length > blockSize)
                 {
-                    cipher.ProcessBlock(input, mac);
+                    m_cipherMode.ProcessBlock(input, mac);
                     input = input[blockSize..];
                 }
             }
@@ -238,7 +238,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             return DoFinal(outBytes.AsSpan(outOff));
 #else
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
 
             byte[] lu;
             if (bufOff == blockSize)
@@ -256,7 +256,7 @@ namespace Org.BouncyCastle.Crypto.Macs
                 buf[i] ^= lu[i];
             }
 
-            cipher.ProcessBlock(buf, 0, mac, 0);
+            m_cipherMode.ProcessBlock(buf, 0, mac, 0);
 
             Array.Copy(mac, 0, outBytes, outOff, macSize);
 
@@ -269,7 +269,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public int DoFinal(Span<byte> output)
         {
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
 
             byte[] lu;
             if (bufOff == blockSize)
@@ -287,7 +287,7 @@ namespace Org.BouncyCastle.Crypto.Macs
                 buf[i] ^= lu[i];
             }
 
-            cipher.ProcessBlock(buf, mac);
+            m_cipherMode.ProcessBlock(buf, mac);
 
             mac.AsSpan(0, macSize).CopyTo(output);
 
@@ -311,7 +311,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             /*
             * Reset the underlying cipher.
             */
-            cipher.Reset();
+            m_cipherMode.Reset();
         }
     }
 }
diff --git a/crypto/src/crypto/macs/CbcBlockCipherMac.cs b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
index abf06170c..c660c0dc3 100644
--- a/crypto/src/crypto/macs/CbcBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
@@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Crypto.Macs
     {
         private byte[] buf;
         private int bufOff;
-        private IBlockCipher cipher;
+        private IBlockCipherMode m_cipherMode;
         private IBlockCipherPadding padding;
 		private int macSize;
 
@@ -86,7 +86,7 @@ namespace Org.BouncyCastle.Crypto.Macs
             if ((macSizeInBits % 8) != 0)
                 throw new ArgumentException("MAC size must be multiple of 8");
 
-			this.cipher = new CbcBlockCipher(cipher);
+			this.m_cipherMode = new CbcBlockCipher(cipher);
             this.padding = padding;
             this.macSize = macSizeInBits / 8;
 
@@ -96,14 +96,14 @@ namespace Org.BouncyCastle.Crypto.Macs
 
 		public string AlgorithmName
         {
-            get { return cipher.AlgorithmName; }
+            get { return m_cipherMode.AlgorithmName; }
         }
 
 		public void Init(ICipherParameters parameters)
         {
             Reset();
 
-			cipher.Init(true, parameters);
+            m_cipherMode.Init(true, parameters);
         }
 
 		public int GetMacSize()
@@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.Macs
         {
 			if (bufOff == buf.Length)
             {
-				cipher.ProcessBlock(buf, 0, buf, 0);
+                m_cipherMode.ProcessBlock(buf, 0, buf, 0);
                 bufOff = 0;
             }
 
@@ -130,14 +130,14 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             BlockUpdate(input.AsSpan(inOff, len));
 #else
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
             if (len > gapLen)
             {
                 Array.Copy(input, inOff, buf, bufOff, gapLen);
 
-                cipher.ProcessBlock(buf, 0, buf, 0);
+                m_cipherMode.ProcessBlock(buf, 0, buf, 0);
 
                 bufOff = 0;
                 len -= gapLen;
@@ -145,7 +145,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
                 while (len > blockSize)
                 {
-                    cipher.ProcessBlock(input, inOff, buf, 0);
+                    m_cipherMode.ProcessBlock(input, inOff, buf, 0);
 
                     len -= blockSize;
                     inOff += blockSize;
@@ -161,21 +161,21 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public void BlockUpdate(ReadOnlySpan<byte> input)
         {
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
             int gapLen = blockSize - bufOff;
 
             if (input.Length > gapLen)
             {
                 input[..gapLen].CopyTo(buf.AsSpan(bufOff));
 
-                cipher.ProcessBlock(buf, buf);
+                m_cipherMode.ProcessBlock(buf, buf);
 
                 bufOff = 0;
                 input = input[gapLen..];
 
                 while (input.Length > blockSize)
                 {
-                    cipher.ProcessBlock(input, buf);
+                    m_cipherMode.ProcessBlock(input, buf);
                     input = input[blockSize..];
                 }
             }
@@ -191,7 +191,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             return DoFinal(output.AsSpan(outOff));
 #else
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
 
             if (padding == null)
             {
@@ -205,14 +205,14 @@ namespace Org.BouncyCastle.Crypto.Macs
             {
                 if (bufOff == blockSize)
                 {
-                    cipher.ProcessBlock(buf, 0, buf, 0);
+                    m_cipherMode.ProcessBlock(buf, 0, buf, 0);
                     bufOff = 0;
                 }
 
 				padding.AddPadding(buf, bufOff);
             }
 
-			cipher.ProcessBlock(buf, 0, buf, 0);
+			m_cipherMode.ProcessBlock(buf, 0, buf, 0);
 
 			Array.Copy(buf, 0, output, outOff, macSize);
 
@@ -225,7 +225,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public int DoFinal(Span<byte> output)
         {
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
 
             if (padding == null)
             {
@@ -239,14 +239,14 @@ namespace Org.BouncyCastle.Crypto.Macs
             {
                 if (bufOff == blockSize)
                 {
-                    cipher.ProcessBlock(buf, buf);
+                    m_cipherMode.ProcessBlock(buf, buf);
                     bufOff = 0;
                 }
 
 				padding.AddPadding(buf, bufOff);
             }
 
-			cipher.ProcessBlock(buf, buf);
+            m_cipherMode.ProcessBlock(buf, buf);
 
             buf.AsSpan(0, macSize).CopyTo(output);
 
@@ -265,8 +265,8 @@ namespace Org.BouncyCastle.Crypto.Macs
 			Array.Clear(buf, 0, buf.Length);
 			bufOff = 0;
 
-			// Reset the underlying cipher.
-            cipher.Reset();
+            // Reset the underlying cipher.
+            m_cipherMode.Reset();
         }
     }
 }
diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
index a4d005700..8f3f89993 100644
--- a/crypto/src/crypto/macs/CfbBlockCipherMac.cs
+++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Macs
     * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
     */
     internal class MacCfbBlockCipher
-		: IBlockCipher
+		: IBlockCipherMode
     {
         private byte[] IV;
         private byte[] cfbV;
@@ -81,7 +81,9 @@ namespace Org.BouncyCastle.Crypto.Macs
 			get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
         }
 
-		public bool IsPartialBlockOkay
+        public IBlockCipher UnderlyingCipher => cipher;
+
+        public bool IsPartialBlockOkay
 		{
 			get { return true; }
 		}
@@ -153,8 +155,6 @@ namespace Org.BouncyCastle.Crypto.Macs
         public void Reset()
         {
 			IV.CopyTo(cfbV, 0);
-
-			cipher.Reset();
         }
 
 		public void GetMacBlock(
diff --git a/crypto/src/crypto/macs/DSTU7624Mac.cs b/crypto/src/crypto/macs/DSTU7624Mac.cs
index 8fecb1915..f96bdec98 100644
--- a/crypto/src/crypto/macs/DSTU7624Mac.cs
+++ b/crypto/src/crypto/macs/DSTU7624Mac.cs
@@ -214,7 +214,6 @@ namespace Org.BouncyCastle.Crypto.Macs
             Arrays.Fill(cTemp, (byte)0x00);
             Arrays.Fill(kDelta, (byte)0x00);
             Arrays.Fill(buf, (byte)0x00);
-            engine.Reset();
             engine.ProcessBlock(kDelta, 0, kDelta, 0);
             bufOff = 0;
         }
diff --git a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
index 40a68007e..1b9562bda 100644
--- a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
+++ b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
@@ -13,7 +13,8 @@ namespace Org.BouncyCastle.Crypto.Macs
 	* This could as well be derived from CBCBlockCipherMac, but then the property mac in the base
 	* class must be changed to protected
 	*/
-	public class ISO9797Alg3Mac : IMac
+	public class ISO9797Alg3Mac
+		: IMac
 	{
 		private byte[] mac;
 		private byte[] buf;
@@ -343,9 +344,6 @@ namespace Org.BouncyCastle.Crypto.Macs
 		{
 			Array.Clear(buf, 0, buf.Length);
 			bufOff = 0;
-
-			// reset the underlying cipher.
-			cipher.Reset();
 		}
 	}
 }
diff --git a/crypto/src/crypto/modes/CbcBlockCipher.cs b/crypto/src/crypto/modes/CbcBlockCipher.cs
index eb89c81ee..2a2db2437 100644
--- a/crypto/src/crypto/modes/CbcBlockCipher.cs
+++ b/crypto/src/crypto/modes/CbcBlockCipher.cs
@@ -8,7 +8,7 @@ namespace Org.BouncyCastle.Crypto.Modes
     * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
     */
     public class CbcBlockCipher
-		: IBlockCipher
+		: IBlockCipherMode
     {
         private byte[]			IV, cbcV, cbcNextV;
 		private int				blockSize;
@@ -36,10 +36,7 @@ namespace Org.BouncyCastle.Crypto.Modes
         *
         * @return the underlying block cipher that we are wrapping.
         */
-        public IBlockCipher GetUnderlyingCipher()
-        {
-            return cipher;
-        }
+        public IBlockCipher UnderlyingCipher => cipher;
 
         /**
         * Initialise the cipher and, possibly, the initialisation vector (IV).
@@ -139,8 +136,6 @@ namespace Org.BouncyCastle.Crypto.Modes
         {
             Array.Copy(IV, 0, cbcV, 0, IV.Length);
 			Array.Clear(cbcNextV, 0, cbcNextV.Length);
-
-            cipher.Reset();
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index 0a2adb57d..fdd664a32 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -191,7 +191,6 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual void Reset()
         {
-            cipher.Reset();
             associatedText.SetLength(0);
             data.SetLength(0);
         }
diff --git a/crypto/src/crypto/modes/CfbBlockCipher.cs b/crypto/src/crypto/modes/CfbBlockCipher.cs
index bcbffcfb6..abcdca959 100644
--- a/crypto/src/crypto/modes/CfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -8,7 +8,7 @@ namespace Org.BouncyCastle.Crypto.Modes
     * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
     */
     public class CfbBlockCipher
-		: IBlockCipher
+		: IBlockCipherMode
     {
         private byte[]	IV;
         private byte[]	cfbV;
@@ -43,10 +43,8 @@ namespace Org.BouncyCastle.Crypto.Modes
         *
         * @return the underlying block cipher that we are wrapping.
         */
-        public IBlockCipher GetUnderlyingCipher()
-        {
-            return cipher;
-        }
+        public IBlockCipher UnderlyingCipher => cipher;
+
         /**
         * Initialise the cipher and, possibly, the initialisation vector (IV).
         * If an IV isn't passed as part of the parameter, the IV will be all zeros.
@@ -223,7 +221,6 @@ namespace Org.BouncyCastle.Crypto.Modes
         public void Reset()
         {
             Array.Copy(IV, 0, cfbV, 0, IV.Length);
-            cipher.Reset();
         }
     }
 }
diff --git a/crypto/src/crypto/modes/CtsBlockCipher.cs b/crypto/src/crypto/modes/CtsBlockCipher.cs
index 5a1682568..022e86675 100644
--- a/crypto/src/crypto/modes/CtsBlockCipher.cs
+++ b/crypto/src/crypto/modes/CtsBlockCipher.cs
@@ -12,21 +12,24 @@ namespace Org.BouncyCastle.Crypto.Modes
     {
         private readonly int blockSize;
 
+        public CtsBlockCipher(IBlockCipher cipher)
+            : this(EcbBlockCipher.GetBlockCipherMode(cipher))
+        {
+        }
+
         /**
         * Create a buffered block cipher that uses Cipher Text Stealing
         *
         * @param cipher the underlying block cipher this buffering object wraps.
         */
-        public CtsBlockCipher(
-            IBlockCipher cipher)
+        public CtsBlockCipher(IBlockCipherMode cipherMode)
         {
-			// TODO Should this test for acceptable ones instead?
-			if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
+            if (!(cipherMode is CbcBlockCipher || cipherMode is EcbBlockCipher))
                 throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
 
-			this.cipher = cipher;
+			m_cipherMode = cipherMode;
 
-            blockSize = cipher.GetBlockSize();
+            blockSize = cipherMode.GetBlockSize();
 
             buf = new byte[blockSize * 2];
             bufOff = 0;
@@ -83,7 +86,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
             if (bufOff == buf.Length)
             {
-                resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+                resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
 				Debug.Assert(resultLen == blockSize);
 
 				Array.Copy(buf, blockSize, buf, 0, blockSize);
@@ -102,7 +105,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
             if (bufOff == buf.Length)
             {
-                resultLen = cipher.ProcessBlock(buf, output);
+                resultLen = m_cipherMode.ProcessBlock(buf, output);
                 Debug.Assert(resultLen == blockSize);
 
                 Array.Copy(buf, blockSize, buf, 0, blockSize);
@@ -147,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             {
                 Array.Copy(input, inOff, buf, bufOff, gapLen);
 
-                resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+                resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
                 Array.Copy(buf, blockSize, buf, 0, blockSize);
 
                 bufOff = blockSize;
@@ -158,7 +161,7 @@ namespace Org.BouncyCastle.Crypto.Modes
                 while (length > blockSize)
                 {
                     Array.Copy(input, inOff, buf, bufOff, blockSize);
-                    resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+                    resultLen += m_cipherMode.ProcessBlock(buf, 0, output, outOff + resultLen);
                     Array.Copy(buf, blockSize, buf, 0, blockSize);
 
                     length -= blockSize;
@@ -191,7 +194,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             {
                 input[..gapLen].CopyTo(buf.AsSpan(bufOff));
 
-                resultLen = cipher.ProcessBlock(buf, output);
+                resultLen = m_cipherMode.ProcessBlock(buf, output);
                 Array.Copy(buf, blockSize, buf, 0, blockSize);
 
                 bufOff = blockSize;
@@ -201,7 +204,7 @@ namespace Org.BouncyCastle.Crypto.Modes
                 while (input.Length > blockSize)
                 {
                     input[..blockSize].CopyTo(buf.AsSpan(bufOff));
-                    resultLen += cipher.ProcessBlock(buf, output[resultLen..]);
+                    resultLen += m_cipherMode.ProcessBlock(buf, output[resultLen..]);
                     Array.Copy(buf, blockSize, buf, 0, blockSize);
 
                     input = input[blockSize..];
@@ -234,13 +237,13 @@ namespace Org.BouncyCastle.Crypto.Modes
             if (bufOff + outOff > output.Length)
                 throw new DataLengthException("output buffer too small in DoFinal");
 
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
             int length = bufOff - blockSize;
             byte[] block = new byte[blockSize];
 
             if (forEncryption)
             {
-                cipher.ProcessBlock(buf, 0, block, 0);
+                m_cipherMode.ProcessBlock(buf, 0, block, 0);
 
 				if (bufOff < blockSize)
 					throw new DataLengthException("need at least one block of input for CTS");
@@ -255,11 +258,7 @@ namespace Org.BouncyCastle.Crypto.Modes
                     buf[i] ^= block[i - blockSize];
                 }
 
-				IBlockCipher c = (cipher is CbcBlockCipher)
-					?	((CbcBlockCipher)cipher).GetUnderlyingCipher()
-					:	cipher;
-
-				c.ProcessBlock(buf, blockSize, output, outOff);
+                m_cipherMode.UnderlyingCipher.ProcessBlock(buf, blockSize, output, outOff);
 
 				Array.Copy(block, 0, output, outOff + blockSize, length);
             }
@@ -267,11 +266,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             {
                 byte[] lastBlock = new byte[blockSize];
 
-				IBlockCipher c = (cipher is CbcBlockCipher)
-					?	((CbcBlockCipher)cipher).GetUnderlyingCipher()
-					:	cipher;
-
-				c.ProcessBlock(buf, 0, block, 0);
+                m_cipherMode.UnderlyingCipher.ProcessBlock(buf, 0, block, 0);
 
 				for (int i = blockSize; i != bufOff; i++)
                 {
@@ -280,7 +275,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
                 Array.Copy(buf, blockSize, block, 0, length);
 
-                cipher.ProcessBlock(block, 0, output, outOff);
+                m_cipherMode.ProcessBlock(block, 0, output, outOff);
                 Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
             }
 
@@ -297,13 +292,13 @@ namespace Org.BouncyCastle.Crypto.Modes
             if (bufOff > output.Length)
                 throw new DataLengthException("output buffer too small in DoFinal");
 
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
             int length = bufOff - blockSize;
             Span<byte> block = stackalloc byte[blockSize];
 
             if (forEncryption)
             {
-                cipher.ProcessBlock(buf, block);
+                m_cipherMode.ProcessBlock(buf, block);
 
                 if (bufOff < blockSize)
                     throw new DataLengthException("need at least one block of input for CTS");
@@ -318,11 +313,7 @@ namespace Org.BouncyCastle.Crypto.Modes
                     buf[i] ^= block[i - blockSize];
                 }
 
-                IBlockCipher c = (cipher is CbcBlockCipher)
-                    ? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
-                    : cipher;
-
-                c.ProcessBlock(buf.AsSpan(blockSize), output);
+                m_cipherMode.UnderlyingCipher.ProcessBlock(buf.AsSpan(blockSize), output);
 
                 block[..length].CopyTo(output[blockSize..]);
             }
@@ -330,11 +321,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             {
                 Span<byte> lastBlock = stackalloc byte[blockSize];
 
-                IBlockCipher c = (cipher is CbcBlockCipher)
-                    ? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
-                    : cipher;
-
-                c.ProcessBlock(buf, block);
+                m_cipherMode.UnderlyingCipher.ProcessBlock(buf, block);
 
                 for (int i = blockSize; i != bufOff; i++)
                 {
@@ -343,7 +330,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
                 buf.AsSpan(blockSize, length).CopyTo(block);
 
-                cipher.ProcessBlock(block, output);
+                m_cipherMode.ProcessBlock(block, output);
                 lastBlock[..length].CopyTo(output[blockSize..]);
             }
 
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index e63826159..acf33ccb7 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 		public virtual string AlgorithmName
 		{
-			get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
+			get { return cipher.UnderlyingCipher.AlgorithmName + "/EAX"; }
 		}
 
 		public virtual IBlockCipher GetUnderlyingCipher()
diff --git a/crypto/src/crypto/modes/EcbBlockCipher.cs b/crypto/src/crypto/modes/EcbBlockCipher.cs
new file mode 100644
index 000000000..96f9811dd
--- /dev/null
+++ b/crypto/src/crypto/modes/EcbBlockCipher.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    public class EcbBlockCipher
+        : IBlockCipherMode
+    {
+        internal static IBlockCipherMode GetBlockCipherMode(IBlockCipher blockCipher)
+        {
+            if (blockCipher is IBlockCipherMode blockCipherMode)
+                return blockCipherMode;
+
+            return new EcbBlockCipher(blockCipher);
+        }
+
+        private readonly IBlockCipher m_cipher;
+
+        public EcbBlockCipher(IBlockCipher cipher)
+        {
+            if (cipher == null)
+                throw new ArgumentNullException(nameof(cipher));
+
+            m_cipher = cipher;
+        }
+
+        public bool IsPartialBlockOkay => false;
+
+        public string AlgorithmName => m_cipher.AlgorithmName + "/ECB";
+
+        public int GetBlockSize()
+        {
+            return m_cipher.GetBlockSize();
+        }
+
+        public IBlockCipher UnderlyingCipher => m_cipher;
+
+        public void Init(bool forEncryption, ICipherParameters parameters)
+        {
+            m_cipher.Init(forEncryption, parameters);
+        }
+
+        public int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff)
+        {
+            return m_cipher.ProcessBlock(inBuf, inOff, outBuf, outOff);
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            return m_cipher.ProcessBlock(input, output);
+        }
+#endif
+
+        public void Reset()
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 2ab406fc3..58e83c257 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -867,11 +867,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             Reset(true);
         }
 
-        private void Reset(
-            bool clearMac)
+        private void Reset(bool clearMac)
         {
-            cipher.Reset();
-
             // note: we do not reset the nonce.
 
             S = new byte[BlockSize];
diff --git a/crypto/src/crypto/modes/GOFBBlockCipher.cs b/crypto/src/crypto/modes/GOFBBlockCipher.cs
index 4c8576a58..cfcbe4fcd 100644
--- a/crypto/src/crypto/modes/GOFBBlockCipher.cs
+++ b/crypto/src/crypto/modes/GOFBBlockCipher.cs
@@ -9,8 +9,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 	* implements the GOST 28147 OFB counter mode (GCTR).
 	*/
 	public class GOfbBlockCipher
-		: IBlockCipher
-	{
+		: IBlockCipherMode
+    {
 		private byte[]	IV;
 		private byte[]	ofbV;
 		private byte[]	ofbOutV;
@@ -46,15 +46,12 @@ namespace Org.BouncyCastle.Crypto.Modes
 			this.ofbOutV = new byte[cipher.GetBlockSize()];
 		}
 
-		/**
+        /**
 		* return the underlying block cipher that we are wrapping.
 		*
 		* @return the underlying block cipher that we are wrapping.
 		*/
-		public IBlockCipher GetUnderlyingCipher()
-		{
-			return cipher;
-		}
+        public IBlockCipher UnderlyingCipher => cipher;
 
 		/**
 		* Initialise the cipher and, possibly, the initialisation vector (IV).
@@ -228,8 +225,6 @@ namespace Org.BouncyCastle.Crypto.Modes
 		public void Reset()
 		{
 			Array.Copy(IV, 0, ofbV, 0, IV.Length);
-
-			cipher.Reset();
 		}
 	}
 }
diff --git a/crypto/src/crypto/modes/IBlockCipherMode.cs b/crypto/src/crypto/modes/IBlockCipherMode.cs
new file mode 100644
index 000000000..f6e3991c6
--- /dev/null
+++ b/crypto/src/crypto/modes/IBlockCipherMode.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    public interface IBlockCipherMode
+        : IBlockCipher
+    {
+        /// <summary>Return the <code cref="IBlockCipher"/> underlying this cipher mode.</summary>
+        IBlockCipher UnderlyingCipher { get; }
+
+        /// <summary>Indicates whether this cipher mode can handle partial blocks.</summary>
+        bool IsPartialBlockOkay { get; }
+
+        /// <summary>
+        /// Reset the cipher mode to the same state as it was after the last init (if there was one).
+        /// </summary>
+        void Reset();
+    }
+}
diff --git a/crypto/src/crypto/modes/KCtrBlockCipher.cs b/crypto/src/crypto/modes/KCtrBlockCipher.cs
index 79b74f84c..b0c4054e0 100644
--- a/crypto/src/crypto/modes/KCtrBlockCipher.cs
+++ b/crypto/src/crypto/modes/KCtrBlockCipher.cs
@@ -7,7 +7,8 @@ namespace Org.BouncyCastle.Crypto.Modes
     /**
     * Implements a Gamming or Counter (CTR) mode on top of a DSTU 7624 block cipher.
     */
-    public class KCtrBlockCipher : IStreamCipher, IBlockCipher
+    public class KCtrBlockCipher
+        : IStreamCipher, IBlockCipherMode
     {
         private byte[] IV;
         private byte[] ofbV;
@@ -40,10 +41,8 @@ namespace Org.BouncyCastle.Crypto.Modes
         *
         * @return the underlying block cipher that we are wrapping.
         */
-        public IBlockCipher GetUnderlyingCipher()
-        {
-            return cipher;
-        }
+        public IBlockCipher UnderlyingCipher => cipher;
+
         /**
         * Initialise the cipher and, possibly, the initialisation vector (IV).
         * If an IV isn't passed as part of the parameter, the IV will be all zeros.
@@ -213,7 +212,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             {
                 cipher.ProcessBlock(IV, 0, ofbV, 0);
             }
-            cipher.Reset();
             byteCount = 0;
         }
 
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index a4eaa08bd..ee327f200 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -643,9 +643,6 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         protected virtual void Reset(bool clearMac)
         {
-            hashCipher.Reset();
-            mainCipher.Reset();
-
             Clear(hashBlock);
             Clear(mainBlock);
 
diff --git a/crypto/src/crypto/modes/OfbBlockCipher.cs b/crypto/src/crypto/modes/OfbBlockCipher.cs
index ac9b9a06c..9bf4c25c7 100644
--- a/crypto/src/crypto/modes/OfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OfbBlockCipher.cs
@@ -8,7 +8,7 @@ namespace Org.BouncyCastle.Crypto.Modes
     * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
     */
     public class OfbBlockCipher
-		: IBlockCipher
+		: IBlockCipherMode
     {
         private byte[]	IV;
         private byte[]	ofbV;
@@ -41,10 +41,7 @@ namespace Org.BouncyCastle.Crypto.Modes
         *
         * @return the underlying block cipher that we are wrapping.
         */
-        public IBlockCipher GetUnderlyingCipher()
-        {
-            return cipher;
-        }
+        public IBlockCipher UnderlyingCipher => cipher;
 
         /**
         * Initialise the cipher and, possibly, the initialisation vector (IV).
@@ -176,9 +173,6 @@ namespace Org.BouncyCastle.Crypto.Modes
         public void Reset()
         {
             Array.Copy(IV, 0, ofbV, 0, IV.Length);
-
-            cipher.Reset();
         }
     }
-
 }
diff --git a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
index 45998248c..4e6e0ffaa 100644
--- a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 	* </p>
     */
     public class OpenPgpCfbBlockCipher
-        : IBlockCipher
+        : IBlockCipherMode
     {
         private byte[] IV;
         private byte[] FR;
@@ -43,15 +43,12 @@ namespace Org.BouncyCastle.Crypto.Modes
             this.FRE = new byte[blockSize];
         }
 
-		/**
+        /**
         * return the underlying block cipher that we are wrapping.
         *
         * @return the underlying block cipher that we are wrapping.
         */
-        public IBlockCipher GetUnderlyingCipher()
-        {
-            return cipher;
-        }
+        public IBlockCipher UnderlyingCipher => cipher;
 
 		/**
         * return the algorithm name and mode.
@@ -110,8 +107,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             count = 0;
 
 			Array.Copy(IV, 0, FR, 0, FR.Length);
-
-			cipher.Reset();
         }
 
         /**
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index 431e2952c..fee8bb028 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Crypto.Modes
     * block cipher.
     */
     public class SicBlockCipher
-        : IBlockCipher
+        : IBlockCipherMode
     {
         private readonly IBlockCipher cipher;
         private readonly int blockSize;
@@ -39,10 +39,7 @@ namespace Org.BouncyCastle.Crypto.Modes
         *
         * @return the underlying block cipher that we are wrapping.
         */
-        public virtual IBlockCipher GetUnderlyingCipher()
-        {
-            return cipher;
-        }
+        public IBlockCipher UnderlyingCipher => cipher;
 
         public virtual void Init(
             bool				forEncryption, //ignored by this CTR mode
@@ -133,7 +130,6 @@ namespace Org.BouncyCastle.Crypto.Modes
         {
             Arrays.Fill(counter, (byte)0);
             Array.Copy(IV, 0, counter, 0, IV.Length);
-            cipher.Reset();
         }
     }
 }
diff --git a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
index a2d4dcc32..fb000ff8b 100644
--- a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
+++ b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Modes;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 
@@ -15,22 +16,25 @@ namespace Org.BouncyCastle.Crypto.Paddings
 	public class PaddedBufferedBlockCipher
 		: BufferedBlockCipher
 	{
-		private readonly IBlockCipherPadding padding;
+        private readonly IBlockCipherPadding padding;
 
-		/**
+        public PaddedBufferedBlockCipher(IBlockCipher cipher, IBlockCipherPadding padding)
+			: this(EcbBlockCipher.GetBlockCipherMode(cipher), padding)
+        {
+        }
+
+        /**
 		* Create a buffered block cipher with the desired padding.
 		*
 		* @param cipher the underlying block cipher this buffering object wraps.
 		* @param padding the padding type.
 		*/
-		public PaddedBufferedBlockCipher(
-			IBlockCipher cipher,
-			IBlockCipherPadding padding)
+        public PaddedBufferedBlockCipher(IBlockCipherMode cipherMode, IBlockCipherPadding padding)
 		{
-			this.cipher = cipher;
+			m_cipherMode = cipherMode;
 			this.padding = padding;
 
-			buf = new byte[cipher.GetBlockSize()];
+			buf = new byte[m_cipherMode.GetBlockSize()];
 			bufOff = 0;
 		}
 
@@ -39,9 +43,8 @@ namespace Org.BouncyCastle.Crypto.Paddings
 		*
 		* @param cipher the underlying block cipher this buffering object wraps.
 		*/
-		public PaddedBufferedBlockCipher(
-			IBlockCipher cipher)
-			: this(cipher, new Pkcs7Padding())
+		public PaddedBufferedBlockCipher(IBlockCipherMode cipherMode)
+			: this(cipherMode, new Pkcs7Padding())
 		{
 		}
 
@@ -54,23 +57,20 @@ namespace Org.BouncyCastle.Crypto.Paddings
 		* @exception ArgumentException if the parameters argument is
 		* inappropriate.
 		*/
-		public override void Init(
-			bool forEncryption,
-			ICipherParameters parameters)
+		public override void Init(bool forEncryption, ICipherParameters parameters)
 		{
 			this.forEncryption = forEncryption;
 
 			SecureRandom initRandom = null;
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				ParametersWithRandom p = (ParametersWithRandom)parameters;
-				initRandom = p.Random;
-				parameters = p.Parameters;
+				initRandom = withRandom.Random;
+				parameters = withRandom.Parameters;
 			}
 
 			Reset();
 			padding.Init(initRandom);
-			cipher.Init(forEncryption, parameters);
+			m_cipherMode.Init(forEncryption, parameters);
 		}
 
 		/**
@@ -138,7 +138,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 
 			if (bufOff == buf.Length)
 			{
-				resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+				resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
 				bufOff = 0;
 			}
 
@@ -154,7 +154,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 
 			if (bufOff == buf.Length)
 			{
-				resultLen = cipher.ProcessBlock(buf, output);
+				resultLen = m_cipherMode.ProcessBlock(buf, output);
 				bufOff = 0;
 			}
 
@@ -196,7 +196,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 			{
 				Array.Copy(input, inOff, buf, bufOff, gapLen);
 
-				resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+				resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
 
 				bufOff = 0;
 				length -= gapLen;
@@ -204,7 +204,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 
 				while (length > buf.Length)
 				{
-					resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+					resultLen += m_cipherMode.ProcessBlock(input, inOff, output, outOff + resultLen);
 
 					length -= blockSize;
 					inOff += blockSize;
@@ -236,14 +236,14 @@ namespace Org.BouncyCastle.Crypto.Paddings
 			{
 				input[..gapLen].CopyTo(buf.AsSpan(bufOff));
 
-				resultLen = cipher.ProcessBlock(buf, output);
+				resultLen = m_cipherMode.ProcessBlock(buf, output);
 
 				bufOff = 0;
 				input = input[gapLen..];
 
 				while (input.Length > buf.Length)
 				{
-					resultLen += cipher.ProcessBlock(input, output[resultLen..]);
+					resultLen += m_cipherMode.ProcessBlock(input, output[resultLen..]);
 
 					input = input[blockSize..];
 				}
@@ -273,7 +273,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 		*/
         public override int DoFinal(byte[] output, int outOff)
         {
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
 			int resultLen = 0;
 
 			if (forEncryption)
@@ -287,13 +287,13 @@ namespace Org.BouncyCastle.Crypto.Paddings
 						throw new OutputLengthException("output buffer too short");
 					}
 
-					resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+					resultLen = m_cipherMode.ProcessBlock(buf, 0, output, outOff);
 					bufOff = 0;
 				}
 
 				padding.AddPadding(buf, bufOff);
 
-				resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+				resultLen += m_cipherMode.ProcessBlock(buf, 0, output, outOff + resultLen);
 
 				Reset();
 			}
@@ -301,7 +301,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 			{
 				if (bufOff == blockSize)
 				{
-					resultLen = cipher.ProcessBlock(buf, 0, buf, 0);
+					resultLen = m_cipherMode.ProcessBlock(buf, 0, buf, 0);
 					bufOff = 0;
 				}
 				else
@@ -329,7 +329,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
 		public override int DoFinal(Span<byte> output)
 		{
-            int blockSize = cipher.GetBlockSize();
+            int blockSize = m_cipherMode.GetBlockSize();
 			int resultLen = 0;
 
 			if (forEncryption)
@@ -343,13 +343,13 @@ namespace Org.BouncyCastle.Crypto.Paddings
 						throw new OutputLengthException("output buffer too short");
 					}
 
-					resultLen = cipher.ProcessBlock(buf, output);
+					resultLen = m_cipherMode.ProcessBlock(buf, output);
 					bufOff = 0;
 				}
 
 				padding.AddPadding(buf, bufOff);
 
-				resultLen += cipher.ProcessBlock(buf, output[resultLen..]);
+				resultLen += m_cipherMode.ProcessBlock(buf, output[resultLen..]);
 
 				Reset();
 			}
@@ -362,7 +362,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
                     throw new DataLengthException("last block incomplete in decryption");
                 }
 
-                resultLen = cipher.ProcessBlock(buf, buf);
+                resultLen = m_cipherMode.ProcessBlock(buf, buf);
 				bufOff = 0;
 
 				try
diff --git a/crypto/src/crypto/util/CipherFactory.cs b/crypto/src/crypto/util/CipherFactory.cs
index 2e8c44bb4..56f57c545 100644
--- a/crypto/src/crypto/util/CipherFactory.cs
+++ b/crypto/src/crypto/util/CipherFactory.cs
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
 
         private static BufferedBlockCipher CreateCipher(DerObjectIdentifier algorithm)
         {
-            IBlockCipher cipher;
+            IBlockCipherMode cipher;
 
             if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm)
                 || NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm)
diff --git a/crypto/src/security/CipherUtilities.cs b/crypto/src/security/CipherUtilities.cs
index 8ed5d8d41..929040e2c 100644
--- a/crypto/src/security/CipherUtilities.cs
+++ b/crypto/src/security/CipherUtilities.cs
@@ -620,6 +620,7 @@ namespace Org.BouncyCastle.Security
             }
 
             string mode = "";
+            IBlockCipherMode blockCipherMode = null;
             if (parts.Length > 1)
             {
                 mode = parts[1];
@@ -639,7 +640,7 @@ namespace Org.BouncyCastle.Security
                     case CipherMode.NONE:
                         break;
                     case CipherMode.CBC:
-                        blockCipher = new CbcBlockCipher(blockCipher);
+                        blockCipherMode = new CbcBlockCipher(blockCipher);
                         break;
                     case CipherMode.CCM:
                         aeadBlockCipher = new CcmBlockCipher(blockCipher);
@@ -650,15 +651,15 @@ namespace Org.BouncyCastle.Security
                             ?	8 * blockCipher.GetBlockSize()
                             :	int.Parse(mode.Substring(di));
     
-                        blockCipher = new CfbBlockCipher(blockCipher, bits);
+                        blockCipherMode = new CfbBlockCipher(blockCipher, bits);
                         break;
                     }
                     case CipherMode.CTR:
-                        blockCipher = new SicBlockCipher(blockCipher);
+                        blockCipherMode = new SicBlockCipher(blockCipher);
                         break;
                     case CipherMode.CTS:
                         cts = true;
-                        blockCipher = new CbcBlockCipher(blockCipher);
+                        blockCipherMode = new CbcBlockCipher(blockCipher);
                         break;
                     case CipherMode.EAX:
                         aeadBlockCipher = new EaxBlockCipher(blockCipher);
@@ -667,7 +668,7 @@ namespace Org.BouncyCastle.Security
                         aeadBlockCipher = new GcmBlockCipher(blockCipher);
                         break;
                     case CipherMode.GOFB:
-                        blockCipher = new GOfbBlockCipher(blockCipher);
+                        blockCipherMode = new GOfbBlockCipher(blockCipher);
                         break;
                     case CipherMode.OCB:
                         aeadBlockCipher = new OcbBlockCipher(blockCipher, CreateBlockCipher(cipherAlgorithm));
@@ -678,18 +679,18 @@ namespace Org.BouncyCastle.Security
                             ?	8 * blockCipher.GetBlockSize()
                             :	int.Parse(mode.Substring(di));
     
-                        blockCipher = new OfbBlockCipher(blockCipher, bits);
+                        blockCipherMode = new OfbBlockCipher(blockCipher, bits);
                         break;
                     }
                     case CipherMode.OPENPGPCFB:
-                        blockCipher = new OpenPgpCfbBlockCipher(blockCipher);
+                        blockCipherMode = new OpenPgpCfbBlockCipher(blockCipher);
                         break;
                     case CipherMode.SIC:
                         if (blockCipher.GetBlockSize() < 16)
                         {
                             throw new ArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
                         }
-                        blockCipher = new SicBlockCipher(blockCipher);
+                        blockCipherMode = new SicBlockCipher(blockCipher);
                         break;
                     default:
                         throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
@@ -713,22 +714,27 @@ namespace Org.BouncyCastle.Security
 
             if (blockCipher != null)
             {
+                if (blockCipherMode == null)
+                {
+                    blockCipherMode = EcbBlockCipher.GetBlockCipherMode(blockCipher);
+                }
+
                 if (cts)
                 {
-                    return new CtsBlockCipher(blockCipher);
+                    return new CtsBlockCipher(blockCipherMode);
                 }
 
                 if (padding != null)
                 {
-                    return new PaddedBufferedBlockCipher(blockCipher, padding);
+                    return new PaddedBufferedBlockCipher(blockCipherMode, padding);
                 }
 
-                if (!padded || blockCipher.IsPartialBlockOkay)
+                if (!padded || blockCipherMode.IsPartialBlockOkay)
                 {
-                    return new BufferedBlockCipher(blockCipher);
+                    return new BufferedBlockCipher(blockCipherMode);
                 }
 
-                return new PaddedBufferedBlockCipher(blockCipher);
+                return new PaddedBufferedBlockCipher(blockCipherMode);
             }
 
             if (asymBlockCipher != null)
diff --git a/crypto/test/src/crypto/io/test/CipherStreamTest.cs b/crypto/test/src/crypto/io/test/CipherStreamTest.cs
index 799b44521..9dc1f4c2a 100644
--- a/crypto/test/src/crypto/io/test/CipherStreamTest.cs
+++ b/crypto/test/src/crypto/io/test/CipherStreamTest.cs
@@ -144,8 +144,8 @@ namespace Org.BouncyCastle.Crypto.IO.Tests
 
 			IBlockCipher blockCipher = AesUtilities.CreateEngine();
 			int bits = 8 * blockCipher.GetBlockSize(); // TODO Is this right?
-			blockCipher = new CfbBlockCipher(blockCipher, bits);
-			IBufferedCipher cipher = new BufferedBlockCipher(blockCipher);
+			IBlockCipherMode blockCipherMode = new CfbBlockCipher(blockCipher, bits);
+			IBufferedCipher cipher = new BufferedBlockCipher(blockCipherMode);
 
 //			SecureRandom random = new SecureRandom();
 			byte[] keyBytes = new byte[32];
diff --git a/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs b/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
index 3e90c5752..047405c77 100644
--- a/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
+++ b/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
@@ -497,11 +497,6 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 get { return cipher.AlgorithmName; }
             }
 
-            public bool IsPartialBlockOkay
-            {
-                get { return false; }
-            }
-
             public int GetBlockSize()
             {
                 return cipher.GetBlockSize();
@@ -520,11 +515,6 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 return cipher.ProcessBlock(input, output);
             }
 #endif
-
-            public void Reset()
-            {
-                cipher.Reset();
-            }
         }
     }
 }
diff --git a/crypto/test/src/crypto/test/NullTest.cs b/crypto/test/src/crypto/test/NullTest.cs
deleted file mode 100644
index 0bc9d28cf..000000000
--- a/crypto/test/src/crypto/test/NullTest.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-
-using NUnit.Framework;
-
-using Org.BouncyCastle.Crypto.Engines;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Utilities.Encoders;
-using Org.BouncyCastle.Utilities.Test;
-
-namespace Org.BouncyCastle.Crypto.Tests
-{
-	[TestFixture]
-	public class NullTest
-		: CipherTest
-	{
-		static SimpleTest[]  tests =
-		{
-			new BlockCipherVectorTest(0, new NullEngine(),
-					new KeyParameter(Hex.Decode("00")), "00", "00")
-		};
-
-		public NullTest()
-			: base(tests, new NullEngine(), new KeyParameter(new byte[2]))
-		{
-		}
-
-		public override string Name
-		{
-			get { return "Null"; }
-		}
-
-		public override void PerformTest()
-		{
-			base.PerformTest();
-
-			IBlockCipher engine = new NullEngine();
-
-			engine.Init(true, null);
-
-			byte[] buf = new byte[1];
-
-			engine.ProcessBlock(buf, 0, buf, 0);
-
-			if (buf[0] != 0)
-			{
-				Fail("NullCipher changed data!");
-			}
-
-			byte[] shortBuf = new byte[0];
-
-			try
-			{
-				engine.ProcessBlock(shortBuf, 0, buf, 0);
-
-				Fail("failed short input check");
-			}
-			catch (DataLengthException)
-			{
-				// expected
-			}
-
-			try
-			{
-				engine.ProcessBlock(buf, 0, shortBuf, 0);
-
-				Fail("failed short output check");
-			}
-			catch (DataLengthException)
-			{
-				// expected
-			}
-		}
-
-		[Test]
-		public void TestFunction()
-		{
-			string resultText = Perform().ToString();
-
-			Assert.AreEqual(Name + ": Okay", resultText);
-		}
-	}
-}