summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorTim Whittington <bc@whittington.net.nz>2013-10-12 19:46:25 +1300
committerTim Whittington <bc@whittington.net.nz>2013-10-20 21:32:33 +1300
commitf64b37993aaec3f2baaab236af58c295b06c9f92 (patch)
treeced19bc4695aafe6112dbada80601d5cf8def51f /crypto
parentPort SkeinDigest and SkeinMac from bc-java. (diff)
downloadBouncyCastle.NET-ed25519-f64b37993aaec3f2baaab236af58c295b06c9f92.tar.xz
Port Memoable digest support from bc-java.
Diffstat (limited to 'crypto')
-rw-r--r--crypto/crypto.mdp2
-rw-r--r--crypto/src/crypto/digests/GOST3411Digest.cs49
-rw-r--r--crypto/src/crypto/digests/GeneralDigest.cs15
-rw-r--r--crypto/src/crypto/digests/LongDigest.cs15
-rw-r--r--crypto/src/crypto/digests/MD2Digest.cs26
-rw-r--r--crypto/src/crypto/digests/MD4Digest.cs23
-rw-r--r--crypto/src/crypto/digests/MD5Digest.cs24
-rw-r--r--crypto/src/crypto/digests/RipeMD128Digest.cs26
-rw-r--r--crypto/src/crypto/digests/RipeMD160Digest.cs22
-rw-r--r--crypto/src/crypto/digests/RipeMD256Digest.cs21
-rw-r--r--crypto/src/crypto/digests/RipeMD320Digest.cs21
-rw-r--r--crypto/src/crypto/digests/SHA3Digest.cs21
-rw-r--r--crypto/src/crypto/digests/Sha1Digest.cs21
-rw-r--r--crypto/src/crypto/digests/Sha224Digest.cs21
-rw-r--r--crypto/src/crypto/digests/Sha256Digest.cs21
-rw-r--r--crypto/src/crypto/digests/Sha384Digest.cs14
-rw-r--r--crypto/src/crypto/digests/Sha512Digest.cs14
-rw-r--r--crypto/src/crypto/digests/Sha512tDigest.cs39
-rw-r--r--crypto/src/crypto/digests/SkeinDigest.cs22
-rw-r--r--crypto/src/crypto/digests/SkeinEngine.cs30
-rw-r--r--crypto/src/crypto/digests/TigerDigest.cs41
-rw-r--r--crypto/src/crypto/digests/WhirlpoolDigest.cs44
-rw-r--r--crypto/src/util/IMemoable.cs29
-rw-r--r--crypto/src/util/MemoableResetException.cs27
-rw-r--r--crypto/test/src/crypto/test/DigestTest.cs44
25 files changed, 536 insertions, 96 deletions
diff --git a/crypto/crypto.mdp b/crypto/crypto.mdp
index f3589858f..e79b81b17 100644
--- a/crypto/crypto.mdp
+++ b/crypto/crypto.mdp
@@ -2308,6 +2308,8 @@
     <File subtype="Code" buildaction="Compile" name="test/src/crypto/test/SkeinDigestTest.cs" />
     <File subtype="Code" buildaction="Compile" name="test/src/crypto/test/SkeinMacTest.cs" />
     <File subtype="Code" buildaction="Compile" name="src/crypto/macs/SkeinMac.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/util/IMemoable.cs" />
+    <File subtype="Code" buildaction="Compile" name="src/util/MemoableResetException.cs" />
   </Contents>
   <References>
     <ProjectReference type="Assembly" localcopy="True" refto="test/lib/nunit.core.dll" />
diff --git a/crypto/src/crypto/digests/GOST3411Digest.cs b/crypto/src/crypto/digests/GOST3411Digest.cs
index 9f0bec9e6..218adf68c 100644
--- a/crypto/src/crypto/digests/GOST3411Digest.cs
+++ b/crypto/src/crypto/digests/GOST3411Digest.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 	* implementation of GOST R 34.11-94
 	*/
 	public class Gost3411Digest
-		: IDigest
+		: IDigest, IMemoable
 	{
 		private const int DIGEST_LENGTH = 32;
 
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 		private ulong	byteCount;
 
 		private readonly IBlockCipher cipher = new Gost28147Engine();
-		private readonly byte[] sBox;
+		private byte[] sBox;
 
 		private static byte[][] MakeC()
 		{
@@ -65,22 +65,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 		 */
 		public Gost3411Digest(Gost3411Digest t)
 		{
-			this.sBox = t.sBox;
-			cipher.Init(true, new ParametersWithSBox(null, sBox));
-
-			Reset();
-
-			Array.Copy(t.H, 0, this.H, 0, t.H.Length);
-			Array.Copy(t.L, 0, this.L, 0, t.L.Length);
-			Array.Copy(t.M, 0, this.M, 0, t.M.Length);
-			Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
-			Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
-			Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
-			Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
-			Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
-
-			this.xBufOff = t.xBufOff;
-			this.byteCount = t.byteCount;
+			Reset(t);
 		}
 
 		public string AlgorithmName
@@ -339,5 +324,33 @@ namespace Org.BouncyCastle.Crypto.Digests
 		{
 			return 32;
 		}
+
+		public IMemoable Copy()
+		{
+			return new Gost3411Digest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			Gost3411Digest t = (Gost3411Digest)other;
+
+			this.sBox = t.sBox;
+			cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+			Reset();
+
+			Array.Copy(t.H, 0, this.H, 0, t.H.Length);
+			Array.Copy(t.L, 0, this.L, 0, t.L.Length);
+			Array.Copy(t.M, 0, this.M, 0, t.M.Length);
+			Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
+			Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
+			Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
+			Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
+			Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
+
+			this.xBufOff = t.xBufOff;
+			this.byteCount = t.byteCount;
+		}
 	}
+
 }
diff --git a/crypto/src/crypto/digests/GeneralDigest.cs b/crypto/src/crypto/digests/GeneralDigest.cs
index 77c17ed58..54a09ae05 100644
--- a/crypto/src/crypto/digests/GeneralDigest.cs
+++ b/crypto/src/crypto/digests/GeneralDigest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -7,7 +9,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     * "Handbook of Applied Cryptography", pages 344 - 347.
     */
     public abstract class GeneralDigest
-		: IDigest
+		: IDigest, IMemoable
     {
         private const int BYTE_LENGTH = 64;
 
@@ -22,8 +24,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         }
 
         internal GeneralDigest(GeneralDigest t)
-        {
-            xBuf = new byte[t.xBuf.Length];
+		{
+			xBuf = new byte[t.xBuf.Length];
+			CopyIn(t);
+		}
+
+		protected void CopyIn(GeneralDigest t)
+		{
             Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
 
             xBufOff = t.xBufOff;
@@ -114,5 +121,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         public abstract string AlgorithmName { get; }
 		public abstract int GetDigestSize();
         public abstract int DoFinal(byte[] output, int outOff);
+		public abstract IMemoable Copy();
+		public abstract void Reset(IMemoable t);
     }
 }
diff --git a/crypto/src/crypto/digests/LongDigest.cs b/crypto/src/crypto/digests/LongDigest.cs
index 702753b2b..9ee9bcd57 100644
--- a/crypto/src/crypto/digests/LongDigest.cs
+++ b/crypto/src/crypto/digests/LongDigest.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     * Base class for SHA-384 and SHA-512.
     */
     public abstract class LongDigest
-		: IDigest
+		: IDigest, IMemoable
     {
         private int     MyByteLength = 128;
 
@@ -41,8 +42,14 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         internal LongDigest(
 			LongDigest t)
-        {
-            xBuf = new byte[t.xBuf.Length];
+		{
+			xBuf = new byte[t.xBuf.Length];
+
+			CopyIn(t);
+		}
+
+		protected void CopyIn(LongDigest t)
+		{
             Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
 
             xBufOff = t.xBufOff;
@@ -342,5 +349,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 		public abstract string AlgorithmName { get; }
 		public abstract int GetDigestSize();
         public abstract int DoFinal(byte[] output, int outOff);
+		public abstract IMemoable Copy();
+		public abstract void Reset(IMemoable t);
     }
 }
diff --git a/crypto/src/crypto/digests/MD2Digest.cs b/crypto/src/crypto/digests/MD2Digest.cs
index 78c696f33..6d90f3f9d 100644
--- a/crypto/src/crypto/digests/MD2Digest.cs
+++ b/crypto/src/crypto/digests/MD2Digest.cs
@@ -1,5 +1,7 @@
 using System;
+
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
     */
     public class MD2Digest
-		: IDigest
+		: IDigest, IMemoable
     {
         private const int DigestLength = 16;
         private const int BYTE_LENGTH = 16;
@@ -32,8 +34,14 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             Reset();
         }
+
         public MD2Digest(MD2Digest t)
-        {
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(MD2Digest t)
+		{
             Array.Copy(t.X, 0, X, 0, t.X.Length);
             xOff = t.xOff;
             Array.Copy(t.M, 0, M, 0, t.M.Length);
@@ -41,6 +49,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             Array.Copy(t.C, 0, C, 0, t.C.Length);
             COff = t.COff;
         }
+
         /**
         * return the algorithm name
         *
@@ -242,6 +251,19 @@ namespace Org.BouncyCastle.Crypto.Digests
         (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,
         (byte)159,(byte)17,(byte)131,(byte)20
         };
+
+		public IMemoable Copy()
+		{
+			return new MD2Digest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			MD2Digest d = (MD2Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/MD4Digest.cs b/crypto/src/crypto/digests/MD4Digest.cs
index bc4eae0fd..8743f7dad 100644
--- a/crypto/src/crypto/digests/MD4Digest.cs
+++ b/crypto/src/crypto/digests/MD4Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -32,7 +34,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         * message digest.
         */
         public MD4Digest(MD4Digest t) : base(t)
-        {
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(MD4Digest t)
+		{
+			base.CopyIn(t);
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -266,6 +274,19 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+
+		public override IMemoable Copy()
+		{
+			return new MD4Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			MD4Digest d = (MD4Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/MD5Digest.cs b/crypto/src/crypto/digests/MD5Digest.cs
index 2116d64f0..c60ac92a3 100644
--- a/crypto/src/crypto/digests/MD5Digest.cs
+++ b/crypto/src/crypto/digests/MD5Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -28,7 +29,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public MD5Digest(MD5Digest t)
             : base(t)
-        {
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(MD5Digest t)
+		{
+			base.CopyIn(t);
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -287,7 +294,20 @@ namespace Org.BouncyCastle.Crypto.Digests
 
             xOff = 0;
         }
-    }
+
+		public override IMemoable Copy()
+		{
+			return new MD5Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			MD5Digest d = (MD5Digest)other;
+
+			CopyIn(d);
+		}
+
+	}
 
 }
 
diff --git a/crypto/src/crypto/digests/RipeMD128Digest.cs b/crypto/src/crypto/digests/RipeMD128Digest.cs
index 8977583a4..e8a0331ca 100644
--- a/crypto/src/crypto/digests/RipeMD128Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD128Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -28,8 +30,15 @@ namespace Org.BouncyCastle.Crypto.Digests
         * message digest.
         */
         public RipeMD128Digest(RipeMD128Digest t) : base(t)
-        {
-            H0 = t.H0;
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD128Digest t)
+		{
+			base.CopyIn(t);
+
+			H0 = t.H0;
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -457,6 +466,19 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD128Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD128Digest d = (RipeMD128Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/RipeMD160Digest.cs b/crypto/src/crypto/digests/RipeMD160Digest.cs
index 8ce52ae58..af4aa44bb 100644
--- a/crypto/src/crypto/digests/RipeMD160Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD160Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -30,6 +32,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public RipeMD160Digest(RipeMD160Digest t) : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD160Digest t)
+		{
+			base.CopyIn(t);
+
             H0 = t.H0;
             H1 = t.H1;
             H2 = t.H2;
@@ -418,6 +427,19 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD160Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD160Digest d = (RipeMD160Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/RipeMD256Digest.cs b/crypto/src/crypto/digests/RipeMD256Digest.cs
index 950e94f80..306275767 100644
--- a/crypto/src/crypto/digests/RipeMD256Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD256Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /// <remarks>
@@ -37,6 +39,12 @@ namespace Org.BouncyCastle.Crypto.Digests
         /// </summary>
         public RipeMD256Digest(RipeMD256Digest t):base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD256Digest t)
+		{
+			base.CopyIn(t);
 
             H0 = t.H0;
             H1 = t.H1;
@@ -405,5 +413,18 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD256Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD256Digest d = (RipeMD256Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/RipeMD320Digest.cs b/crypto/src/crypto/digests/RipeMD320Digest.cs
index 25c74baef..767d74dba 100644
--- a/crypto/src/crypto/digests/RipeMD320Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD320Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
 	/// <remarks>
@@ -38,6 +40,12 @@ namespace Org.BouncyCastle.Crypto.Digests
         public RipeMD320Digest(RipeMD320Digest t)
 			: base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD320Digest t)
+		{
+			base.CopyIn(t);
 
             H0 = t.H0;
             H1 = t.H1;
@@ -434,5 +442,18 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD320Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD320Digest d = (RipeMD320Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
index a115495f4..2c6837b3c 100644
--- a/crypto/src/crypto/digests/SHA3Digest.cs
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     /// Following the naming conventions used in the C source code to enable easy review of the implementation.
     /// </remarks>
     public class Sha3Digest
-        : IDigest
+        : IDigest, IMemoable
     {
         private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
 
@@ -103,6 +103,11 @@ namespace Org.BouncyCastle.Crypto.Digests
 
         public Sha3Digest(Sha3Digest source)
         {
+			CopyIn(source);
+		}
+
+		private void CopyIn(Sha3Digest source)
+		{
             Array.Copy(source.state, 0, this.state, 0, source.state.Length);
             Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
             this.rate = source.rate;
@@ -537,5 +542,19 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             Array.Copy(byteState, 0, data, 0, laneCount * 8);
         }
+
+		public IMemoable Copy()
+		{
+			return new Sha3Digest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			Sha3Digest d = (Sha3Digest)other;
+
+			CopyIn(d);
+		}
+
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha1Digest.cs b/crypto/src/crypto/digests/Sha1Digest.cs
index e72b84f94..60ec651d5 100644
--- a/crypto/src/crypto/digests/Sha1Digest.cs
+++ b/crypto/src/crypto/digests/Sha1Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -33,6 +34,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         public Sha1Digest(Sha1Digest t)
             : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(Sha1Digest t)
+		{
+			base.CopyIn(t);
+
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -259,5 +267,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             xOff = 0;
             Array.Clear(X, 0, 16);
         }
+		
+		public override IMemoable Copy()
+		{
+			return new Sha1Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha1Digest d = (Sha1Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha224Digest.cs b/crypto/src/crypto/digests/Sha224Digest.cs
index 66ecd4ecd..b4e853745 100644
--- a/crypto/src/crypto/digests/Sha224Digest.cs
+++ b/crypto/src/crypto/digests/Sha224Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -41,6 +42,13 @@ namespace Org.BouncyCastle.Crypto.Digests
 			 Sha224Digest t)
 			 : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(Sha224Digest t)
+		{
+			base.CopyIn(t);
+
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -264,5 +272,18 @@ namespace Org.BouncyCastle.Crypto.Digests
 			0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
         };
+		
+		public override IMemoable Copy()
+		{
+			return new Sha224Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha224Digest d = (Sha224Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha256Digest.cs b/crypto/src/crypto/digests/Sha256Digest.cs
index 1c00ab71f..98e10a34d 100644
--- a/crypto/src/crypto/digests/Sha256Digest.cs
+++ b/crypto/src/crypto/digests/Sha256Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -36,6 +37,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public Sha256Digest(Sha256Digest t) : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(Sha256Digest t)
+		{
+			base.CopyIn(t);
+
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -305,5 +313,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
             0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
         };
+		
+		public override IMemoable Copy()
+		{
+			return new Sha256Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha256Digest d = (Sha256Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha384Digest.cs b/crypto/src/crypto/digests/Sha384Digest.cs
index f1372d0a9..e6c9a9aa9 100644
--- a/crypto/src/crypto/digests/Sha384Digest.cs
+++ b/crypto/src/crypto/digests/Sha384Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -83,5 +84,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             H7 = 0xdb0c2e0d64f98fa7;
             H8 = 0x47b5481dbefa4fa4;
         }
+		
+		public override IMemoable Copy()
+		{
+			return new Sha384Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha384Digest d = (Sha384Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha512Digest.cs b/crypto/src/crypto/digests/Sha512Digest.cs
index b38ff8ee7..2a0964fd3 100644
--- a/crypto/src/crypto/digests/Sha512Digest.cs
+++ b/crypto/src/crypto/digests/Sha512Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -86,5 +87,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             H7 = 0x1f83d9abfb41bd6b;
             H8 = 0x5be0cd19137e2179;
         }
+		
+		public override IMemoable Copy()
+		{
+			return new Sha512Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha512Digest d = (Sha512Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha512tDigest.cs b/crypto/src/crypto/digests/Sha512tDigest.cs
index 7580d6267..2caefa763 100644
--- a/crypto/src/crypto/digests/Sha512tDigest.cs
+++ b/crypto/src/crypto/digests/Sha512tDigest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -44,14 +45,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             this.digestLength = t.digestLength;
 
-            this.H1t = t.H1t;
-            this.H2t = t.H2t;
-            this.H3t = t.H3t;
-            this.H4t = t.H4t;
-            this.H5t = t.H5t;
-            this.H6t = t.H6t;
-            this.H7t = t.H7t;
-            this.H8t = t.H8t;
+			Reset(t);
         }
 
         public override string AlgorithmName
@@ -175,5 +169,32 @@ namespace Org.BouncyCastle.Crypto.Digests
                 bs[off + num] = (byte)(n >> shift);
             }
         }
-    }
+
+		public override IMemoable Copy()
+		{
+			return new Sha512tDigest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha512tDigest t = (Sha512tDigest)other;
+
+			if (this.digestLength != t.digestLength)
+			{
+				throw new MemoableResetException("digestLength inappropriate in other");
+			}
+
+			base.CopyIn(t);
+
+			this.H1t = t.H1t;
+			this.H2t = t.H2t;
+			this.H3t = t.H3t;
+			this.H4t = t.H4t;
+			this.H5t = t.H5t;
+			this.H6t = t.H6t;
+			this.H7t = t.H7t;
+			this.H8t = t.H8t;
+		}
+
+	}
 }
diff --git a/crypto/src/crypto/digests/SkeinDigest.cs b/crypto/src/crypto/digests/SkeinDigest.cs
index b24fb3995..f826ce503 100644
--- a/crypto/src/crypto/digests/SkeinDigest.cs
+++ b/crypto/src/crypto/digests/SkeinDigest.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 	/// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
 	/// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
 	public class SkeinDigest
-		: IDigest//, IMemoable
+		: IDigest, IMemoable
 	{
 		/// <summary>
 		/// 256 bit block size - Skein-256
@@ -57,16 +57,16 @@ namespace Org.BouncyCastle.Crypto.Digests
 			this.engine = new SkeinEngine(digest.engine);
 		}
 
-		//	    public void Reset(IMemoable other)
-		//	    {
-		//	        SkeinDigest d = (SkeinDigest)other;
-		//	        engine.reset(d.engine);
-		//	    }
-		//
-		//	    public IMemoable copy()
-		//	    {
-		//	        return new SkeinDigest(this);
-		//	    }
+		public void Reset(IMemoable other)
+		{
+			SkeinDigest d = (SkeinDigest)other;
+			engine.Reset(d.engine);
+		}
+
+		public IMemoable Copy()
+		{
+			return new SkeinDigest(this);
+		}
 
 		public String AlgorithmName
 		{
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
index 94529bcf6..49ec51304 100644
--- a/crypto/src/crypto/digests/SkeinEngine.cs
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 	/// </remarks>
 	/// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
 	public class SkeinEngine
-		//	    : IMemoable
+		: IMemoable
 	{
 		/// <summary>
 		/// 256 bit block size - Skein-256
@@ -565,20 +565,20 @@ namespace Org.BouncyCastle.Crypto.Digests
 			return existing;
 		}
 
-		//	    public IMemoable Copy()
-		//	    {
-		//	        return new SkeinEngine(this);
-		//	    }
-		//
-		//	    public void Reset(IMemoable other)
-		//	    {
-		//	        SkeinEngine s = (SkeinEngine)other;
-		//	        if ((getBlockSize() != s.getBlockSize()) || (outputSizeBytes != s.outputSizeBytes))
-		//	        {
-		//	            throw new IllegalArgumentException("Incompatible parameters in provided SkeinEngine.");
-		//	        }
-		//	        copyIn(s);
-		//	    }
+		public IMemoable Copy()
+		{
+			return new SkeinEngine(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			SkeinEngine s = (SkeinEngine)other;
+			if ((BlockSize != s.BlockSize) || (outputSizeBytes != s.outputSizeBytes))
+			{
+				throw new MemoableResetException("Incompatible parameters in provided SkeinEngine.");
+			}
+			CopyIn(s);
+		}
 
 		public int OutputSize
 		{
diff --git a/crypto/src/crypto/digests/TigerDigest.cs b/crypto/src/crypto/digests/TigerDigest.cs
index b8c9a7664..059232de0 100644
--- a/crypto/src/crypto/digests/TigerDigest.cs
+++ b/crypto/src/crypto/digests/TigerDigest.cs
@@ -1,5 +1,7 @@
 using System;
+
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     *  http://www.cs.technion.ac.il/~biham/Reports/Tiger</a>
     */
     public class TigerDigest
-		: IDigest
+		: IDigest, IMemoable
     {
         private const int MyByteLength = 64;
 
@@ -571,17 +573,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public TigerDigest(TigerDigest t)
         {
-            a = t.a;
-            b = t.b;
-            c = t.c;
-
-            Array.Copy(t.x, 0, x, 0, t.x.Length);
-            xOff = t.xOff;
-
-            Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
-            bOff = t.bOff;
-
-            byteCount = t.byteCount;
+			Reset(t);
         }
 
 		public string AlgorithmName
@@ -864,5 +856,28 @@ namespace Org.BouncyCastle.Crypto.Digests
 
             byteCount = 0;
         }
-    }
+
+		public IMemoable Copy()
+		{
+			return new TigerDigest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			TigerDigest t = (TigerDigest)other;
+
+			a = t.a;
+			b = t.b;
+			c = t.c;
+
+			Array.Copy(t.x, 0, x, 0, t.x.Length);
+			xOff = t.xOff;
+
+			Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
+			bOff = t.bOff;
+
+			byteCount = t.byteCount;
+		}    
+
+	}
 }
diff --git a/crypto/src/crypto/digests/WhirlpoolDigest.cs b/crypto/src/crypto/digests/WhirlpoolDigest.cs
index df83f4508..55b71205e 100644
--- a/crypto/src/crypto/digests/WhirlpoolDigest.cs
+++ b/crypto/src/crypto/digests/WhirlpoolDigest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +10,8 @@ namespace Org.BouncyCastle.Crypto.Digests
 	* and Rijmen.
 	*
 	*/
-	public sealed class WhirlpoolDigest : IDigest
+	public sealed class WhirlpoolDigest
+		: IDigest, IMemoable
 	{
 		private const int BYTE_LENGTH = 64;
 
@@ -149,19 +151,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 			*/
 		public WhirlpoolDigest(WhirlpoolDigest originalDigest)
 		{
-			Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length);
-
-			Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length);
-
-			this._bufferPos = originalDigest._bufferPos;
-			Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length);
-
-			// -- internal hash state --
-			Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length);
-			Array.Copy(originalDigest._K, 0, _K, 0, _K.Length);
-			Array.Copy(originalDigest._L, 0, _L, 0, _L.Length);
-			Array.Copy(originalDigest._block, 0, _block, 0, _block.Length);
-			Array.Copy(originalDigest._state, 0, _state, 0, _state.Length);
+			Reset(originalDigest);
 		}
 
 		public string AlgorithmName
@@ -393,5 +383,31 @@ namespace Org.BouncyCastle.Crypto.Digests
 		{
 			return BYTE_LENGTH;
 		}
+
+		public IMemoable Copy()
+		{
+			return new WhirlpoolDigest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			WhirlpoolDigest originalDigest = (WhirlpoolDigest)other;
+
+			Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length);
+
+			Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length);
+
+			this._bufferPos = originalDigest._bufferPos;
+			Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length);
+
+			// -- internal hash state --
+			Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length);
+			Array.Copy(originalDigest._K, 0, _K, 0, _K.Length);
+			Array.Copy(originalDigest._L, 0, _L, 0, _L.Length);
+			Array.Copy(originalDigest._block, 0, _block, 0, _block.Length);
+			Array.Copy(originalDigest._state, 0, _state, 0, _state.Length);
+		}
+
+
 	}
 }
diff --git a/crypto/src/util/IMemoable.cs b/crypto/src/util/IMemoable.cs
new file mode 100644
index 000000000..befc10fbf
--- /dev/null
+++ b/crypto/src/util/IMemoable.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+	public interface IMemoable
+	{
+		/// <summary>
+		/// Produce a copy of this object with its configuration and in its current state.
+		/// </summary>
+		/// <remarks>
+		/// The returned object may be used simply to store the state, or may be used as a similar object
+		/// starting from the copied state.
+		/// </remarks>
+		IMemoable Copy();
+
+		/// <summary>
+		/// Restore a copied object state into this object.
+		/// </summary>
+		/// <remarks>
+		/// Implementations of this method <em>should</em> try to avoid or minimise memory allocation to perform the reset.
+		/// </remarks>
+		/// <param name="other">an object originally {@link #copy() copied} from an object of the same type as this instance.</param>
+		/// <exception cref="ClassCastException">if the provided object is not of the correct type.</exception>
+		/// <exception cref="MemoableResetException">if the <b>other</b> parameter is in some other way invalid.</exception>
+		void Reset(IMemoable other);
+	}
+
+}
+
diff --git a/crypto/src/util/MemoableResetException.cs b/crypto/src/util/MemoableResetException.cs
new file mode 100644
index 000000000..d9542dab2
--- /dev/null
+++ b/crypto/src/util/MemoableResetException.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+	/**
+	 * Exception to be thrown on a failure to reset an object implementing Memoable.
+	 * <p>
+	 * The exception extends ClassCastException to enable users to have a single handling case,
+	 * only introducing specific handling of this one if required.
+	 * </p>
+	 */
+	public class MemoableResetException
+		: InvalidCastException
+	{
+		/**
+	     * Basic Constructor.
+	     *
+	     * @param msg message to be associated with this exception.
+	     */
+		public MemoableResetException(string msg)
+			: base(msg)
+		{
+		}
+	}
+
+}
+
diff --git a/crypto/test/src/crypto/test/DigestTest.cs b/crypto/test/src/crypto/test/DigestTest.cs
index 533e87181..930979643 100644
--- a/crypto/test/src/crypto/test/DigestTest.cs
+++ b/crypto/test/src/crypto/test/DigestTest.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Crypto;
 
+using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.Utilities.Test;
 
@@ -35,9 +36,9 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 			for (int i = 0; i < input.Length - 1; i++)
 			{
-				byte[] m = toByteArray(input[i]);
+				byte[] msg = toByteArray(input[i]);
 
-				vectorTest(digest, i, resBuf, m, Hex.Decode(results[i]));
+				vectorTest(digest, i, resBuf, msg, Hex.Decode(results[i]));
 			}
 
 			byte[] lastV = toByteArray(input[input.Length - 1]);
@@ -68,6 +69,45 @@ namespace Org.BouncyCastle.Crypto.Tests
 			{
 				Fail("failing second clone vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
 			}
+
+			//
+			// memo test
+			//
+			IMemoable m = (IMemoable)digest;
+
+			digest.BlockUpdate(lastV, 0, lastV.Length/2);
+
+			// copy the Digest
+			IMemoable copy1 = m.Copy();
+			IMemoable copy2 = copy1.Copy();
+
+			digest.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing memo vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+
+			m.Reset(copy1);
+
+			digest.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing memo reset vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+
+			IDigest md = (IDigest)copy2;
+
+			md.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			md.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing memo copy vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
 		}
 
 		private byte[] toByteArray(