summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2017-07-06 14:32:08 -0400
committerOren Novotny <oren@novotny.org>2017-07-06 14:32:08 -0400
commit0f1f4a1d1f79948db22f92b22e30143fb346074a (patch)
tree3dbb7695f4d940894c2f8398a0ddd1dc54182303 /crypto
parentRemove unused nuspec (diff)
parentrefactored out key size (diff)
downloadBouncyCastle.NET-ed25519-0f1f4a1d1f79948db22f92b22e30143fb346074a.tar.xz
Merge branch 'master' into netstandard
Diffstat (limited to 'crypto')
-rw-r--r--crypto/Contributors.html5
-rw-r--r--crypto/crypto.csproj40
-rw-r--r--crypto/src/asn1/Asn1Object.cs12
-rw-r--r--crypto/src/asn1/crmf/CertReqMsg.cs7
-rw-r--r--crypto/src/asn1/gm/GMNamedCurves.cs157
-rw-r--r--crypto/src/asn1/gm/GMObjectIdentifiers.cs85
-rw-r--r--crypto/src/asn1/gnu/GNUObjectIdentifiers.cs5
-rw-r--r--crypto/src/asn1/pkcs/CertificationRequest.cs3
-rw-r--r--crypto/src/asn1/pkcs/CertificationRequestInfo.cs43
-rw-r--r--crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs52
-rw-r--r--crypto/src/asn1/x509/KeyPurposeId.cs2
-rw-r--r--crypto/src/asn1/x509/X509Extensions.cs5
-rw-r--r--crypto/src/asn1/x9/ECNamedCurveTable.cs31
-rw-r--r--crypto/src/bcpg/ArmoredOutputStream.cs49
-rw-r--r--crypto/src/crypto/agreement/DHAgreement.cs18
-rw-r--r--crypto/src/crypto/agreement/DHBasicAgreement.cs14
-rw-r--r--crypto/src/crypto/agreement/DHStandardGroups.cs15
-rw-r--r--crypto/src/crypto/digests/DSTU7564Digest.cs562
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs25
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs62
-rw-r--r--crypto/src/crypto/encodings/Pkcs1Encoding.cs132
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs19
-rw-r--r--crypto/src/crypto/engines/AesFastEngine.cs5
-rw-r--r--crypto/src/crypto/engines/ChaCha7539Engine.cs2
-rw-r--r--crypto/src/crypto/engines/Dstu7624Engine.cs855
-rw-r--r--crypto/src/crypto/engines/Dstu7624WrapEngine.cs263
-rw-r--r--crypto/src/crypto/macs/DSTU7564Mac.cs156
-rw-r--r--crypto/src/crypto/macs/DSTU7624Mac.cs160
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs70
-rw-r--r--crypto/src/crypto/modes/GOFBBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/KCtrBlockCipher.cs235
-rw-r--r--crypto/src/crypto/modes/OCBBlockCipher.cs4
-rw-r--r--crypto/src/crypto/parameters/DHPublicKeyParameters.cs31
-rw-r--r--crypto/src/crypto/parameters/DsaPublicKeyParameters.cs18
-rw-r--r--crypto/src/crypto/parameters/ECPublicKeyParameters.cs21
-rw-r--r--crypto/src/crypto/parameters/RsaKeyParameters.cs24
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandom.cs15
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs5
-rw-r--r--crypto/src/crypto/signers/Iso9796d2Signer.cs6
-rw-r--r--crypto/src/crypto/tls/EncryptionAlgorithm.cs5
-rw-r--r--crypto/src/crypto/tls/ExtensionType.cs10
-rw-r--r--crypto/src/crypto/tls/RecordStream.cs36
-rw-r--r--crypto/src/crypto/tls/TlsDHKeyExchange.cs3
-rw-r--r--crypto/src/crypto/tls/TlsECDHKeyExchange.cs3
-rw-r--r--crypto/src/crypto/tls/TlsException.cs14
-rw-r--r--crypto/src/crypto/tls/TlsFatalAlert.cs3
-rw-r--r--crypto/src/crypto/tls/TlsFatalAlertReceived.cs21
-rw-r--r--crypto/src/crypto/tls/TlsNoCloseNotifyException.cs4
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs302
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs35
-rw-r--r--crypto/src/crypto/util/Pack.cs9
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs77
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1Field.cs307
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs211
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1Point.cs279
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Field.cs12
-rw-r--r--crypto/src/openpgp/PgpUtilities.cs81
-rw-r--r--crypto/src/security/CipherUtilities.cs6
-rw-r--r--crypto/src/security/MacUtilities.cs2
-rw-r--r--crypto/src/security/WrapperUtilities.cs2
-rw-r--r--crypto/test/src/asn1/test/MiscTest.cs126
-rw-r--r--crypto/test/src/crypto/examples/DESExample.cs7
-rw-r--r--crypto/test/src/crypto/prng/test/CtrDrbgTest.cs26
-rw-r--r--crypto/test/src/crypto/test/CMacTest.cs2
-rw-r--r--crypto/test/src/crypto/test/DSTU7564Test.cs645
-rw-r--r--crypto/test/src/crypto/test/DSTU7624Test.cs481
-rw-r--r--crypto/test/src/crypto/test/EAXTest.cs6
-rw-r--r--crypto/test/src/crypto/test/GCMTest.cs52
-rw-r--r--crypto/test/src/crypto/test/GMacTest.cs4
-rw-r--r--crypto/test/src/crypto/test/OAEPTest.cs43
-rw-r--r--crypto/test/src/crypto/test/Poly1305Test.cs8
-rw-r--r--crypto/test/src/crypto/test/RSABlindedTest.cs8
-rw-r--r--crypto/test/src/crypto/test/RsaTest.cs130
-rw-r--r--crypto/test/src/crypto/test/StreamCipherVectorTest.cs12
-rw-r--r--crypto/test/src/openpgp/test/PGPArmoredTest.cs17
-rw-r--r--crypto/test/src/security/test/SecureRandomTest.cs4
-rw-r--r--crypto/test/src/test/DHTest.cs93
-rw-r--r--crypto/test/src/test/NamedCurveTest.cs15
78 files changed, 5772 insertions, 547 deletions
diff --git a/crypto/Contributors.html b/crypto/Contributors.html
index 5211b193f..c43b5a864 100644
--- a/crypto/Contributors.html
+++ b/crypto/Contributors.html
@@ -139,7 +139,10 @@
                 <p>Oren Novotny (https://github.com/onovotny) - developed and maintained a fork supporting Portable Class Library, worked closely with us to integrate the changes back into the main project.</p>
             </li>
             <li>
-                <p>Nicolas Dorier (https://github.com/NicolasDorier) - patch to fix culture-dependent lookups in MacUtilities.
+                <p>Nicolas Dorier (https://github.com/NicolasDorier) - patch to fix culture-dependent lookups in MacUtilities.</p>
+            </li>
+            <li>
+		<p>Artem Storozhuk &lt;storojs72&#064gmail.com&gt; initial implementation of DSTU7564 (digest) and DSTU7624 (cipher) and their associated modes.</p>
             </li>
 		</ul>
 	</body>
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index fe6b5fa1c..026a2fe1b 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -1319,6 +1319,16 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\asn1\gm\GMNamedCurves.cs" 
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\gm\GMObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\asn1\gnu\GNUObjectIdentifiers.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -5169,6 +5179,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\TlsException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\TlsExtensionsUtilities.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -5179,6 +5194,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\TlsFatalAlertReceived.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\TlsHandshakeHash.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
@@ -5444,6 +5464,26 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\math\ec\custom\gm\SM2P256V1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\gm\SM2P256V1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\gm\SM2P256V1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\gm\SM2P256V1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\math\ec\custom\sec\SecP128R1Curve.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/Asn1Object.cs b/crypto/src/asn1/Asn1Object.cs
index a86fdbb4a..4faa81ac8 100644
--- a/crypto/src/asn1/Asn1Object.cs
+++ b/crypto/src/asn1/Asn1Object.cs
@@ -6,11 +6,13 @@ namespace Org.BouncyCastle.Asn1
     public abstract class Asn1Object
 		: Asn1Encodable
     {
-		/// <summary>Create a base ASN.1 object from a byte array.</summary>
-		/// <param name="data">The byte array to parse.</param>
-		/// <returns>The base ASN.1 object represented by the byte array.</returns>
-		/// <exception cref="IOException">If there is a problem parsing the data.</exception>
-		public static Asn1Object FromByteArray(
+        /// <summary>Create a base ASN.1 object from a byte array.</summary>
+        /// <param name="data">The byte array to parse.</param>
+        /// <returns>The base ASN.1 object represented by the byte array.</returns>
+        /// <exception cref="IOException">
+        /// If there is a problem parsing the data, or parsing an object did not exhaust the available data.
+        /// </exception>
+        public static Asn1Object FromByteArray(
 			byte[] data)
 		{
             try
diff --git a/crypto/src/asn1/crmf/CertReqMsg.cs b/crypto/src/asn1/crmf/CertReqMsg.cs
index 20fd4179a..03ce32d99 100644
--- a/crypto/src/asn1/crmf/CertReqMsg.cs
+++ b/crypto/src/asn1/crmf/CertReqMsg.cs
@@ -39,6 +39,13 @@ namespace Org.BouncyCastle.Asn1.Crmf
             return null;
         }
 
+        public static CertReqMsg GetInstance(
+            Asn1TaggedObject obj,
+            bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
         /**
          * Creates a new CertReqMsg.
          * @param certReq CertRequest
diff --git a/crypto/src/asn1/gm/GMNamedCurves.cs b/crypto/src/asn1/gm/GMNamedCurves.cs
new file mode 100644
index 000000000..e2ec6d854
--- /dev/null
+++ b/crypto/src/asn1/gm/GMNamedCurves.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.GM
+{
+    public sealed class GMNamedCurves
+    {
+        private GMNamedCurves()
+        {
+        }
+
+        private static ECCurve ConfigureCurve(ECCurve curve)
+        {
+            return curve;
+        }
+
+        private static BigInteger FromHex(string hex)
+        {
+            return new BigInteger(1, Hex.Decode(hex));
+        }
+
+        /*
+         * sm2p256v1
+         */
+        internal class SM2P256V1Holder
+            : X9ECParametersHolder
+        {
+            private SM2P256V1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new SM2P256V1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger p = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF");
+                BigInteger a = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC");
+                BigInteger b = FromHex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93");
+                byte[] S = null;
+                BigInteger n = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123");
+                BigInteger h = BigInteger.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+                    + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
+                    + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"));
+
+                return new X9ECParameters(curve, G, n, h, S);
+            }
+        }
+
+        /*
+         * wapip192v1
+         */
+        internal class WapiP192V1Holder
+            : X9ECParametersHolder
+        {
+            private WapiP192V1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new WapiP192V1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger p = FromHex("BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F");
+                BigInteger a = FromHex("BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985");
+                BigInteger b = FromHex("1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1");
+                byte[] S = null;
+                BigInteger n = FromHex("BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677");
+                BigInteger h = BigInteger.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+                    + "4AD5F7048DE709AD51236DE6" + "5E4D4B482C836DC6E4106640"
+                    + "02BB3A02D4AAADACAE24817A" + "4CA3A1B014B5270432DB27D2"));
+
+                return new X9ECParameters(curve, G, n, h, S);
+            }
+        }
+
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary curves = Platform.CreateHashtable();
+        private static readonly IDictionary names = Platform.CreateHashtable();
+
+        private static void DefineCurve(
+            string					name,
+            DerObjectIdentifier		oid,
+            X9ECParametersHolder	holder)
+        {
+            objIds.Add(Platform.ToUpperInvariant(name), oid);
+            names.Add(oid, name);
+            curves.Add(oid, holder);
+        }
+
+        static GMNamedCurves()
+        {
+            DefineCurve("wapip192v1", GMObjectIdentifiers.wapip192v1, WapiP192V1Holder.Instance);
+            DefineCurve("sm2p256v1", GMObjectIdentifiers.sm2p256v1, SM2P256V1Holder.Instance);
+        }
+
+        public static X9ECParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = GetOid(name);
+            return oid == null ? null : GetByOid(oid);
+        }
+
+        /**
+         * return the X9ECParameters object for the named curve represented by
+         * the passed in object identifier. Null if the curve isn't present.
+         *
+         * @param oid an object identifier representing a named curve, if present.
+         */
+        public static X9ECParameters GetByOid(
+            DerObjectIdentifier oid)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+         * return the object identifier signified by the passed in name. Null
+         * if there is no object identifier associated with name.
+         *
+         * @return the object identifier associated with name, if present.
+         */
+        public static DerObjectIdentifier GetOid(
+            string name)
+        {
+            return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)];
+        }
+
+        /**
+         * return the named curve name represented by the given object identifier.
+         */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string)names[oid];
+        }
+
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(names.Values); }
+        }
+    }
+}
diff --git a/crypto/src/asn1/gm/GMObjectIdentifiers.cs b/crypto/src/asn1/gm/GMObjectIdentifiers.cs
new file mode 100644
index 000000000..edb3a41c5
--- /dev/null
+++ b/crypto/src/asn1/gm/GMObjectIdentifiers.cs
@@ -0,0 +1,85 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.GM
+{
+	public abstract class GMObjectIdentifiers
+	{
+        public static readonly DerObjectIdentifier sm_scheme = new DerObjectIdentifier("1.2.156.10197.1");
+
+        public static readonly DerObjectIdentifier sm6_ecb = sm_scheme.Branch("101.1");
+        public static readonly DerObjectIdentifier sm6_cbc = sm_scheme.Branch("101.2");
+        public static readonly DerObjectIdentifier sm6_ofb128 = sm_scheme.Branch("101.3");
+        public static readonly DerObjectIdentifier sm6_cfb128 = sm_scheme.Branch("101.4");
+
+        public static readonly DerObjectIdentifier sm1_ecb = sm_scheme.Branch("102.1");
+        public static readonly DerObjectIdentifier sm1_cbc = sm_scheme.Branch("102.2");
+        public static readonly DerObjectIdentifier sm1_ofb128 = sm_scheme.Branch("102.3");
+        public static readonly DerObjectIdentifier sm1_cfb128 = sm_scheme.Branch("102.4");
+        public static readonly DerObjectIdentifier sm1_cfb1 = sm_scheme.Branch("102.5");
+        public static readonly DerObjectIdentifier sm1_cfb8 = sm_scheme.Branch("102.6");
+
+        public static readonly DerObjectIdentifier ssf33_ecb = sm_scheme.Branch("103.1");
+        public static readonly DerObjectIdentifier ssf33_cbc = sm_scheme.Branch("103.2");
+        public static readonly DerObjectIdentifier ssf33_ofb128 = sm_scheme.Branch("103.3");
+        public static readonly DerObjectIdentifier ssf33_cfb128 = sm_scheme.Branch("103.4");
+        public static readonly DerObjectIdentifier ssf33_cfb1 = sm_scheme.Branch("103.5");
+        public static readonly DerObjectIdentifier ssf33_cfb8 = sm_scheme.Branch("103.6");
+
+        public static readonly DerObjectIdentifier sms4_ecb = sm_scheme.Branch("104.1");
+        public static readonly DerObjectIdentifier sms4_cbc = sm_scheme.Branch("104.2");
+        public static readonly DerObjectIdentifier sms4_ofb128 = sm_scheme.Branch("104.3");
+        public static readonly DerObjectIdentifier sms4_cfb128 = sm_scheme.Branch("104.4");
+        public static readonly DerObjectIdentifier sms4_cfb1 = sm_scheme.Branch("104.5");
+        public static readonly DerObjectIdentifier sms4_cfb8 = sm_scheme.Branch("104.6");
+        public static readonly DerObjectIdentifier sms4_ctr = sm_scheme.Branch("104.7");
+        public static readonly DerObjectIdentifier sms4_gcm = sm_scheme.Branch("104.8");
+        public static readonly DerObjectIdentifier sms4_ccm = sm_scheme.Branch("104.9");
+        public static readonly DerObjectIdentifier sms4_xts = sm_scheme.Branch("104.10");
+        public static readonly DerObjectIdentifier sms4_wrap = sm_scheme.Branch("104.11");
+        public static readonly DerObjectIdentifier sms4_wrap_pad = sm_scheme.Branch("104.12");
+        public static readonly DerObjectIdentifier sms4_ocb = sm_scheme.Branch("104.100");
+
+        public static readonly DerObjectIdentifier sm5 = sm_scheme.Branch("201");
+
+        public static readonly DerObjectIdentifier sm2p256v1 = sm_scheme.Branch("301");
+        public static readonly DerObjectIdentifier sm2sign = sm_scheme.Branch("301.1");
+        public static readonly DerObjectIdentifier sm2exchange = sm_scheme.Branch("301.2");
+        public static readonly DerObjectIdentifier sm2encrypt = sm_scheme.Branch("301.3");
+
+        public static readonly DerObjectIdentifier wapip192v1 = sm_scheme.Branch("301.101");
+
+        public static readonly DerObjectIdentifier sm2encrypt_recommendedParameters = sm2encrypt.Branch("1");
+        public static readonly DerObjectIdentifier sm2encrypt_specifiedParameters = sm2encrypt.Branch("2");
+        public static readonly DerObjectIdentifier sm2encrypt_with_sm3 = sm2encrypt.Branch("2.1");
+        public static readonly DerObjectIdentifier sm2encrypt_with_sha1 = sm2encrypt.Branch("2.2");
+        public static readonly DerObjectIdentifier sm2encrypt_with_sha224 = sm2encrypt.Branch("2.3");
+        public static readonly DerObjectIdentifier sm2encrypt_with_sha256 = sm2encrypt.Branch("2.4");
+        public static readonly DerObjectIdentifier sm2encrypt_with_sha384 = sm2encrypt.Branch("2.5");
+        public static readonly DerObjectIdentifier sm2encrypt_with_sha512 = sm2encrypt.Branch("2.6");
+        public static readonly DerObjectIdentifier sm2encrypt_with_rmd160 = sm2encrypt.Branch("2.7");
+        public static readonly DerObjectIdentifier sm2encrypt_with_whirlpool = sm2encrypt.Branch("2.8");
+        public static readonly DerObjectIdentifier sm2encrypt_with_blake2b512 = sm2encrypt.Branch("2.9");
+        public static readonly DerObjectIdentifier sm2encrypt_with_blake2s256 = sm2encrypt.Branch("2.10");
+        public static readonly DerObjectIdentifier sm2encrypt_with_md5 = sm2encrypt.Branch("2.11");
+
+        public static readonly DerObjectIdentifier id_sm9PublicKey = sm_scheme.Branch("302");
+        public static readonly DerObjectIdentifier sm9sign = sm_scheme.Branch("302.1");
+        public static readonly DerObjectIdentifier sm9keyagreement = sm_scheme.Branch("302.2");
+        public static readonly DerObjectIdentifier sm9encrypt = sm_scheme.Branch("302.3");
+
+        public static readonly DerObjectIdentifier sm3 = sm_scheme.Branch("401");
+
+        public static readonly DerObjectIdentifier hmac_sm3 = sm3.Branch("2");
+
+        public static readonly DerObjectIdentifier sm2sign_with_sm3 = sm_scheme.Branch("501");
+        public static readonly DerObjectIdentifier sm2sign_with_sha1 = sm_scheme.Branch("502");
+        public static readonly DerObjectIdentifier sm2sign_with_sha256 = sm_scheme.Branch("503");
+        public static readonly DerObjectIdentifier sm2sign_with_sha512 = sm_scheme.Branch("504");
+        public static readonly DerObjectIdentifier sm2sign_with_sha224 = sm_scheme.Branch("505");
+        public static readonly DerObjectIdentifier sm2sign_with_sha384 = sm_scheme.Branch("506");
+        public static readonly DerObjectIdentifier sm2sign_with_rmd160 = sm_scheme.Branch("507");
+        public static readonly DerObjectIdentifier sm2sign_with_whirlpool = sm_scheme.Branch("520");
+        public static readonly DerObjectIdentifier sm2sign_with_blake2b512 = sm_scheme.Branch("521");
+        public static readonly DerObjectIdentifier sm2sign_with_blake2s256 = sm_scheme.Branch("522");
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs b/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
index 9311a3ac1..b322ef233 100644
--- a/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
+++ b/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
@@ -27,5 +27,10 @@ namespace Org.BouncyCastle.Asn1.Gnu
 		public static readonly DerObjectIdentifier Serpent256Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB
 		public static readonly DerObjectIdentifier Crc					= new DerObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
 		public static readonly DerObjectIdentifier Crc32				= new DerObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32
+
+        /** 1.3.6.1.4.1.11591.15 - ellipticCurve */
+        public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.6.1.4.1.11591.15");
+
+        public static readonly DerObjectIdentifier Ed25519   = EllipticCurve.Branch("1");
 	}
 }
diff --git a/crypto/src/asn1/pkcs/CertificationRequest.cs b/crypto/src/asn1/pkcs/CertificationRequest.cs
index 35bdd56eb..98caa2268 100644
--- a/crypto/src/asn1/pkcs/CertificationRequest.cs
+++ b/crypto/src/asn1/pkcs/CertificationRequest.cs
@@ -47,7 +47,8 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             this.sigBits = signature;
         }
 
-		public CertificationRequest(
+        [Obsolete("Use 'GetInstance' instead")]
+        public CertificationRequest(
             Asn1Sequence seq)
         {
 			if (seq.Count != 3)
diff --git a/crypto/src/asn1/pkcs/CertificationRequestInfo.cs b/crypto/src/asn1/pkcs/CertificationRequestInfo.cs
index d57753235..6d980131e 100644
--- a/crypto/src/asn1/pkcs/CertificationRequestInfo.cs
+++ b/crypto/src/asn1/pkcs/CertificationRequestInfo.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
@@ -31,20 +30,13 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         internal SubjectPublicKeyInfo	subjectPKInfo;
         internal Asn1Set				attributes;
 
-		public static CertificationRequestInfo GetInstance(
-            object  obj)
+		public static CertificationRequestInfo GetInstance(object obj)
         {
             if (obj is CertificationRequestInfo)
-            {
-                return (CertificationRequestInfo) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new CertificationRequestInfo((Asn1Sequence) obj);
-            }
-
-			throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+                return (CertificationRequestInfo)obj;
+            if (obj != null)
+                return new CertificationRequestInfo(Asn1Sequence.GetInstance(obj));
+            return null;
 		}
 
 		public CertificationRequestInfo(
@@ -56,7 +48,9 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             this.subjectPKInfo = pkInfo;
             this.attributes = attributes;
 
-			if (subject == null || version == null || subjectPKInfo == null)
+            ValidateAttributes(attributes);
+
+            if (subject == null || version == null || subjectPKInfo == null)
             {
                 throw new ArgumentException(
 					"Not all mandatory fields set in CertificationRequestInfo generator.");
@@ -81,7 +75,9 @@ namespace Org.BouncyCastle.Asn1.Pkcs
                 attributes = Asn1Set.GetInstance(tagobj, false);
             }
 
-			if (subject == null || version == null || subjectPKInfo == null)
+            ValidateAttributes(attributes);
+
+            if (subject == null || version == null || subjectPKInfo == null)
             {
                 throw new ArgumentException(
 					"Not all mandatory fields set in CertificationRequestInfo generator.");
@@ -120,5 +116,22 @@ namespace Org.BouncyCastle.Asn1.Pkcs
 
 			return new DerSequence(v);
         }
+
+        private static void ValidateAttributes(Asn1Set attributes)
+        {
+            if (attributes == null)
+                return;
+
+            foreach (Asn1Encodable ae in attributes)
+            {
+                Asn1Object obj = ae.ToAsn1Object();
+                AttributePkcs attr = AttributePkcs.GetInstance(obj);
+                if (attr.AttrType.Equals(PkcsObjectIdentifiers.Pkcs9AtChallengePassword))
+                {
+                    if (attr.AttrValues.Count != 1)
+                        throw new ArgumentException("challengePassword attribute must have one value");
+                }
+            }
+        }
     }
 }
diff --git a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
index 042911a06..1a9a03e9f 100644
--- a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
+++ b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
@@ -9,23 +9,28 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
         //
         public const string Pkcs1 = "1.2.840.113549.1.1";
+        internal static readonly DerObjectIdentifier Pkcs1Oid                 = new DerObjectIdentifier(Pkcs1);
+
+        public static readonly DerObjectIdentifier RsaEncryption            = Pkcs1Oid.Branch("1");
+        public static readonly DerObjectIdentifier MD2WithRsaEncryption		= Pkcs1Oid.Branch("2");
+        public static readonly DerObjectIdentifier MD4WithRsaEncryption		= Pkcs1Oid.Branch("3");
+        public static readonly DerObjectIdentifier MD5WithRsaEncryption		= Pkcs1Oid.Branch("4");
+        public static readonly DerObjectIdentifier Sha1WithRsaEncryption	= Pkcs1Oid.Branch("5");
+        public static readonly DerObjectIdentifier SrsaOaepEncryptionSet	= Pkcs1Oid.Branch("6");
+        public static readonly DerObjectIdentifier IdRsaesOaep				= Pkcs1Oid.Branch("7");
+        public static readonly DerObjectIdentifier IdMgf1					= Pkcs1Oid.Branch("8");
+        public static readonly DerObjectIdentifier IdPSpecified				= Pkcs1Oid.Branch("9");
+        public static readonly DerObjectIdentifier IdRsassaPss				= Pkcs1Oid.Branch("10");
+        public static readonly DerObjectIdentifier Sha256WithRsaEncryption	= Pkcs1Oid.Branch("11");
+        public static readonly DerObjectIdentifier Sha384WithRsaEncryption	= Pkcs1Oid.Branch("12");
+        public static readonly DerObjectIdentifier Sha512WithRsaEncryption	= Pkcs1Oid.Branch("13");
+        public static readonly DerObjectIdentifier Sha224WithRsaEncryption	= Pkcs1Oid.Branch("14");
+        /** PKCS#1: 1.2.840.113549.1.1.15 */
+        public static readonly DerObjectIdentifier Sha512_224WithRSAEncryption = Pkcs1Oid.Branch("15");
+        /** PKCS#1: 1.2.840.113549.1.1.16 */
+        public static readonly DerObjectIdentifier Sha512_256WithRSAEncryption = Pkcs1Oid.Branch("16");
 
-		public static readonly DerObjectIdentifier RsaEncryption			= new DerObjectIdentifier(Pkcs1 + ".1");
-        public static readonly DerObjectIdentifier MD2WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".2");
-        public static readonly DerObjectIdentifier MD4WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".3");
-        public static readonly DerObjectIdentifier MD5WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".4");
-        public static readonly DerObjectIdentifier Sha1WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".5");
-        public static readonly DerObjectIdentifier SrsaOaepEncryptionSet	= new DerObjectIdentifier(Pkcs1 + ".6");
-        public static readonly DerObjectIdentifier IdRsaesOaep				= new DerObjectIdentifier(Pkcs1 + ".7");
-        public static readonly DerObjectIdentifier IdMgf1					= new DerObjectIdentifier(Pkcs1 + ".8");
-        public static readonly DerObjectIdentifier IdPSpecified				= new DerObjectIdentifier(Pkcs1 + ".9");
-        public static readonly DerObjectIdentifier IdRsassaPss				= new DerObjectIdentifier(Pkcs1 + ".10");
-        public static readonly DerObjectIdentifier Sha256WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".11");
-        public static readonly DerObjectIdentifier Sha384WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".12");
-        public static readonly DerObjectIdentifier Sha512WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".13");
-        public static readonly DerObjectIdentifier Sha224WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".14");
-
-		//
+        //
         // pkcs-3 OBJECT IDENTIFIER ::= {
         //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
         //
@@ -195,6 +200,7 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
         //
         public const string IdAA = "1.2.840.113549.1.9.16.2";
+        public static readonly DerObjectIdentifier IdAAOid = new DerObjectIdentifier(IdAA);
 
 		public static readonly DerObjectIdentifier IdAAContentHint = new DerObjectIdentifier(IdAA + ".4"); // See RFC 2634
     	public static readonly DerObjectIdentifier IdAAMsgSigDigest = new DerObjectIdentifier(IdAA + ".5");
@@ -229,6 +235,20 @@ namespace Org.BouncyCastle.Asn1.Pkcs
 		public static readonly DerObjectIdentifier IdAAEtsCertCrlTimestamp = new DerObjectIdentifier(IdAA + ".26");
 		public static readonly DerObjectIdentifier IdAAEtsArchiveTimestamp = new DerObjectIdentifier(IdAA + ".27");
 
+        /** PKCS#9: 1.2.840.113549.1.9.16.6.2.37 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.5">RFC 4108</a> */
+        public static readonly DerObjectIdentifier IdAADecryptKeyID = IdAAOid.Branch("37");
+
+        /** PKCS#9: 1.2.840.113549.1.9.16.6.2.38 - <a href="https://tools.ietf.org/html/rfc4108#section-2.2.6">RFC 4108</a> */
+        public static readonly DerObjectIdentifier IdAAImplCryptoAlgs = IdAAOid.Branch("38");
+
+        /** PKCS#9: 1.2.840.113549.1.9.16.2.54 <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/
+        public static readonly DerObjectIdentifier IdAAAsymmDecryptKeyID = IdAAOid.Branch("54");
+
+        /** PKCS#9: 1.2.840.113549.1.9.16.2.43   <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/
+        public static readonly DerObjectIdentifier IdAAImplCompressAlgs = IdAAOid.Branch("43");
+        /** PKCS#9: 1.2.840.113549.1.9.16.2.40   <a href="https://tools.ietf.org/html/rfc7030">RFC7030</a>*/
+        public static readonly DerObjectIdentifier IdAACommunityIdentifiers = IdAAOid.Branch("40");
+
 		[Obsolete("Use 'IdAAEtsSigPolicyID' instead")]
 		public static readonly DerObjectIdentifier IdAASigPolicyID = IdAAEtsSigPolicyID;
 		[Obsolete("Use 'IdAAEtsCommitmentType' instead")]
diff --git a/crypto/src/asn1/x509/KeyPurposeId.cs b/crypto/src/asn1/x509/KeyPurposeId.cs
index 4b48a9b51..1a564b97a 100644
--- a/crypto/src/asn1/x509/KeyPurposeId.cs
+++ b/crypto/src/asn1/x509/KeyPurposeId.cs
@@ -32,5 +32,7 @@ namespace Org.BouncyCastle.Asn1.X509
         // microsoft key purpose ids
         //
         public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+
+        public static readonly KeyPurposeID IdKPMacAddress = new KeyPurposeID("1.3.6.1.1.1.1.22");
     }
 }
diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs
index 2ef73f629..049d728bb 100644
--- a/crypto/src/asn1/x509/X509Extensions.cs
+++ b/crypto/src/asn1/x509/X509Extensions.cs
@@ -164,6 +164,11 @@ namespace Org.BouncyCastle.Asn1.X509
 		 */
 		public static readonly DerObjectIdentifier TargetInformation = new DerObjectIdentifier("2.5.29.55");
 
+        /**
+         * Expired Certificates on CRL extension
+         */
+        public static readonly DerObjectIdentifier ExpiredCertsOnCrl = new DerObjectIdentifier("2.5.29.60");
+
         private readonly IDictionary extensions = Platform.CreateHashtable();
         private readonly IList ordering;
 
diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs
index 92d4393a8..317ef17b4 100644
--- a/crypto/src/asn1/x9/ECNamedCurveTable.cs
+++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs
@@ -2,6 +2,7 @@
 using System.Collections;
 
 using Org.BouncyCastle.Asn1.Anssi;
+using Org.BouncyCastle.Asn1.GM;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.TeleTrust;
@@ -25,27 +26,26 @@ namespace Org.BouncyCastle.Asn1.X9
         public static X9ECParameters GetByName(string name)
         {
             X9ECParameters ecP = X962NamedCurves.GetByName(name);
-
             if (ecP == null)
             {
                 ecP = SecNamedCurves.GetByName(name);
             }
-
             if (ecP == null)
             {
                 ecP = NistNamedCurves.GetByName(name);
             }
-
             if (ecP == null)
             {
                 ecP = TeleTrusTNamedCurves.GetByName(name);
             }
-
             if (ecP == null)
             {
                 ecP = AnssiNamedCurves.GetByName(name);
             }
-
+            if (ecP == null)
+            {
+                ecP = GMNamedCurves.GetByName(name);
+            }
             return ecP;
         }
 
@@ -68,6 +68,10 @@ namespace Org.BouncyCastle.Asn1.X9
             {
                 name = AnssiNamedCurves.GetName(oid);
             }
+            if (name == null)
+            {
+                name = GMNamedCurves.GetName(oid);
+            }
             return name;
         }
 
@@ -80,27 +84,26 @@ namespace Org.BouncyCastle.Asn1.X9
         public static DerObjectIdentifier GetOid(string name)
         {
             DerObjectIdentifier oid = X962NamedCurves.GetOid(name);
-
             if (oid == null)
             {
                 oid = SecNamedCurves.GetOid(name);
             }
-
             if (oid == null)
             {
                 oid = NistNamedCurves.GetOid(name);
             }
-
             if (oid == null)
             {
                 oid = TeleTrusTNamedCurves.GetOid(name);
             }
-
             if (oid == null)
             {
                 oid = AnssiNamedCurves.GetOid(name);
             }
-
+            if (oid == null)
+            {
+                oid = GMNamedCurves.GetOid(name);
+            }
             return oid;
         }
 
@@ -114,7 +117,6 @@ namespace Org.BouncyCastle.Asn1.X9
         public static X9ECParameters GetByOid(DerObjectIdentifier oid)
         {
             X9ECParameters ecP = X962NamedCurves.GetByOid(oid);
-
             if (ecP == null)
             {
                 ecP = SecNamedCurves.GetByOid(oid);
@@ -126,12 +128,14 @@ namespace Org.BouncyCastle.Asn1.X9
             {
                 ecP = TeleTrusTNamedCurves.GetByOid(oid);
             }
-
             if (ecP == null)
             {
                 ecP = AnssiNamedCurves.GetByOid(oid);
             }
-
+            if (ecP == null)
+            {
+                ecP = GMNamedCurves.GetByOid(oid);
+            }
             return ecP;
         }
 
@@ -150,6 +154,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 CollectionUtilities.AddRange(v, NistNamedCurves.Names);
                 CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names);
                 CollectionUtilities.AddRange(v, AnssiNamedCurves.Names);
+                CollectionUtilities.AddRange(v, GMNamedCurves.Names);
                 return v;
             }
         }
diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs
index 1f0e412d8..7a5066ec3 100644
--- a/crypto/src/bcpg/ArmoredOutputStream.cs
+++ b/crypto/src/bcpg/ArmoredOutputStream.cs
@@ -20,6 +20,8 @@ namespace Org.BouncyCastle.Bcpg
     public class ArmoredOutputStream
         : BaseOutputStream
     {
+        public static readonly string HeaderVersion = "Version";
+
         private static readonly byte[] encodingTable =
         {
             (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
@@ -101,44 +103,58 @@ namespace Org.BouncyCastle.Bcpg
         private static readonly string    footerStart = "-----END PGP ";
         private static readonly string    footerTail = "-----";
 
-        private static readonly string version = "BCPG C# v" + AssemblyInfo.Version;
+        private static readonly string Version = "BCPG C# v" + AssemblyInfo.Version;
 
         private readonly IDictionary headers;
 
         public ArmoredOutputStream(Stream outStream)
         {
             this.outStream = outStream;
-            this.headers = Platform.CreateHashtable();
-            this.headers["Version"] = version;
+            this.headers = Platform.CreateHashtable(1);
+            this.headers.Add(HeaderVersion, Version);
         }
 
         public ArmoredOutputStream(Stream outStream, IDictionary headers)
         {
             this.outStream = outStream;
             this.headers = Platform.CreateHashtable(headers);
-            this.headers["Version"] = version;
+            if (!this.headers.Contains(HeaderVersion))
+            {
+                this.headers.Add(HeaderVersion, Version);
+            }
         }
 
         /**
-         * Set an additional header entry.
+         * Set an additional header entry. A null value will clear the entry for name.
          *
          * @param name the name of the header entry.
          * @param v the value of the header entry.
          */
-        public void SetHeader(
-            string name,
-            string v)
+        public void SetHeader(string name, string v)
         {
-            headers[name] = v;
+            if (v == null)
+            {
+                headers.Remove(name);
+            }
+            else
+            {
+                headers[name] = v;
+            }
         }
 
         /**
-         * Reset the headers to only contain a Version string.
+         * Reset the headers to only contain a Version string (if one is present).
          */
         public void ResetHeaders()
         {
+            string version = (string)headers[HeaderVersion];
+
             headers.Clear();
-            headers["Version"] = version;
+
+            if (version != null)
+            {
+                headers[HeaderVersion] = Version;
+            }
         }
 
         /**
@@ -248,14 +264,17 @@ namespace Org.BouncyCastle.Bcpg
                 }
 
                 DoWrite(headerStart + type + headerTail + nl);
-                WriteHeaderEntry("Version", (string) headers["Version"]);
+                if (headers.Contains(HeaderVersion))
+                {
+                    WriteHeaderEntry(HeaderVersion, (string)headers[HeaderVersion]);
+                }
 
                 foreach (DictionaryEntry de in headers)
                 {
-                    string k = (string) de.Key;
-                    if (k != "Version")
+                    string k = (string)de.Key;
+                    if (k != HeaderVersion)
                     {
-                        string v = (string) de.Value;
+                        string v = (string)de.Value;
                         WriteHeaderEntry(k, v);
                     }
                 }
diff --git a/crypto/src/crypto/agreement/DHAgreement.cs b/crypto/src/crypto/agreement/DHAgreement.cs
index d214caafe..e988c0d53 100644
--- a/crypto/src/crypto/agreement/DHAgreement.cs
+++ b/crypto/src/crypto/agreement/DHAgreement.cs
@@ -81,13 +81,19 @@ namespace Org.BouncyCastle.Crypto.Agreement
 				throw new ArgumentNullException("message");
 
 			if (!pub.Parameters.Equals(dhParams))
-			{
 				throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
-			}
 
-			BigInteger p = dhParams.P;
+            BigInteger p = dhParams.P;
 
-			return message.ModPow(key.X, p).Multiply(pub.Y.ModPow(privateValue, p)).Mod(p);
-		}
-	}
+            BigInteger peerY = pub.Y;
+            if (peerY == null || peerY.CompareTo(BigInteger.One) <= 0 || peerY.CompareTo(p.Subtract(BigInteger.One)) >= 0)
+                throw new ArgumentException("Diffie-Hellman public key is weak");
+
+            BigInteger result = peerY.ModPow(privateValue, p);
+            if (result.Equals(BigInteger.One))
+                throw new InvalidOperationException("Shared key can't be 1");
+
+            return message.ModPow(key.X, p).Multiply(result).Mod(p);
+        }
+    }
 }
diff --git a/crypto/src/crypto/agreement/DHBasicAgreement.cs b/crypto/src/crypto/agreement/DHBasicAgreement.cs
index 75b5e9db5..6c3fe6595 100644
--- a/crypto/src/crypto/agreement/DHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/DHBasicAgreement.cs
@@ -54,11 +54,19 @@ namespace Org.BouncyCastle.Crypto.Agreement
             DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
 
             if (!pub.Parameters.Equals(dhParams))
-            {
                 throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
-            }
 
-            return pub.Y.ModPow(key.X, dhParams.P);
+            BigInteger p = dhParams.P;
+
+            BigInteger peerY = pub.Y;
+            if (peerY == null || peerY.CompareTo(BigInteger.One) <= 0 || peerY.CompareTo(p.Subtract(BigInteger.One)) >= 0)
+                throw new ArgumentException("Diffie-Hellman public key is weak");
+
+            BigInteger result = peerY.ModPow(key.X, p);
+            if (result.Equals(BigInteger.One))
+                throw new InvalidOperationException("Shared key can't be 1");
+
+            return result;
         }
     }
 }
diff --git a/crypto/src/crypto/agreement/DHStandardGroups.cs b/crypto/src/crypto/agreement/DHStandardGroups.cs
index 93b65af98..425a9784c 100644
--- a/crypto/src/crypto/agreement/DHStandardGroups.cs
+++ b/crypto/src/crypto/agreement/DHStandardGroups.cs
@@ -161,6 +161,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
             + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
             + "855E6EEB22B3B2E5";
         private static readonly string rfc5114_1024_160_q = "F518AA8781A8DF278ABA4E7D64B7CB9D49462353";
+
+        /// <remarks>
+        /// Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf .
+        /// </remarks>
+        [Obsolete("Existence of a 'hidden SNFS' backdoor cannot be ruled out.")]
         public static readonly DHParameters rfc5114_1024_160 = FromPGQ(rfc5114_1024_160_p, rfc5114_1024_160_g,
             rfc5114_1024_160_q);
 
@@ -177,6 +182,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
             + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"
             + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" + "81BC087F2A7065B384B890D3191F2BFA";
         private static readonly string rfc5114_2048_224_q = "801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB";
+
+        /// <remarks>
+        /// Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf .
+        /// </remarks>
+        [Obsolete("Existence of a 'hidden SNFS' backdoor cannot be ruled out.")]
         public static readonly DHParameters rfc5114_2048_224 = FromPGQ(rfc5114_2048_224_p, rfc5114_2048_224_g,
             rfc5114_2048_224_q);
 
@@ -194,6 +204,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
             + "184B523D1DB246C32F63078490F00EF8D647D148D4795451" + "5E2327CFEF98C582664B4C0F6CC41659";
         private static readonly string rfc5114_2048_256_q = "8CF83642A709A097B447997640129DA299B1A47D1EB3750B"
             + "A308B0FE64F5FBD3";
+
+        /// <remarks>
+        /// Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf .
+        /// </remarks>
+        [Obsolete("Existence of a 'hidden SNFS' backdoor cannot be ruled out.")]
         public static readonly DHParameters rfc5114_2048_256 = FromPGQ(rfc5114_2048_256_p, rfc5114_2048_256_g,
             rfc5114_2048_256_q);
 
diff --git a/crypto/src/crypto/digests/DSTU7564Digest.cs b/crypto/src/crypto/digests/DSTU7564Digest.cs
new file mode 100644
index 000000000..9de41dd6b
--- /dev/null
+++ b/crypto/src/crypto/digests/DSTU7564Digest.cs
@@ -0,0 +1,562 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+//using Org.BouncyCastle.Utilities;
+
+
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+     /**
+	* implementation of Ukrainian DSTU 7564 hash function
+	*/
+     public class Dstu7564Digest : IDigest, IMemoable
+     {
+          private const int ROWS = 8;
+          private const int REDUCTION_POLYNOMIAL = 0x011d;
+          private const int BITS_IN_BYTE = 8;
+
+
+          private const int NB_512 = 8;  //Number of 8-byte words in state for <=256-bit hash code.
+          private const int NB_1024 = 16;  //Number of 8-byte words in state for <=512-bit hash code. 
+
+          private const int NR_512 = 10;  //Number of rounds for 512-bit state.
+          private const int NR_1024 = 14;  //Number of rounds for 1024-bit state.
+
+          private const int STATE_BYTE_SIZE_512 = ROWS * NB_512;
+          private const int STATE_BYTE_SIZE_1024 = ROWS * NB_1024;
+
+          private int hashSize;
+          private int blockSize;
+
+
+
+          private int columns;
+          private int rounds;
+
+
+          private byte[] padded_;
+
+          private byte[][] state_;
+
+        private ulong inputLength;
+        private int bufOff;
+        private byte[] buf;
+
+        public Dstu7564Digest(Dstu7564Digest digest)
+        {
+            copyIn(digest);
+        }
+
+        private void copyIn(Dstu7564Digest digest)
+        {
+            this.hashSize = digest.hashSize;
+            this.blockSize = digest.blockSize;
+
+            this.columns = digest.columns;
+            this.rounds = digest.rounds;
+
+            this.padded_ = Arrays.Clone(digest.padded_);
+            this.state_ = new byte[digest.state_.Length][];
+            for (int i = 0; i != this.state_.Length; i++)
+            {
+                this.state_[i] = Arrays.Clone(digest.state_[i]);
+            }
+
+            this.inputLength = digest.inputLength;
+            this.bufOff = digest.bufOff;
+            this.buf = Arrays.Clone(digest.buf);
+        }
+
+        public Dstu7564Digest(int hashSizeBits)
+          {
+               if (hashSizeBits == 256 || hashSizeBits == 384 || hashSizeBits == 512)
+               {
+                    this.hashSize = hashSizeBits / 8;
+               }
+               else
+               {
+                    throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size");
+               }
+
+               if (hashSizeBits > 256)
+               {
+                    this.blockSize = 1024 / 8;
+                    this.columns = NB_1024;
+                    this.rounds = NR_1024;
+                    this.state_ = new byte[STATE_BYTE_SIZE_1024][];
+
+               }
+               else
+               {
+                    this.blockSize = 512 / 8;
+                    this.columns = NB_512;
+                    this.rounds = NR_512;
+                    this.state_ = new byte[STATE_BYTE_SIZE_512][];
+
+               }
+
+               //Console.WriteLine("length: " + state_.Length);
+
+               for (int i = 0; i < state_.Length; i++)
+               {
+                    this.state_[i] = new byte[columns];
+               }
+
+               this.state_[0][0] = (byte)state_.Length;
+               
+               this.hashSize = hashSizeBits / 8;
+
+               this.padded_ = null;
+               this.buf = new byte[blockSize];
+        }
+
+          public string AlgorithmName
+          {
+               get { return "DSTU7564"; }
+          }
+
+
+          public virtual void BlockUpdate(byte[] input, int inOff, int length)
+          {
+            while (bufOff != 0 && length > 0)
+            {
+                Update(input[inOff++]);
+                length--;
+            }
+
+            if (length > 0)
+            {
+                while (length > blockSize)
+                {
+                    ProcessBlock(input, inOff);
+                    inOff += blockSize;
+                    inputLength += (ulong)blockSize;
+                    length -= blockSize;
+                }
+
+                while (length > 0)
+                {
+                    Update(input[inOff++]);
+                    length--;
+                }
+            }
+        }
+
+          protected byte[] Pad(byte[] input, int inOff, int length)
+          {
+            //Console.WriteLine(length);
+
+            byte[] padded;
+            if (blockSize - length < 13)         // terminator byte + 96 bits of length
+            {
+                padded = new byte[2 * blockSize];
+            }
+            else
+            {
+                padded = new byte[blockSize];
+            }
+
+
+              Array.Copy(input, inOff, padded, 0, length);
+              padded[length] = 0x80;
+              Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12);
+
+              return padded;
+          }
+
+          protected void ProcessBlock(byte[] input, int inOff)
+          {
+               byte[][] temp1 = new byte[STATE_BYTE_SIZE_1024][];
+               byte[][] temp2 = new byte[STATE_BYTE_SIZE_1024][];
+
+               for (int i = 0; i < state_.Length; i++)
+               {
+                    temp1[i] = new byte[ROWS];
+                    temp2[i] = new byte[ROWS];
+               }
+               
+               for (int i = 0; i < ROWS; ++i)
+               {
+                    for (int j = 0; j < columns; ++j)
+                    {
+                         //Console.WriteLine("row = {0}, column = {1}", i, j);
+
+                         temp1[j][i] = (byte)(state_[j][i] ^ input[j * ROWS + i + inOff]);
+                         temp2[j][i] = input[j * ROWS + i + inOff];
+
+                    }
+                    
+               }
+
+               P(temp1);
+
+               Q(temp2);
+
+               for (int i = 0; i < ROWS; ++i)
+               {
+                    for (int j = 0; j < columns; ++j)
+                    {
+                         state_[j][i] ^= (byte)(temp1[j][i] ^ temp2[j][i]);
+
+                    }
+ 
+               }
+          }
+
+          public int DoFinal(byte[] output, int outOff)
+          {
+            padded_ = Pad(buf, 0, bufOff);
+
+            int paddedLen = padded_.Length;
+            int paddedOff = 0;
+
+            while (paddedLen != 0)
+            {
+                ProcessBlock(padded_, paddedOff);
+                paddedOff += blockSize;
+                paddedLen -= blockSize;
+            }
+
+
+            //Console.WriteLine(stateLine.Length);
+
+            byte[][] temp = new byte[STATE_BYTE_SIZE_1024][];
+               for (int i = 0; i < state_.Length; i++)
+               {
+                    temp[i] = new byte[ROWS];
+                    Array.Copy(state_[i], temp[i], ROWS);
+               }
+
+            P(temp);
+
+            for (int i = 0; i < ROWS; ++i)
+            {
+                 for (int j = 0; j < columns; ++j)
+                 {
+                      state_[j][i] ^= temp[j][i];
+                      //Console.Write("{0:x} ", state_[j][i]);
+                 }
+                 //Console.WriteLine();
+            }
+
+            byte[] stateLine = new byte[ROWS * columns];
+            int stateLineIndex = 0;
+               for (int j = 0; j < columns; ++j)
+               {
+                    for (int i = 0; i < ROWS; ++i)
+                    {
+                    
+                         stateLine[stateLineIndex] = state_[j][i];
+                         stateLineIndex++;
+
+                         //Console.WriteLine("index = {0}, row = {1}, column = {2}", stateLineIndex, i, j);
+
+                    }
+               }
+               
+               //Console.WriteLine("final: " + Hex.ToHexString(stateLine));
+               //Console.WriteLine(stateLine.Length);
+               
+               Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize);
+
+                Reset();
+
+               return hashSize;
+          }
+
+          public void Reset()
+          {
+            for (int bufferIndex = 0; bufferIndex < state_.Length; bufferIndex++)
+            {
+                state_[bufferIndex] = new byte[columns];
+            }
+
+            state_[0][0] = (byte)state_.Length;
+
+            inputLength = 0;
+            bufOff = 0;
+
+            Arrays.Fill(buf, (byte)0);
+
+            if (padded_ != null)
+            {
+                Arrays.Fill(padded_, (byte)0);
+            }
+        }
+
+          public int GetDigestSize()
+          {
+               return hashSize;
+          }
+
+          public int GetByteLength()
+          {
+               return blockSize;
+          }
+
+          public void Update(byte input)
+          {
+            buf[bufOff++] = input;
+            if (bufOff == blockSize)
+            {
+                ProcessBlock(buf, 0);
+                bufOff = 0;
+            }
+            inputLength++;
+          }
+
+        void SubBytes(byte[][] state)
+          {
+               int i, j;
+               for (i = 0; i < ROWS; ++i)
+               {
+                    for (j = 0; j < columns; ++j)
+                    {
+                         state[j][i] = sBoxes[i % 4][state[j][i]];
+                    }
+               }
+          }
+
+          void ShiftBytes(byte[][] state)
+          {
+               int i, j;
+               byte[] temp = new byte[NB_1024];
+               int shift = -1;
+               for (i = 0; i < ROWS; ++i)
+               {
+                    if ((i == ROWS - 1) && (columns == NB_1024))
+                    {
+                         shift = 11;
+                    }
+                    else
+                    {
+                         ++shift;
+                    }
+                    for (j = 0; j < columns; ++j)
+                    {
+                         temp[(j + shift) % columns] = state[j][i];
+                    }
+                    for (j = 0; j < columns; ++j)
+                    {
+                         state[j][i] = temp[j];
+                    }
+               }
+          }
+
+          byte MultiplyGF(byte x, byte y)
+          {
+               int i;
+               byte r = 0;
+               byte hbit = 0;
+               for (i = 0; i < BITS_IN_BYTE; ++i)
+               {
+                    if ((y & 0x1) == 1)
+                    {
+                         r ^= x;
+                    }
+
+                    hbit = (byte)(x & 0x80);
+
+                    x <<= 1;
+
+                    if (hbit == 0x80)
+                    {
+                         x = (byte)((int)x ^ REDUCTION_POLYNOMIAL);
+                    }
+
+                    y >>= 1;
+               }
+               return r;
+          }
+
+          private void MixColumns(byte[][] state)
+          {
+               int i, row, col, b;
+               byte product;
+               byte[] result = new byte[ROWS];
+
+               for (col = 0; col < columns; ++col)
+               {
+                    Array.Clear(result, 0, ROWS);
+                    for (row = ROWS - 1; row >= 0; --row)
+                    {
+                         product = 0;
+                         for (b = ROWS - 1; b >= 0; --b)
+                         {
+                              product ^= MultiplyGF(state[col][b], mds_matrix[row][b]);
+                         }
+                         result[row] = product;
+                    }
+                    for (i = 0; i < ROWS; ++i)
+                    {
+                         state[col][i] = result[i];
+                    }
+               }
+          }
+
+          void AddRoundConstantP(byte[][] state, int round)
+          {
+               int i;
+               for (i = 0; i < columns; ++i)
+               {
+                    state[i][0] ^= (byte)((i * 0x10) ^ round);
+               }
+          }
+
+          void AddRoundConstantQ(byte[][] state, int round)
+          {
+               int j;
+               UInt64[] s = new UInt64[columns];
+
+               for (j = 0; j < columns; j++)
+               {
+                    s[j] = Pack.LE_To_UInt64(state[j]);
+
+                    s[j] = s[j] + (0x00F0F0F0F0F0F0F3UL ^ ((((UInt64)(columns - j - 1) * 0x10UL) ^ (UInt64)round) << (7 * 8)));
+
+                    state[j] = Pack.UInt64_To_LE(s[j]);
+               }
+          }
+
+          void P(byte[][] state)
+          {
+               int i;
+               for (i = 0; i < rounds; ++i)
+               {
+                    AddRoundConstantP(state, i);
+                    SubBytes(state);
+                    ShiftBytes(state);
+                    MixColumns(state);
+               }
+          }
+
+          void Q(byte[][] state)
+          {
+               int i;
+               for (i = 0; i < rounds; ++i)
+               {
+                    AddRoundConstantQ(state, i);
+                    SubBytes(state);
+                    ShiftBytes(state);
+                    MixColumns(state);
+               }
+          }
+
+        public IMemoable Copy()
+        {
+            return new Dstu7564Digest(this);
+        }
+
+        public void Reset(IMemoable other)
+        {
+            Dstu7564Digest d = (Dstu7564Digest)other;
+
+            copyIn(d);
+        }
+
+        private readonly byte[][] mds_matrix = new byte[][]
+          { 
+               new byte[] {0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04},
+	          new byte[] {0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07},
+	          new byte[] {0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06},
+	          new byte[] {0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08},
+	          new byte[] {0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01},
+	          new byte[] {0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05},
+	          new byte[] {0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01},
+               new byte[] {0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01}
+          };
+
+
+
+
+          private readonly byte[][] sBoxes = new byte[][]
+          {
+               new byte[]
+               {
+                    0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, 
+	               0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, 
+	               0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, 
+	               0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, 
+	               0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, 
+	               0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, 
+	               0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, 
+	               0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, 
+	               0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, 
+	               0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, 
+	               0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, 
+	               0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, 
+	               0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, 
+	               0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, 
+	               0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, 
+	               0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
+               },
+
+               new byte[]
+               {
+                    0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, 
+	               0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, 
+	               0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, 
+	               0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, 
+	               0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, 
+	               0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, 
+	               0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, 
+	               0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, 
+	               0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, 
+	               0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, 
+	               0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, 
+	               0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, 
+	               0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, 
+	               0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, 
+	               0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, 
+	               0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
+               },
+
+               new byte[]
+               {
+                    0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, 
+	               0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, 
+	               0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, 
+	               0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, 
+	               0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, 
+	               0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, 
+	               0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, 
+	               0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, 
+	               0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, 
+	               0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, 
+	               0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, 
+	               0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, 
+	               0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, 
+	               0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, 
+	               0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, 
+	               0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
+               },
+
+               new byte[]
+               {
+                    0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, 
+	               0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, 
+	               0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, 
+	               0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, 
+	               0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, 
+	               0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, 
+	               0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, 
+	               0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, 
+	               0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, 
+	               0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, 
+	               0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, 
+	               0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, 
+	               0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, 
+	               0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, 
+	               0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, 
+	               0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
+               }
+          };
+
+
+     }
+}
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index 8a0c50a47..4b7600e09 100644
--- a/crypto/src/crypto/ec/CustomNamedCurves.cs
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -2,11 +2,13 @@ using System;
 using System.Collections;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.GM;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Math.EC.Custom.Djb;
+using Org.BouncyCastle.Math.EC.Custom.GM;
 using Org.BouncyCastle.Math.EC.Custom.Sec;
 using Org.BouncyCastle.Math.EC.Endo;
 using Org.BouncyCastle.Utilities;
@@ -746,6 +748,27 @@ namespace Org.BouncyCastle.Crypto.EC
             }
         };
 
+        /*
+         * sm2p256v1
+         */
+        internal class SM2P256V1Holder
+            : X9ECParametersHolder
+        {
+            private SM2P256V1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new SM2P256V1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new SM2P256V1Curve());
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+                    + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
+                    + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
 
         private static readonly IDictionary nameToCurve = Platform.CreateHashtable();
         private static readonly IDictionary nameToOid = Platform.CreateHashtable();
@@ -820,6 +843,8 @@ namespace Org.BouncyCastle.Crypto.EC
             DefineCurveWithOid("sect571k1", SecObjectIdentifiers.SecT571k1, SecT571K1Holder.Instance);
             DefineCurveWithOid("sect571r1", SecObjectIdentifiers.SecT571r1, SecT571R1Holder.Instance);
 
+            DefineCurveWithOid("sm2p256v1", GMObjectIdentifiers.sm2p256v1, SM2P256V1Holder.Instance);
+
             DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
             DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
             DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index cb23b1710..287876f12 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -3,6 +3,7 @@ using System;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Encodings
 {
@@ -13,7 +14,6 @@ namespace Org.BouncyCastle.Crypto.Encodings
         : IAsymmetricBlockCipher
     {
         private byte[] defHash;
-        private IDigest hash;
         private IDigest mgf1Hash;
 
         private IAsymmetricBlockCipher engine;
@@ -48,10 +48,11 @@ namespace Org.BouncyCastle.Crypto.Encodings
             byte[]					encodingParams)
         {
             this.engine = cipher;
-            this.hash = hash;
             this.mgf1Hash = mgf1Hash;
             this.defHash = new byte[hash.GetDigestSize()];
 
+            hash.Reset();
+
             if (encodingParams != null)
             {
                 hash.BlockUpdate(encodingParams, 0, encodingParams.Length);
@@ -137,6 +138,8 @@ namespace Org.BouncyCastle.Crypto.Encodings
             int		inOff,
             int		inLen)
         {
+            Check.DataLength(inLen > GetInputBlockSize(), "input data too long");
+
             byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
 
             //
@@ -202,28 +205,17 @@ namespace Org.BouncyCastle.Crypto.Encodings
             int		inLen)
         {
             byte[] data = engine.ProcessBlock(inBytes, inOff, inLen);
-            byte[] block;
+            byte[] block = new byte[engine.GetOutputBlockSize()];
 
             //
             // as we may have zeros in our leading bytes for the block we produced
             // on encryption, we need to make sure our decrypted block comes back
             // the same size.
             //
-            if (data.Length < engine.GetOutputBlockSize())
-            {
-                block = new byte[engine.GetOutputBlockSize()];
 
-                Array.Copy(data, 0, block, block.Length - data.Length, data.Length);
-            }
-            else
-            {
-                block = data;
-            }
+            Array.Copy(data, 0, block, block.Length - data.Length, data.Length);
 
-            if (block.Length < (2 * defHash.Length) + 1)
-            {
-                throw new InvalidCipherTextException("data too short");
-            }
+            bool shortData = (block.Length < (2 * defHash.Length) + 1);
 
             //
             // unmask the seed.
@@ -250,36 +242,39 @@ namespace Org.BouncyCastle.Crypto.Encodings
             // check the hash of the encoding params.
             // long check to try to avoid this been a source of a timing attack.
             //
+            bool defHashWrong = false;
+
+            for (int i = 0; i != defHash.Length; i++)
             {
-                int diff = 0;
-                for (int i = 0; i < defHash.Length; ++i)
+                if (defHash[i] != block[defHash.Length + i])
                 {
-                    diff |= (byte)(defHash[i] ^ block[defHash.Length + i]);
+                    defHashWrong = true;
                 }
- 
-                if (diff != 0)
-                    throw new InvalidCipherTextException("data hash wrong");
             }
 
             //
             // find the data block
             //
-            int start;
-            for (start = 2 * defHash.Length; start != block.Length; start++)
+            int start = block.Length;
+
+            for (int index = 2 * defHash.Length; index != block.Length; index++)
             {
-                if (block[start] != 0)
+                if (block[index] != 0 & start == block.Length)
                 {
-                    break;
+                    start = index;
                 }
             }
 
-            if (start > (block.Length - 1) || block[start] != 1)
-            {
-                throw new InvalidCipherTextException("data start wrong " + start);
-            }
+            bool dataStartWrong = (start > (block.Length - 1) | block[start] != 1);
 
             start++;
 
+            if (defHashWrong | shortData | dataStartWrong)
+            {
+                Arrays.Fill(block, 0);
+                throw new InvalidCipherTextException("data wrong");
+            }
+
             //
             // extract the data block
             //
@@ -317,9 +312,9 @@ namespace Org.BouncyCastle.Crypto.Encodings
             byte[] C = new byte[4];
             int counter = 0;
 
-            hash.Reset();
+            mgf1Hash.Reset();
 
-            do
+            while (counter < (length / hashBuf.Length))
             {
                 ItoOSP(counter, C);
 
@@ -328,8 +323,9 @@ namespace Org.BouncyCastle.Crypto.Encodings
                 mgf1Hash.DoFinal(hashBuf, 0);
 
                 Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length);
+
+                counter++;
             }
-            while (++counter < (length / hashBuf.Length));
 
             if ((counter * hashBuf.Length) < length)
             {
diff --git a/crypto/src/crypto/encodings/Pkcs1Encoding.cs b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
index 35fd96abe..b2d60fe4c 100644
--- a/crypto/src/crypto/encodings/Pkcs1Encoding.cs
+++ b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -45,16 +45,18 @@ namespace Org.BouncyCastle.Crypto.Encodings
         }
 
 
-        private SecureRandom			random;
-        private IAsymmetricBlockCipher	engine;
-        private bool					forEncryption;
-        private bool					forPrivateKey;
-        private bool					useStrictLength;
-        private int                     pLen = -1;
-        private byte[]                  fallback = null;
+        private SecureRandom random;
+        private IAsymmetricBlockCipher engine;
+        private bool forEncryption;
+        private bool forPrivateKey;
+        private bool useStrictLength;
+        private int pLen = -1;
+        private byte[] fallback = null;
+        private byte[] blockBuffer = null;
 
         /**
          * Basic constructor.
+         *
          * @param cipher
          */
         public Pkcs1Encoding(
@@ -104,9 +106,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             get { return engine.AlgorithmName + "/PKCS1Padding"; }
         }
 
-        public void Init(
-            bool				forEncryption,
-            ICipherParameters	parameters)
+        public void Init(bool forEncryption, ICipherParameters parameters)
         {
             AsymmetricKeyParameter kParam;
             if (parameters is ParametersWithRandom)
@@ -126,6 +126,10 @@ namespace Org.BouncyCastle.Crypto.Encodings
 
             this.forPrivateKey = kParam.IsPrivate;
             this.forEncryption = forEncryption;
+            this.blockBuffer = new byte[engine.GetOutputBlockSize()];
+
+            if (pLen > 0 && fallback == null && random == null)
+                throw new ArgumentException("encoder requires random");
         }
 
         public int GetInputBlockSize()
@@ -255,7 +259,6 @@ namespace Org.BouncyCastle.Crypto.Encodings
          * @param inLen Length of the encrypted block.
          * @param pLen Length of the desired output.
          * @return The plaintext without padding, or a random value if the padding was incorrect.
-         * 
          * @throws InvalidCipherTextException
          */
         private byte[] DecodeBlockOrRandom(byte[] input, int inOff, int inLen)
@@ -264,7 +267,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
                 throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
 
             byte[] block = engine.ProcessBlock(input, inOff, inLen);
-            byte[] random = null;
+            byte[] random;
             if (this.fallback == null)
             {
                 random = new byte[this.pLen];
@@ -275,37 +278,25 @@ namespace Org.BouncyCastle.Crypto.Encodings
                 random = fallback;
             }
 
-            /*
-             * TODO: This is a potential dangerous side channel. However, you can
-             * fix this by changing the RSA engine in a way, that it will always
-             * return blocks of the same length and prepend them with 0 bytes if
-             * needed.
-             */
-            if (block.Length < GetOutputBlockSize())
-                throw new InvalidCipherTextException("block truncated");
+            byte[] data = (useStrictLength & (block.Length != engine.GetOutputBlockSize())) ? blockBuffer : block;
 
-            /*
-             * TODO: Potential side channel. Fix it by making the engine always
-             * return blocks of the correct length.
-             */
-            if (useStrictLength && block.Length != engine.GetOutputBlockSize())
-                throw new InvalidCipherTextException("block incorrect size");
-
-            /*
-             * Check the padding.
-             */
-            int correct = Pkcs1Encoding.CheckPkcs1Encoding(block, this.pLen);
+		    /*
+		     * Check the padding.
+		     */
+            int correct = CheckPkcs1Encoding(data, this.pLen);
 
-            /*
-             * Now, to a constant time constant memory copy of the decrypted value
-             * or the random value, depending on the validity of the padding.
-             */
+		    /*
+		     * Now, to a constant time constant memory copy of the decrypted value
+		     * or the random value, depending on the validity of the padding.
+		     */
             byte[] result = new byte[this.pLen];
             for (int i = 0; i < this.pLen; i++)
             {
-                result[i] = (byte)((block[i+(block.Length-pLen)]&(~correct)) | (random[i]&correct));
+                result[i] = (byte)((data[i + (data.Length - pLen)] & (~correct)) | (random[i] & correct));
             }
 
+            Arrays.Fill(data, 0);
+
             return result;
         }
 
@@ -327,56 +318,67 @@ namespace Org.BouncyCastle.Crypto.Encodings
             }
 
             byte[] block = engine.ProcessBlock(input, inOff, inLen);
+            bool incorrectLength = (useStrictLength & (block.Length != engine.GetOutputBlockSize()));
 
+            byte[] data;
             if (block.Length < GetOutputBlockSize())
             {
-                throw new InvalidCipherTextException("block truncated");
+                data = blockBuffer;
             }
-
-            byte type = block[0];
-
-            if (type != 1 && type != 2)
+            else
             {
-                throw new InvalidCipherTextException("unknown block type");
+                data = block;
             }
 
-            if (useStrictLength && block.Length != engine.GetOutputBlockSize())
-            {
-                throw new InvalidCipherTextException("block incorrect size");
-            }
+            byte expectedType = (byte)(forPrivateKey ? 2 : 1);
+            byte type = data[0];
+
+            bool badType = (type != expectedType);
 
             //
             // find and extract the message block.
             //
-            int start;
-            for (start = 1; start != block.Length; start++)
-            {
-                byte pad = block[start];
+            int start = FindStart(type, data);
 
-                if (pad == 0)
-                {
-                    break;
-                }
+            start++;           // data should start at the next byte
 
-                if (type == 1 && pad != (byte)0xff)
-                {
-                    throw new InvalidCipherTextException("block padding incorrect");
-                }
+            if (badType | (start < HeaderLength))
+            {
+                Arrays.Fill(data, 0);
+                throw new InvalidCipherTextException("block incorrect");
             }
 
-            start++;           // data should start at the next byte
-
-            if (start > block.Length || start < HeaderLength)
+            // if we get this far, it's likely to be a genuine encoding error
+            if (incorrectLength)
             {
-                throw new InvalidCipherTextException("no data in block");
+                Arrays.Fill(data, 0);
+                throw new InvalidCipherTextException("block incorrect size");
             }
 
-            byte[] result = new byte[block.Length - start];
+            byte[] result = new byte[data.Length - start];
 
-            Array.Copy(block, start, result, 0, result.Length);
+            Array.Copy(data, start, result, 0, result.Length);
 
             return result;
         }
-    }
 
+        private int FindStart(byte type, byte[] block)
+        {
+            int start = -1;
+            bool padErr = false;
+
+            for (int i = 1; i != block.Length; i++)
+            {
+                byte pad = block[i];
+
+                if (pad == 0 & start < 0)
+                {
+                    start = i;
+                }
+                padErr |= ((type == 1) & (start < 0) & (pad != (byte)0xff));
+            }
+
+            return padErr ? -1 : start;
+        }
+    }
 }
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index ba62af4da..91bdf69ef 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -429,6 +429,8 @@ namespace Org.BouncyCastle.Crypto.Engines
         private uint C0, C1, C2, C3;
         private bool forEncryption;
 
+        private byte[] s;
+
         private const int BLOCK_SIZE = 16;
 
         /**
@@ -459,6 +461,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
 
             this.forEncryption = forEncryption;
+            this.s = Arrays.Clone(forEncryption ? S : Si);
         }
 
         public virtual string AlgorithmName
@@ -560,10 +563,10 @@ namespace Org.BouncyCastle.Crypto.Engines
             // the final round's table is a simple function of S so we don't use a whole other four tables for it
 
             kw = KW[r];
-            this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
-            this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
-            this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
-            this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+            this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[0];
+            this.C1 = (uint)s[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[1];
+            this.C2 = (uint)s[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+            this.C3 = (uint)s[r3 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
         }
 
         private void DecryptBlock(uint[][] KW)
@@ -598,10 +601,10 @@ namespace Org.BouncyCastle.Crypto.Engines
             // the final round's table is a simple function of Si so we don't use a whole other four tables for it
 
             kw = KW[0];
-            this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
-            this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
-            this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
-            this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
+            this.C0 = (uint)Si[r0 & 255] ^ (((uint)s[(r3 >> 8) & 255]) << 8) ^ (((uint)s[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+            this.C1 = (uint)s[r1 & 255] ^ (((uint)s[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)s[(r2 >> 24) & 255]) << 24) ^ kw[1];
+            this.C2 = (uint)s[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)s[(r3 >> 24) & 255]) << 24) ^ kw[2];
+            this.C3 = (uint)Si[r3 & 255] ^ (((uint)s[(r2 >> 8) & 255]) << 8) ^ (((uint)s[(r1 >> 16) & 255]) << 16) ^ (((uint)s[(r0 >> 24) & 255]) << 24) ^ kw[3];
         }
     }
 }
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index 3a9c3a89e..9d3a86fd2 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -31,6 +31,11 @@ namespace Org.BouncyCastle.Crypto.Engines
     * This file contains the fast version with 8Kbytes of static tables for round precomputation
     * </p>
     */
+    /// <remarks>
+    /// Unfortunately this class has a few side channel issues.
+    /// In an environment where encryption/decryption may be closely observed it should not be used.
+    /// </remarks>
+    [Obsolete("Use AesEngine instead")]
     public class AesFastEngine
         : IBlockCipher
     {
diff --git a/crypto/src/crypto/engines/ChaCha7539Engine.cs b/crypto/src/crypto/engines/ChaCha7539Engine.cs
index 5a12be016..af4163a02 100644
--- a/crypto/src/crypto/engines/ChaCha7539Engine.cs
+++ b/crypto/src/crypto/engines/ChaCha7539Engine.cs
@@ -19,7 +19,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         public override string AlgorithmName
         {
-            get { return "ChaCha" + rounds; }
+            get { return "ChaCha7539" + rounds; }
         }
 
         protected override int NonceSize
diff --git a/crypto/src/crypto/engines/Dstu7624Engine.cs b/crypto/src/crypto/engines/Dstu7624Engine.cs
new file mode 100644
index 000000000..422b5574a
--- /dev/null
+++ b/crypto/src/crypto/engines/Dstu7624Engine.cs
@@ -0,0 +1,855 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * implementation of DSTU 7624 (Kalyna)
+    */
+    public class Dstu7624Engine
+         : IBlockCipher
+    {
+        private static readonly int BITS_IN_WORD = 64;
+        private static readonly int BITS_IN_BYTE = 8;
+
+        private static readonly int REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */
+
+        private ulong[] internalState;
+        private ulong[] workingKey;
+        private ulong[][] roundKeys;
+
+        /* Number of 64-bit words in block */
+        private int wordsInBlock;
+
+        /* Number of 64-bit words in key */
+        private int wordsInKey;
+
+        /* Number of encryption rounds depending on key length */
+        private static int ROUNDS_128 = 10;
+        private static int ROUNDS_256 = 14;
+        private static int ROUNDS_512 = 18;
+
+        private int blockSizeBits;
+        private int roundsAmount;
+
+        private bool forEncryption;
+
+        private byte[] internalStateBytes;
+        private byte[] tempInternalStateBytes;
+
+        public Dstu7624Engine(int blockSizeBits)
+        {
+            /* DSTU7624 supports 128 | 256 | 512 key/block sizes */
+            if (blockSizeBits != 128 && blockSizeBits != 256 && blockSizeBits != 512)
+            {
+                throw new ArgumentException("Unsupported block length: only 128/256/512 are allowed");
+            }
+            this.blockSizeBits = blockSizeBits;
+
+            wordsInBlock = blockSizeBits / BITS_IN_WORD;
+            internalState = new ulong[wordsInBlock];
+
+            internalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE];
+            tempInternalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE];
+        }
+
+        #region INITIALIZATION
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
+        {
+            if (parameters is KeyParameter)
+            {
+                this.forEncryption = forEncryption;
+
+                byte[] keyBytes = ((KeyParameter)parameters).GetKey();
+                int keyBitLength = keyBytes.Length * BITS_IN_BYTE;
+                int blockBitLength = wordsInBlock * BITS_IN_WORD;
+
+                if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512)
+                {
+                    throw new ArgumentException("unsupported key length: only 128/256/512 are allowed");
+                }
+
+                /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */
+                if (blockBitLength == 128)
+                {
+                    if (keyBitLength == 512)
+                    {
+                        throw new ArgumentException("Unsupported key length");
+                    }
+                }
+
+                if (blockBitLength == 256)
+                {
+                    if (keyBitLength == 128)
+                    {
+                        throw new ArgumentException("Unsupported key length");
+                    }
+                }
+
+                if (blockBitLength == 512)
+                {
+                    if (keyBitLength != 512)
+                    {
+                        throw new ArgumentException("Unsupported key length");
+                    }
+                }
+
+                switch (keyBitLength)
+                {
+                    case 128:
+                        roundsAmount = ROUNDS_128;
+                        break;
+                    case 256:
+                        roundsAmount = ROUNDS_256;
+                        break;
+                    case 512:
+                        roundsAmount = ROUNDS_512;
+                        break;
+                }
+
+                wordsInKey = keyBitLength / BITS_IN_WORD;
+
+                /* +1 round key as defined in standard */
+                roundKeys = new ulong[roundsAmount + 1][];
+                for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++)
+                {
+                    roundKeys[roundKeyIndex] = new ulong[wordsInBlock];
+                }
+
+                workingKey = new ulong[wordsInKey];
+
+                if (keyBytes.Length != wordsInKey * BITS_IN_WORD / BITS_IN_BYTE)
+                {
+                    throw new ArgumentException("Invalid key parameter passed to DSTU7624Engine init");
+                }
+
+                /* Unpack encryption key bytes to words */
+                Pack.LE_To_UInt64(keyBytes, 0, workingKey);
+
+                ulong[] kt = new ulong[wordsInBlock];
+
+                KeyExpandKT(workingKey, kt);
+
+                KeyExpandEven(workingKey, kt);
+
+                KeyExpandOdd();
+
+            }
+            else if (parameters != null)
+            {
+                throw new ArgumentException("invalid parameter passed to Dstu7624 init - "
+                + Platform.GetTypeName(parameters));
+            }
+
+            this.forEncryption = forEncryption;
+        }
+
+        private void KeyExpandKT(ulong[] key, ulong[] kt)
+        {
+            ulong[] k0 = new ulong[wordsInBlock];
+            ulong[] k1 = new ulong[wordsInBlock];
+
+            internalState = new ulong[wordsInBlock];
+            internalState[0] += (ulong)(wordsInBlock + wordsInKey + 1);
+
+            if (wordsInBlock == wordsInKey)
+            {
+                Array.Copy(key, k0, k0.Length);
+                Array.Copy(key, k1, k1.Length);
+            }
+            else
+            {
+                Array.Copy(key, 0, k0, 0, wordsInBlock);
+                Array.Copy(key, wordsInBlock, k1, 0, wordsInBlock);
+            }
+
+            AddRoundKeyExpand(k0);
+
+            EncryptionRound();
+
+            XorRoundKeyExpand(k1);
+
+            EncryptionRound();
+
+            AddRoundKeyExpand(k0);
+
+            EncryptionRound();
+
+            Array.Copy(internalState, kt, wordsInBlock);
+        }
+
+        private void KeyExpandEven(ulong[] key, ulong[] kt)
+        {
+            ulong[] initial_data = new ulong[wordsInKey];
+
+            ulong[] kt_round = new ulong[wordsInBlock];
+
+            ulong[] tmv = new ulong[wordsInBlock];
+
+            int round = 0;
+
+            Array.Copy(key, initial_data, wordsInKey);
+
+            for (int i = 0; i < wordsInBlock; i++)
+            {
+                tmv[i] = 0x0001000100010001;
+            }
+
+            while (true)
+            {
+                Array.Copy(kt, internalState, wordsInBlock);
+
+                AddRoundKeyExpand(tmv);
+
+                Array.Copy(internalState, kt_round, wordsInBlock);
+                Array.Copy(initial_data, internalState, wordsInBlock);
+
+                AddRoundKeyExpand(kt_round);
+
+                EncryptionRound();
+
+                XorRoundKeyExpand(kt_round);
+
+                EncryptionRound();
+
+                AddRoundKeyExpand(kt_round);
+
+                Array.Copy(internalState, roundKeys[round], wordsInBlock);
+
+                if (roundsAmount == round)
+                {
+                    break;
+                }
+                if (wordsInKey != wordsInBlock)
+                {
+                    round += 2;
+
+                    ShiftLeft(tmv);
+
+                    Array.Copy(kt, internalState, wordsInBlock);
+
+                    AddRoundKeyExpand(tmv);
+
+                    Array.Copy(internalState, kt_round, wordsInBlock);
+                    Array.Copy(initial_data, wordsInBlock, internalState, 0, wordsInBlock);
+
+                    AddRoundKeyExpand(kt_round);
+
+                    EncryptionRound();
+
+                    XorRoundKeyExpand(kt_round);
+
+                    EncryptionRound();
+
+                    AddRoundKeyExpand(kt_round);
+
+                    Array.Copy(internalState, roundKeys[round], wordsInBlock);
+
+                    if (roundsAmount == round)
+                    {
+                        break;
+                    }
+                }
+
+                round += 2;
+                ShiftLeft(tmv);
+
+                //Rotate initial data array on 1 element left
+                ulong temp = initial_data[0];
+                Array.Copy(initial_data, 1, initial_data, 0, initial_data.Length - 1);
+                initial_data[initial_data.Length - 1] = temp;
+            }
+        }
+        private void KeyExpandOdd()
+        {
+            for (int i = 1; i < roundsAmount; i += 2)
+            {
+                Array.Copy(roundKeys[i - 1], roundKeys[i], wordsInBlock);
+                RotateLeft(roundKeys[i]);
+            }
+        }
+        #endregion
+
+
+        public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+        {
+            if (workingKey == null)
+                throw new InvalidOperationException("Dstu7624 engine not initialised");
+
+            Check.DataLength(input, inOff, GetBlockSize(), "input buffer too short");
+            Check.OutputLength(output, outOff, GetBlockSize(), "output buffer too short");
+
+            if (forEncryption)
+            {
+                Encrypt(input, inOff, output, outOff);
+            }
+            else
+            {
+                Decrypt(input, inOff, output, outOff);
+            }
+
+            return GetBlockSize();
+        }
+
+        private void Encrypt(byte[] plain, int inOff, byte[] cipherText, int outOff)
+        {
+            int round = 0;
+
+            Array.Copy(plain, inOff, plain, 0, blockSizeBits / BITS_IN_BYTE);
+            Array.Resize(ref plain, blockSizeBits / BITS_IN_BYTE);
+            
+            ulong[] plain_ = BytesToWords(plain);
+
+            Array.Copy(plain_, internalState, wordsInBlock);
+
+            AddRoundKey(round);
+
+            for (round = 1; round < roundsAmount; round++)
+            {
+                EncryptionRound();
+
+                XorRoundKey(round);
+
+            }
+            EncryptionRound();
+
+            AddRoundKey(roundsAmount);
+
+            ulong[] cipherText_ = new ulong[internalState.Length];
+
+            Array.Copy(internalState, cipherText_, wordsInBlock);
+
+            byte[] temp = WordsToBytes(cipherText_);
+
+            Array.Copy(temp, 0, cipherText, outOff, temp.Length);
+
+        }
+        private void Decrypt(byte[] cipherText, int inOff, byte[] decryptedText, int outOff)
+        {
+            Array.Copy(cipherText, inOff, cipherText, 0, blockSizeBits / BITS_IN_BYTE);
+            Array.Resize(ref cipherText, blockSizeBits / BITS_IN_BYTE);
+
+            int round = roundsAmount;
+
+            ulong[] cipherText_ = BytesToWords(cipherText);
+
+            Array.Copy(cipherText_, internalState, wordsInBlock);
+
+            SubRoundKey(round);
+
+            for (round = roundsAmount - 1; round > 0; round--)
+            {
+                DecryptionRound();
+                XorRoundKey(round);
+            }
+
+            DecryptionRound();
+            SubRoundKey(0);
+
+            ulong[] decryptedText_ = new ulong[internalState.Length];
+
+            Array.Copy(internalState, decryptedText_, wordsInBlock);
+
+
+            byte[] temp = WordsToBytes(decryptedText_);
+            Array.Copy(temp, 0, decryptedText, outOff, temp.Length);
+
+            
+        }
+
+
+
+
+
+
+
+
+
+        private void AddRoundKeyExpand(ulong[] value)
+        {
+            for (int i = 0; i < wordsInBlock; i++)
+            {
+                internalState[i] += value[i];
+            }
+        }
+
+        private void EncryptionRound()
+        {
+            SubBytes();
+            ShiftRows();
+            MixColumns();
+        }
+
+        private void DecryptionRound()
+        {
+            InvMixColumns();
+            InvShiftRows();
+            InvSubBytes();
+        }
+
+        private void RotateLeft(ulong[] state_value)
+        {
+            int rotateBytesLength = 2 * state_value.Length + 3;
+            int bytesLength = state_value.Length * (BITS_IN_WORD / BITS_IN_BYTE);
+
+
+            byte[] bytes = WordsToBytes(state_value);
+            byte[] buffer = new byte[rotateBytesLength];
+
+            Array.Copy(bytes, buffer, rotateBytesLength);
+
+            Buffer.BlockCopy(bytes, rotateBytesLength, bytes, 0, bytesLength - rotateBytesLength);
+
+            Array.Copy(buffer, 0, bytes, bytesLength - rotateBytesLength, rotateBytesLength);
+
+            var temp = BytesToWords(bytes);
+            Array.Copy(temp, state_value, state_value.Length);
+        }
+
+        private void ShiftLeft(ulong[] state_value)
+        {
+            for (int i = 0; i < state_value.Length; i++)
+            {
+                state_value[i] <<= 1;
+            }
+            Array.Reverse(state_value);
+        }
+
+        private void XorRoundKeyExpand(ulong[] value)
+        {
+            for (int i = 0; i < wordsInBlock; i++)
+            {
+                internalState[i] ^= value[i];
+            }
+        }
+
+        private void XorRoundKey(int round)
+        {
+            for (int i = 0; i < wordsInBlock; i++)
+            {
+                internalState[i] ^= roundKeys[round][i];
+            }
+        }
+
+        private void ShiftRows()
+        {
+            int row, col;
+            int shift = -1;
+
+            byte[] stateBytes = WordsToBytes(internalState);
+
+            byte[] nstate = new byte[wordsInBlock * sizeof(ulong)];
+
+            for (row = 0; row < sizeof(ulong); row++)
+            {
+                if (row % (sizeof(ulong) / wordsInBlock) == 0)
+                {
+                    shift += 1;
+                }
+
+                for (col = 0; col < wordsInBlock; col++)
+                {
+                    nstate[row + ((col + shift) % wordsInBlock) * sizeof(ulong)] = stateBytes[row + col * sizeof(ulong)];
+                }
+            }
+
+            internalState = BytesToWords(nstate);
+
+        }
+
+        private void InvShiftRows()
+        {
+            int row, col;
+            int shift = -1;
+
+            byte[] stateBytes = WordsToBytes(internalState);
+            byte[] nstate = new byte[wordsInBlock * sizeof(ulong)];
+
+            for (row = 0; row < sizeof(ulong); row++)
+            {
+                if (row % (sizeof(ulong) / wordsInBlock) == 0)
+                {
+                    shift += 1;
+                }
+
+                for (col = 0; col < wordsInBlock; col++)
+                {
+                    nstate[row + col * sizeof(ulong)] = stateBytes[row + ((col + shift) % wordsInBlock) * sizeof(ulong)];
+                }
+            }
+
+            internalState = BytesToWords(nstate);
+        }
+
+        private ulong[] BytesToWords(byte[] bytes)
+        {
+            ulong[] words = new ulong[bytes.Length / sizeof(ulong)];
+
+            for (int i = 0; i < words.Length; i++)
+            {
+                words[i] = BitConverter.ToUInt64(bytes, i * sizeof(ulong));
+
+                if (!BitConverter.IsLittleEndian)
+                {
+                    words[i] = ReverseWord(words[i]);
+                }
+            }
+
+            return words;
+        }
+
+        private byte[] WordsToBytes(ulong[] words)
+        {
+            byte[] bytes = new byte[words.Length * sizeof(ulong)];
+
+            byte[] tempBytes = new byte[sizeof(ulong)];
+
+            for (int i = 0; i < words.Length; ++i)
+            {
+                if (!BitConverter.IsLittleEndian)
+                {
+                    words[i] = ReverseWord(words[i]);
+                }
+
+                tempBytes = BitConverter.GetBytes(words[i]);
+                Array.Copy(tempBytes, 0, bytes, i * tempBytes.Length, tempBytes.Length);
+            }
+            return bytes;
+        }
+
+        private ulong ReverseWord(ulong x)
+        {
+            byte[] bytes = BitConverter.GetBytes(x);
+            Array.Reverse(bytes);
+            return BitConverter.ToUInt64(bytes, 0);
+        }
+
+        private void AddRoundKey(int round)
+        {
+            for (int i = 0; i < wordsInBlock; ++i)
+            {
+                internalState[i] += roundKeys[round][i];
+            }
+        }
+
+        private void SubRoundKey(int round)
+        {
+            for (int i = 0; i < wordsInBlock; ++i)
+            {
+                internalState[i] -= roundKeys[round][i];
+            }
+        }
+
+        private void MixColumns()
+        {
+            MatrixMultiply(mdsMatrix);
+        }
+
+        private void InvMixColumns()
+        {
+            MatrixMultiply(mdsInvMatrix);
+        }
+
+        private void MatrixMultiply(byte[][] matrix)
+        {
+            int col, row, b;
+            byte product;
+            ulong result;
+            byte[] stateBytes = WordsToBytes(internalState);
+
+            for (col = 0; col < wordsInBlock; ++col)
+            {
+                result = 0;
+                for (row = sizeof(ulong) - 1; row >= 0; --row)
+                {
+                    product = 0;
+                    for (b = sizeof(ulong) - 1; b >= 0; --b)
+                    {
+                        product ^= MultiplyGF(stateBytes[b + col * sizeof(ulong)], matrix[row][b]);
+                    }
+                    result |= (ulong)product << (row * sizeof(ulong));
+                }
+                internalState[col] = result;
+            }
+        }
+
+        private byte MultiplyGF(byte x, byte y)
+        {
+            byte r = 0;
+            byte hbit = 0;
+
+            for (int i = 0; i < BITS_IN_BYTE; i++)
+            {
+                if ((y & 0x01) == 1)
+                {
+                    r ^= x;
+                }
+
+                hbit = (byte)(x & 0x80);
+
+                x <<= 1;
+
+                if (hbit == 0x80)
+                {
+                    x = (byte)((int)x ^ REDUCTION_POLYNOMIAL);
+                }
+                y >>= 1;
+            }
+            return r;
+        }
+
+        private void SubBytes()
+        {
+            for (int i = 0; i < wordsInBlock; i++)
+            {
+                internalState[i] = sboxesForEncryption[0][internalState[i] & 0x00000000000000FF] |
+                           ((ulong)sboxesForEncryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) |
+                           ((ulong)sboxesForEncryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) |
+                           ((ulong)sboxesForEncryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) |
+                           ((ulong)sboxesForEncryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) |
+                           ((ulong)sboxesForEncryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) |
+                           ((ulong)sboxesForEncryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) |
+                           ((ulong)sboxesForEncryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56);
+            }
+        }
+
+        private void InvSubBytes()
+        {
+            for (int i = 0; i < wordsInBlock; i++)
+            {
+                internalState[i] = sboxesForDecryption[0][internalState[i] & 0x00000000000000FF] |
+                           ((ulong)sboxesForDecryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) |
+                           ((ulong)sboxesForDecryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) |
+                           ((ulong)sboxesForDecryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) |
+                           ((ulong)sboxesForDecryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) |
+                           ((ulong)sboxesForDecryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) |
+                           ((ulong)sboxesForDecryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) |
+                           ((ulong)sboxesForDecryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56);
+            }
+        }
+
+
+        #region TABLES AND S-BOXES
+
+        private byte[][] mdsMatrix = 
+          {
+               new byte[] { 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04 },
+               new byte[] { 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07 },
+               new byte[] { 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06 },
+               new byte[] { 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08 },
+               new byte[] { 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01 },
+               new byte[] { 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05 },
+               new byte[] { 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01 },
+               new byte[] { 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01 },
+          };
+
+        private byte[][] mdsInvMatrix = 
+          {
+               new byte[] { 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA },
+               new byte[] { 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7 },
+               new byte[] { 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49 },
+               new byte[] { 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F },
+               new byte[] { 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8 },
+               new byte[] { 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76 },
+               new byte[] { 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95 },
+               new byte[] { 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD },
+          };
+
+
+        private byte[][] sboxesForEncryption = 
+          {
+               new byte[]
+               {
+                    0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09, 
+                    0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39, 
+                    0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6, 
+                    0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1, 
+                    0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27, 
+                    0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41, 
+                    0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e, 
+                    0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55, 
+                    0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff, 
+                    0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1, 
+                    0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76, 
+                    0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26, 
+                    0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82, 
+                    0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8, 
+                    0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d, 
+                    0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80 
+               },
+
+               new byte[]
+               {
+                    0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8, 
+                    0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d, 
+                    0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d, 
+                    0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc, 
+                    0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee, 
+                    0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca, 
+                    0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20, 
+                    0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f, 
+                    0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51, 
+                    0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98, 
+                    0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9, 
+                    0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05, 
+                    0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82, 
+                    0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad, 
+                    0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59, 
+                    0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7 
+               },
+
+               new byte[]
+               {
+                    0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59, 
+                    0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1, 
+                    0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72, 
+                    0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90, 
+                    0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35, 
+                    0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48, 
+                    0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38, 
+                    0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33, 
+                    0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29, 
+                    0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83, 
+                    0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2, 
+                    0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43, 
+                    0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82, 
+                    0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91, 
+                    0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44, 
+                    0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67 
+               },
+
+               new byte[]
+               {
+                    0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f, 
+                    0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd, 
+                    0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66, 
+                    0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf, 
+                    0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99, 
+                    0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71, 
+                    0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60, 
+                    0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b, 
+                    0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09, 
+                    0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2, 
+                    0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7, 
+                    0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a, 
+                    0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39, 
+                    0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef, 
+                    0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36, 
+                    0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61 
+               }
+
+          };
+
+
+        private byte[][] sboxesForDecryption = 
+          {
+               new byte[]
+               {
+	               0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b, 
+	               0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28, 
+	               0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0, 
+	               0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c, 
+	               0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23, 
+	               0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02, 
+	               0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c, 
+	               0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7, 
+	               0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c, 
+	               0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d, 
+	               0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17, 
+	               0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29, 
+	               0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec, 
+	               0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09, 
+	               0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1, 
+	               0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f
+               },
+
+               new byte[]
+               {
+                    0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29, 
+                    0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc, 
+                    0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2, 
+                    0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76, 
+                    0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8, 
+                    0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f, 
+                    0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c, 
+                    0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9, 
+                    0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99, 
+                    0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38, 
+                    0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7, 
+                    0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87, 
+                    0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b, 
+                    0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c, 
+                    0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4, 
+                    0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa
+               },
+
+               new byte[]
+               {
+                    0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95, 
+                    0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3, 
+                    0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a, 
+                    0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85, 
+                    0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52, 
+                    0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5, 
+                    0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb, 
+                    0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7, 
+                    0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62, 
+                    0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c, 
+                    0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d, 
+                    0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3, 
+                    0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91, 
+                    0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a, 
+                    0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49, 
+                    0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1
+               },
+
+               new byte[]
+               {
+                    0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3, 
+                    0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f, 
+                    0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21, 
+                    0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba, 
+                    0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49, 
+                    0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66, 
+                    0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4, 
+                    0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8, 
+                    0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85, 
+                    0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91, 
+                    0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb, 
+                    0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d, 
+                    0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d, 
+                    0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f, 
+                    0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf, 
+                    0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d
+               }
+          };
+        #endregion
+
+
+
+        public virtual string AlgorithmName
+        {
+            get { return "Dstu7624"; }
+        }
+
+        public virtual int GetBlockSize()
+        {
+            return blockSizeBits / BITS_IN_BYTE;
+        }
+
+        public virtual bool IsPartialBlockOkay
+        {
+            get { return false; }
+        }
+
+        public virtual void Reset()
+        {
+
+        }
+
+    }
+}
diff --git a/crypto/src/crypto/engines/Dstu7624WrapEngine.cs b/crypto/src/crypto/engines/Dstu7624WrapEngine.cs
new file mode 100644
index 000000000..5d21f6e85
--- /dev/null
+++ b/crypto/src/crypto/engines/Dstu7624WrapEngine.cs
@@ -0,0 +1,263 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using System.Collections.Generic;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+     public class Dstu7624WrapEngine : IWrapper 
+     {
+          private const int BYTES_IN_INTEGER = 4;
+
+          private KeyParameter param;
+          private Dstu7624Engine engine;
+          private bool forWrapping;
+          private int blockSize;
+
+          private byte[] buffer;
+          private byte[] intArray;
+
+          private readonly byte[] checkSumArray, zeroArray;
+
+
+          public Dstu7624WrapEngine(int blockSizeBits)
+          {
+               engine = new Dstu7624Engine(blockSizeBits);
+               param = null;
+           
+               blockSize = blockSizeBits / 8;
+               buffer = new byte[blockSize];
+               
+               intArray = new byte[BYTES_IN_INTEGER];
+
+               checkSumArray = new byte[blockSize];
+               zeroArray = new byte[blockSize];
+          }
+          
+
+          public string AlgorithmName
+          {
+               get { return "Dstu7624WrapEngine"; }
+          }
+
+          public void Init(bool forWrapping, ICipherParameters parameters)
+          {
+               this.forWrapping = forWrapping;
+                            
+               if (parameters is KeyParameter)
+               {
+                    this.param = (KeyParameter)parameters;
+
+                    engine.Init(forWrapping, param);
+               }
+               else
+               {
+                    throw new ArgumentException("Bad parameters passed to Dstu7624WrapEngine");
+               }
+          }
+
+          public byte[] Wrap(byte[] input, int inOff, int length)
+          {
+               if (!forWrapping)
+               {
+                    throw new InvalidOperationException("Not set for wrapping");
+               }
+
+               if ((input.Length - inOff) % blockSize != 0)
+               {
+                    throw new ArgumentException("Padding not supported");
+               }
+
+               int n = 2 * (1 + input.Length / blockSize);
+               
+               int V = (n - 1) * 6;
+
+               buffer = new byte[input.Length - inOff + blockSize];
+               Array.Copy(input, inOff, buffer, 0, input.Length - inOff);
+               //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+
+               
+
+               byte[] B = new byte[blockSize / 2];
+               Array.Copy(buffer, 0, B, 0, blockSize / 2);
+               //Console.WriteLine("B0: "+ Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+               
+               
+               List<byte[]> bTemp = new List<byte[]>();
+              
+               int bHalfBlocksLen = buffer.Length - blockSize  / 2;
+               int bufOff = blockSize / 2;
+               while (bHalfBlocksLen != 0)
+               {                    
+                    byte[] temp = new byte[blockSize / 2];
+                    Array.Copy(buffer, bufOff, temp, 0, blockSize / 2);
+                    //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+                    //Console.WriteLine(buffer.Length);
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(temp));
+                    
+                    bTemp.Add(temp);
+
+                    bHalfBlocksLen -= blockSize / 2;
+                    bufOff += blockSize / 2;
+               }
+
+                                       
+
+               for (int j = 0; j < V; j++)
+               {
+                    Array.Copy(B, 0, buffer, 0, blockSize / 2);
+                    Array.Copy(bTemp[0], 0, buffer, blockSize / 2, blockSize / 2);
+
+                    engine.ProcessBlock(buffer, 0, buffer, 0);
+                                        
+                    intTobytes(j + 1, intArray, 0);
+                    for (int byteNum = 0; byteNum < BYTES_IN_INTEGER; byteNum++)
+                    {
+                         buffer[byteNum + blockSize / 2] ^= intArray[byteNum];
+                    }
+
+                    Array.Copy(buffer, blockSize / 2, B, 0, blockSize / 2);
+                    
+                    for (int i = 2; i < n; i++)
+                    {                        
+                         Array.Copy(bTemp[i - 1], 0, bTemp[i - 2], 0, blockSize / 2);
+                    }
+
+                    Array.Copy(buffer, 0, bTemp[n - 2], 0, blockSize / 2);
+
+                    //Console.WriteLine("B" + j.ToString() + ": " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[0]));
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[1]));
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[2]));
+
+                    //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+               }
+
+
+               Array.Copy(B, 0, buffer, 0, blockSize / 2);
+               bufOff = blockSize / 2;
+
+               for (int i = 0; i < n - 1; i++)
+               {
+                    Array.Copy(bTemp[i], 0, buffer, bufOff, blockSize / 2);
+                    bufOff += blockSize / 2;
+               }
+
+               return buffer;
+          }
+
+          public byte[] Unwrap(byte[] input, int inOff, int length)
+          {
+               if (forWrapping)
+               {
+                    throw new InvalidOperationException("not set for unwrapping");
+               }
+
+               if ((input.Length - inOff) % blockSize != 0)
+               {
+                    throw new ArgumentException("Padding not supported");
+               }
+
+               int n = 2 * input.Length / blockSize;
+
+               int V = (n - 1) * 6;
+
+               buffer = new byte[input.Length - inOff];
+               Array.Copy(input, inOff, buffer, 0, input.Length - inOff);
+                              
+               byte[] B = new byte[blockSize / 2];
+               Array.Copy(buffer, 0, B, 0, blockSize / 2);
+               //Console.WriteLine("B18: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+               
+               List<byte[]> bTemp = new List<byte[]>();
+
+               int bHalfBlocksLen = buffer.Length - blockSize / 2;
+               int bufOff = blockSize / 2;
+               while (bHalfBlocksLen != 0)
+               {
+                    byte[] temp = new byte[blockSize / 2];
+                    Array.Copy(buffer, bufOff, temp, 0, blockSize / 2);
+                    //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+                    //Console.WriteLine(buffer.Length);
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(temp));
+
+                    bTemp.Add(temp);
+
+                    bHalfBlocksLen -= blockSize / 2;
+                    bufOff += blockSize / 2;     
+               }
+
+
+               for (int j = 0; j < V; j++)
+               {
+                    Array.Copy(bTemp[n - 2], 0, buffer, 0, blockSize / 2);
+                    Array.Copy(B, 0, buffer, blockSize / 2, blockSize / 2);
+                    intTobytes(V - j, intArray, 0);
+                    for (int byteNum = 0; byteNum < BYTES_IN_INTEGER; byteNum++)
+                    {
+                         buffer[byteNum + blockSize / 2] ^= intArray[byteNum];
+                    }
+
+                    //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+
+                    engine.ProcessBlock(buffer, 0, buffer, 0);
+
+                    //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+                                        
+                    Array.Copy(buffer, 0, B, 0, blockSize / 2);
+
+                    for (int i = 2; i < n; i++)
+                    {
+                         Array.Copy(bTemp[n - i - 1], 0, bTemp[n - i], 0, blockSize / 2);
+                    }
+
+                    Array.Copy(buffer, blockSize / 2, bTemp[0], 0, blockSize / 2);
+
+                    //Console.WriteLine("B" + (V - j - 1).ToString() + ": " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[0]));
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[1]));
+                    //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[2]));
+
+                    //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+               }
+
+
+               Array.Copy(B, 0, buffer, 0, blockSize / 2);
+               bufOff = blockSize / 2;
+
+               for (int i = 0; i < n - 1; i++)
+               {
+                    Array.Copy(bTemp[i], 0, buffer, bufOff, blockSize / 2);
+                    bufOff += blockSize / 2;
+               }
+
+               
+               Array.Copy(buffer, buffer.Length - blockSize, checkSumArray, 0, blockSize);
+
+
+               if (!Arrays.AreEqual(checkSumArray, zeroArray))
+               {
+                    throw new InvalidCipherTextException("checksum failed");
+               }
+               else
+               {
+                    Array.Resize(ref buffer, buffer.Length - blockSize);
+               }
+
+               return buffer;
+          }
+
+          //int to array of bytes
+          private static void intTobytes(
+                    int num,
+                    byte[] outBytes,
+                    int outOff)
+          {
+               outBytes[outOff + 3] = (byte)(num >> 24);
+               outBytes[outOff + 2] = (byte)(num >> 16);
+               outBytes[outOff + 1] = (byte)(num >> 8);
+               outBytes[outOff] = (byte)num;
+          }
+     }
+}
diff --git a/crypto/src/crypto/macs/DSTU7564Mac.cs b/crypto/src/crypto/macs/DSTU7564Mac.cs
new file mode 100644
index 000000000..907355487
--- /dev/null
+++ b/crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+     /// <summary>
+     /// Implementation of DSTU7564 mac mode
+     /// </summary>
+     public class Dstu7564Mac : IMac
+     {
+          private Dstu7564Digest engine;
+          private int macSize;
+
+        private ulong inputLength;
+
+        byte[] paddedKey;
+          byte[] invertedKey;
+          byte[] paddedInput;
+
+        public string AlgorithmName
+        {
+            get
+            {
+                return "DSTU7564Mac";
+            }
+        }
+
+        public Dstu7564Mac(int macSizeBits)
+          {
+            engine = new Dstu7564Digest(macSizeBits);
+            macSize = macSizeBits / 8;
+          }
+
+          public void Init(ICipherParameters parameters)
+          {
+            if (parameters is KeyParameter)
+        {
+                byte[] key = ((KeyParameter)parameters).GetKey();
+
+                invertedKey = new byte[key.Length];
+
+                paddedKey = PadKey(key);
+
+                for (int byteIndex = 0; byteIndex < invertedKey.Length; byteIndex++)
+                {
+                    invertedKey[byteIndex] = (byte)(key[byteIndex] ^ (byte)0xFF);
+                }
+            }
+        else
+        {
+                throw new ArgumentException("Bad parameter passed");
+            }
+
+            engine.BlockUpdate(paddedKey, 0, paddedKey.Length);
+        }
+
+          public int GetMacSize()
+          {
+               return macSize;
+          }
+
+          public void BlockUpdate(byte[] input, int inOff, int len)
+          {
+            if (input.Length - inOff < len)
+            {
+                throw new DataLengthException("Input buffer too short");
+            }
+
+            if (paddedKey == null)
+            {
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+            }
+
+            engine.BlockUpdate(input, inOff, len);
+            inputLength += (ulong)len;
+
+          }
+
+        public void Update(byte input)
+        {
+            engine.Update(input);
+            inputLength++;
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (output.Length - outOff < macSize)
+            {
+                throw new DataLengthException("Output buffer too short");
+            }
+            if (paddedKey == null)
+            {
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+            }
+
+            Pad();
+
+            engine.BlockUpdate(invertedKey, 0, invertedKey.Length);
+
+            inputLength = 0;
+
+            return engine.DoFinal(output, outOff);
+        }
+
+        public void Reset()
+        {
+            inputLength = 0;
+            engine.Reset();
+            if (paddedKey != null)
+            {
+                engine.BlockUpdate(paddedKey, 0, paddedKey.Length);
+            }
+        }
+
+        private void Pad()
+        {
+            int extra = engine.GetByteLength() - (int)(inputLength % (ulong)engine.GetByteLength());
+            if (extra < 13)  // terminator byte + 96 bits of length
+            {
+                extra += engine.GetByteLength();
+            }
+
+            byte[] padded = new byte[extra];
+
+            padded[0] = (byte)0x80; // Defined in standard;
+
+            // Defined in standard;
+            Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12);
+
+            engine.BlockUpdate(padded, 0, padded.Length);
+        }
+
+        private byte[] PadKey(byte[] input)
+        {
+            int paddedLen = ((input.Length + engine.GetByteLength() - 1) / engine.GetByteLength()) *engine.GetByteLength();
+
+            int extra = engine.GetByteLength() - (int)(input.Length % engine.GetByteLength());
+            if (extra < 13)  // terminator byte + 96 bits of length
+            {
+                paddedLen += engine.GetByteLength();
+            }
+
+            byte[] padded = new byte[paddedLen];
+
+            Array.Copy(input, 0, padded, 0, input.Length);
+
+            padded[input.Length] = (byte)0x80; // Defined in standard;
+            Pack.UInt32_To_LE((uint)(input.Length * 8), padded, padded.Length - 12); // Defined in standard;
+
+            return padded;
+        }
+    }
+}
diff --git a/crypto/src/crypto/macs/DSTU7624Mac.cs b/crypto/src/crypto/macs/DSTU7624Mac.cs
new file mode 100644
index 000000000..953d8164f
--- /dev/null
+++ b/crypto/src/crypto/macs/DSTU7624Mac.cs
@@ -0,0 +1,160 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+     /**
+     * implementation of DSTU 7624 MAC
+     */
+     public class Dstu7624Mac : IMac
+     {
+          private int macSize;
+                    
+          private Dstu7624Engine engine;
+          private int blockSize;
+
+          private byte[] c, cTemp, kDelta;
+          private byte[] buf;
+          private int bufOff;
+
+          public Dstu7624Mac(int blockSizeBits, int q)
+          {
+               engine = new Dstu7624Engine(blockSizeBits);
+
+               blockSize = blockSizeBits / 8;
+
+               macSize = q / 8;
+
+               c = new byte[blockSize];
+              
+               cTemp = new byte[blockSize];
+
+               kDelta = new byte[blockSize];
+               buf = new byte[blockSize];
+        }
+
+          public void Init(ICipherParameters parameters)
+          {
+               if (parameters is KeyParameter)
+               {
+                    engine.Init(true, (KeyParameter)parameters);
+
+                    engine.ProcessBlock(kDelta, 0, kDelta, 0);
+               }
+               else
+               {
+                    throw new ArgumentException("invalid parameter passed to Dstu7624Mac init - "
+                    + Platform.GetTypeName(parameters));
+               }             
+          }
+
+          public string AlgorithmName
+          {
+               get { return "Dstu7624Mac"; }
+          }
+
+          public int GetMacSize()
+          {
+               return macSize;
+          }
+
+          public void Update(byte input)
+          {
+            if (bufOff == buf.Length)
+            {
+                processBlock(buf, 0);
+                bufOff = 0;
+            }
+
+            buf[bufOff++] = input;
+        }
+
+          public void BlockUpdate(byte[] input, int inOff, int len)
+          {
+            if (len < 0)
+            {
+                throw new ArgumentException(
+                    "Can't have a negative input length!");
+            }
+
+            int blockSize = engine.GetBlockSize();
+            int gapLen = blockSize - bufOff;
+
+            if (len > gapLen)
+            {
+                Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+                processBlock(buf, 0);
+
+                bufOff = 0;
+                len -= gapLen;
+                inOff += gapLen;
+
+                while (len > blockSize)
+                {
+                    processBlock(input, inOff);
+
+                    len -= blockSize;
+                    inOff += blockSize;
+                }
+            }
+
+            Array.Copy(input, inOff, buf, bufOff, len);
+
+            bufOff += len;
+        }
+
+        private void processBlock(byte[] input, int inOff)
+        {
+            Xor(c, 0, input, inOff, cTemp);
+
+            engine.ProcessBlock(cTemp, 0, c, 0);
+        }
+
+        private void Xor(byte[] c, int cOff, byte[] input, int inOff, byte[] xorResult)
+          {
+               for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
+               {
+                    xorResult[byteIndex] = (byte)(c[byteIndex + cOff] ^ input[byteIndex + inOff]);
+               }
+          }
+
+          public int DoFinal(byte[] output, int outOff)
+          {
+            if (bufOff % buf.Length != 0)
+            {
+                throw new DataLengthException("Input must be a multiple of blocksize");
+            }
+
+            //Last block
+            Xor(c, 0, buf, 0, cTemp);
+            Xor(cTemp, 0, kDelta, 0, c);
+            engine.ProcessBlock(c, 0, c, 0);
+
+            if (macSize + outOff > output.Length)
+            {
+                throw new DataLengthException("Output buffer too short");
+            }
+
+            Array.Copy(c, 0, output, outOff, macSize);
+
+            return macSize;
+        }
+
+          public void Reset()
+          {
+            Arrays.Fill(c, (byte)0x00);
+            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/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 9d940fe75..a6cd00401 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -23,7 +23,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         // These fields are set by Init and not modified by processing
         private bool        forEncryption;
+        private bool        initialised;
         private int         macSize;
+        private byte[]      lastKey;
         private byte[]      nonce;
         private byte[]      initialAssociatedText;
         private byte[]      H;
@@ -90,14 +92,16 @@ namespace Org.BouncyCastle.Crypto.Modes
         {
             this.forEncryption = forEncryption;
             this.macBlock = null;
+            this.initialised = true;
 
             KeyParameter keyParam;
+            byte[] newNonce = null;
 
             if (parameters is AeadParameters)
             {
                 AeadParameters param = (AeadParameters)parameters;
 
-                nonce = param.GetNonce();
+                newNonce = param.GetNonce();
                 initialAssociatedText = param.GetAssociatedText();
 
                 int macSizeBits = param.MacSize;
@@ -113,7 +117,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             {
                 ParametersWithIV param = (ParametersWithIV)parameters;
 
-                nonce = param.GetIV();
+                newNonce = param.GetIV();
                 initialAssociatedText = null;
                 macSize = 16; 
                 keyParam = (KeyParameter)param.Parameters;
@@ -126,11 +130,32 @@ namespace Org.BouncyCastle.Crypto.Modes
             int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
             this.bufBlock = new byte[bufLength];
 
-            if (nonce == null || nonce.Length < 1)
+            if (newNonce == null || newNonce.Length < 1)
             {
                 throw new ArgumentException("IV must be at least 1 byte");
             }
 
+            if (forEncryption)
+            {
+                if (nonce != null && Arrays.AreEqual(nonce, newNonce))
+                {
+                    if (keyParam == null)
+                    {
+                        throw new ArgumentException("cannot reuse nonce for GCM encryption");
+                    }
+                    if (lastKey != null && Arrays.AreEqual(lastKey, keyParam.GetKey()))
+                    {
+                        throw new ArgumentException("cannot reuse nonce for GCM encryption");
+                    }
+                }
+            }
+
+            nonce = newNonce;
+            if (keyParam != null)
+            {
+                lastKey = keyParam.GetKey();
+            }
+
             // TODO Restrict macSize to 16 if nonce length not 12?
 
             // Cipher always used in forward mode
@@ -186,7 +211,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual byte[] GetMac()
         {
-            return Arrays.Clone(macBlock);
+            return macBlock == null
+                ?   new byte[macSize]
+                :   Arrays.Clone(macBlock);
         }
 
         public virtual int GetOutputSize(
@@ -219,6 +246,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual void ProcessAadByte(byte input)
         {
+            CheckStatus();
+
             atBlock[atBlockPos] = input;
             if (++atBlockPos == BlockSize)
             {
@@ -231,6 +260,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
         {
+            CheckStatus();
+
             for (int i = 0; i < len; ++i)
             {
                 atBlock[atBlockPos] = inBytes[inOff + i];
@@ -270,6 +301,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             byte[]	output,
             int		outOff)
         {
+            CheckStatus();
+
             bufBlock[bufOff] = input;
             if (++bufOff == bufBlock.Length)
             {
@@ -286,6 +319,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             byte[]	output,
             int		outOff)
         {
+            CheckStatus();
+
             if (input.Length < (inOff + len))
                 throw new DataLengthException("Input buffer too short");
 
@@ -325,6 +360,8 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public int DoFinal(byte[] output, int outOff)
         {
+            CheckStatus();
+
             if (totalLength == 0)
             {
                 InitCipher();
@@ -441,6 +478,8 @@ namespace Org.BouncyCastle.Crypto.Modes
         {
             cipher.Reset();
 
+            // note: we do not reset the nonce.
+
             S = new byte[BlockSize];
             S_at = new byte[BlockSize];
             S_atPre = new byte[BlockSize];
@@ -463,9 +502,16 @@ namespace Org.BouncyCastle.Crypto.Modes
                 macBlock = null;
             }
 
-            if (initialAssociatedText != null)
+            if (forEncryption)
             {
-                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+                initialised = false;
+            }
+            else
+            {
+                if (initialAssociatedText != null)
+                {
+                    ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+                }
             }
         }
 
@@ -532,5 +578,17 @@ namespace Org.BouncyCastle.Crypto.Modes
             cipher.ProcessBlock(counter, 0, tmp, 0);
             return tmp;
         }
+
+        private void CheckStatus()
+        {
+            if (!initialised)
+            {
+                if (forEncryption)
+                {
+                    throw new InvalidOperationException("GCM cipher cannot be reused for encryption");
+                }
+                throw new InvalidOperationException("GCM cipher needs to be initialised");
+            }
+        }
     }
 }
diff --git a/crypto/src/crypto/modes/GOFBBlockCipher.cs b/crypto/src/crypto/modes/GOFBBlockCipher.cs
index 4299f11a9..436b58a1d 100644
--- a/crypto/src/crypto/modes/GOFBBlockCipher.cs
+++ b/crypto/src/crypto/modes/GOFBBlockCipher.cs
@@ -171,7 +171,10 @@ namespace Org.BouncyCastle.Crypto.Modes
 			N4 += C1;
             if (N4 < C1)  // addition is mod (2**32 - 1)
             {
-                N4++;
+                if (N4 > 0)
+                {
+                    N4++;
+                }
             }
             intTobytes(N3, ofbV, 0);
 			intTobytes(N4, ofbV, 4);
diff --git a/crypto/src/crypto/modes/KCtrBlockCipher.cs b/crypto/src/crypto/modes/KCtrBlockCipher.cs
new file mode 100644
index 000000000..ff0249a6c
--- /dev/null
+++ b/crypto/src/crypto/modes/KCtrBlockCipher.cs
@@ -0,0 +1,235 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+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
+    {
+        private byte[] IV;
+        private byte[] ofbV;
+        private byte[] ofbOutV;
+        private bool initialised;
+
+        private int byteCount;
+
+        private readonly int blockSize;
+        private readonly IBlockCipher cipher;
+
+        /**
+      * Basic constructor.
+      *
+      * @param cipher the block cipher to be used as the basis of the
+      * feedback mode.
+      */
+        public KCtrBlockCipher(IBlockCipher cipher)
+        {
+            this.cipher = cipher;
+            this.IV = new byte[cipher.GetBlockSize()];
+            this.blockSize = cipher.GetBlockSize();
+
+            this.ofbV = new byte[cipher.GetBlockSize()];
+            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;
+        }
+        /**
+        * 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.
+        * An IV which is too short is handled in FIPS compliant fashion.
+        *
+        * @param forEncryption if true the cipher is initialised for
+        *  encryption, if false for decryption.
+        * @param param the key and other data required by the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool forEncryption,
+            ICipherParameters parameters)
+        {
+            this.initialised = true;
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV)parameters;
+                byte[] iv = ivParam.GetIV();
+                int diff = IV.Length - iv.Length;
+
+                Array.Clear(IV, 0, IV.Length);
+                Array.Copy(iv, 0, IV, diff, iv.Length);
+         
+                parameters = ivParam.Parameters;
+            }
+            else
+            {
+                throw new ArgumentException("Invalid parameter passed");
+            }
+
+            // if it's null, key is to be reused.
+            if (parameters != null)
+            {
+                cipher.Init(true, parameters);
+            }
+
+            Reset();
+        }
+
+        /**
+        * return the algorithm name and mode.
+        *
+        * @return the name of the underlying algorithm followed by "/KCTR"
+        * and the block size in bits.
+        */
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/KCTR"; }
+        }
+
+        public bool IsPartialBlockOkay
+        {
+            get { return true; }
+        }
+
+        /**
+      * return the block size we are operating at.
+      *
+      * @return the block size we are operating at (in bytes).
+      */
+        public int GetBlockSize()
+        {
+            return cipher.GetBlockSize();
+        }
+
+        public byte ReturnByte(byte input)
+        {
+            return CalculateByte(input);
+        }
+
+        public void ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            if (outOff + len > output.Length)
+            {
+               throw new DataLengthException("Output buffer too short");
+            }
+
+            if (inOff + len > input.Length)
+            {
+                    throw new DataLengthException("Input buffer too small");
+            }
+
+            int inStart = inOff;
+            int inEnd = inOff + len;
+            int outStart = outOff;
+
+            while (inStart<inEnd)
+            {
+                 output[outStart++] = CalculateByte(input[inStart++]);
+            }
+        }
+
+        protected byte CalculateByte(byte b)
+        {
+            if (byteCount == 0)
+            {
+                incrementCounterAt(0);
+
+                checkCounter();
+
+                cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+                return (byte)(ofbOutV[byteCount++] ^ b);
+            }
+
+            byte rv = (byte)(ofbOutV[byteCount++] ^ b);
+
+            if (byteCount == ofbV.Length)
+            {
+                byteCount = 0;
+            }
+
+            return rv;
+        }
+
+        /**
+         * Process one block of input from the array in and write it to
+         * the out array.
+         *
+         * @param input the array containing the input data.
+         * @param inOff offset into the in array the data starts at.
+         * @param output the array the output data will be copied into.
+         * @param outOff the offset into the out array the output will start at.
+         * @exception DataLengthException if there isn't enough data in in, or
+         * space in out.
+         * @exception InvalidOperationException if the cipher isn't initialised.
+         * @return the number of bytes processed and produced.
+         */
+        public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+        {
+            if (input.Length - inOff< GetBlockSize())
+            {
+                throw new DataLengthException("Input buffer too short");
+            }
+            if (output.Length - outOff< GetBlockSize())
+            {
+                throw new DataLengthException("Output buffer too short");
+            }
+
+            ProcessBytes(input, inOff, GetBlockSize(), output, outOff);
+
+            return GetBlockSize();
+        }
+
+        /**
+        * reset the chaining vector back to the IV and reset the underlying
+        * cipher.
+        */
+        public void Reset()
+        {
+            if (initialised)
+            {
+                cipher.ProcessBlock(IV, 0, ofbV, 0);
+            }
+            cipher.Reset();
+            byteCount = 0;
+        }
+
+        private void incrementCounterAt(int pos)
+        {
+            int i = pos;
+            while (i < ofbV.Length)
+            {
+                if (++ofbV[i++] != 0)
+                {
+                    break;
+                }
+            }
+        }
+
+        private void checkCounter()
+        {
+            // TODO:
+            // if the IV is the same as the blocksize we assume the user knows what they are doing
+            //        if (IV.length < ofbV.length)
+            //        {
+            //            for (int i = 0; i != IV.length; i++)
+            //            {
+            //                if (ofbV[i] != IV[i])
+            //                {
+            //                    throw new IllegalStateException("Counter in KCTR mode out of range.");
+            //                }
+            //            }
+            //        }
+        }
+    }
+}
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
index e7dc466e6..91fdfff18 100644
--- a/crypto/src/crypto/modes/OCBBlockCipher.cs
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -237,7 +237,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public virtual byte[] GetMac()
         {
-            return Arrays.Clone(macBlock);
+            return macBlock == null
+                ? new byte[macSize]
+                : Arrays.Clone(macBlock);
         }
 
         public virtual int GetOutputSize(int len)
diff --git a/crypto/src/crypto/parameters/DHPublicKeyParameters.cs b/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
index e79375f71..e7aeeff19 100644
--- a/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
@@ -8,6 +8,25 @@ namespace Org.BouncyCastle.Crypto.Parameters
     public class DHPublicKeyParameters
 		: DHKeyParameters
     {
+        private static BigInteger Validate(BigInteger y, DHParameters dhParams)
+        {
+            if (y == null)
+                throw new ArgumentNullException("y");
+
+            // TLS check
+            if (y.CompareTo(BigInteger.Two) < 0 || y.CompareTo(dhParams.P.Subtract(BigInteger.Two)) > 0)
+                throw new ArgumentException("invalid DH public key", "y");
+
+            // we can't validate without Q.
+            if (dhParams.Q != null
+                && !y.ModPow(dhParams.Q, dhParams.P).Equals(BigInteger.One))
+            {
+                throw new ArgumentException("y value does not appear to be in correct group", "y");
+            }
+
+            return y;
+        }
+
         private readonly BigInteger y;
 
 		public DHPublicKeyParameters(
@@ -15,10 +34,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             DHParameters	parameters)
 			: base(false, parameters)
         {
-			if (y == null)
-				throw new ArgumentNullException("y");
-
-			this.y = y;
+			this.y = Validate(y, parameters);
         }
 
 		public DHPublicKeyParameters(
@@ -27,13 +43,10 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		    DerObjectIdentifier	algorithmOid)
 			: base(false, parameters, algorithmOid)
         {
-			if (y == null)
-				throw new ArgumentNullException("y");
-
-			this.y = y;
+            this.y = Validate(y, parameters);
         }
 
-        public BigInteger Y
+        public virtual BigInteger Y
         {
             get { return y; }
         }
diff --git a/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs b/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
index f11f858f3..3a81bfdd0 100644
--- a/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
@@ -7,6 +7,22 @@ namespace Org.BouncyCastle.Crypto.Parameters
     public class DsaPublicKeyParameters
 		: DsaKeyParameters
     {
+        private static BigInteger Validate(BigInteger y, DsaParameters parameters)
+        {
+            // we can't validate without params, fortunately we can't use the key either...
+            if (parameters != null)
+            {
+                if (y.CompareTo(BigInteger.Two) < 0
+                    || y.CompareTo(parameters.P.Subtract(BigInteger.Two)) > 0
+                    || !y.ModPow(parameters.Q, parameters.P).Equals(BigInteger.One))
+                {
+                    throw new ArgumentException("y value does not appear to be in correct group");
+                }
+            }
+
+            return y;
+        }
+
         private readonly BigInteger y;
 
 		public DsaPublicKeyParameters(
@@ -17,7 +33,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 			if (y == null)
 				throw new ArgumentNullException("y");
 
-			this.y = y;
+			this.y = Validate(y, parameters);
         }
 
 		public BigInteger Y
diff --git a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
index 1eb665da9..474e5d82c 100644
--- a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
@@ -9,6 +9,21 @@ namespace Org.BouncyCastle.Crypto.Parameters
     public class ECPublicKeyParameters
         : ECKeyParameters
     {
+        private static ECPoint Validate(ECPoint q)
+        {
+            if (q == null)
+                throw new ArgumentNullException("q");
+            if (q.IsInfinity)
+                throw new ArgumentException("point at infinity", "q");
+
+            q = q.Normalize();
+
+            if (!q.IsValid())
+                throw new ArgumentException("point not on curve", "q");
+
+            return q;
+        }
+
         private readonly ECPoint q;
 
         public ECPublicKeyParameters(
@@ -27,7 +42,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (q == null)
                 throw new ArgumentNullException("q");
 
-            this.q = q.Normalize();
+            this.q = Validate(q);
         }
 
         public ECPublicKeyParameters(
@@ -39,7 +54,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (q == null)
                 throw new ArgumentNullException("q");
 
-            this.q = q.Normalize();
+            this.q = Validate(q);
         }
 
         public ECPublicKeyParameters(
@@ -51,7 +66,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             if (q == null)
                 throw new ArgumentNullException("q");
 
-            this.q = q.Normalize();
+            this.q = Validate(q);
         }
 
         public ECPoint Q
diff --git a/crypto/src/crypto/parameters/RsaKeyParameters.cs b/crypto/src/crypto/parameters/RsaKeyParameters.cs
index 72c0d806f..5480f0561 100644
--- a/crypto/src/crypto/parameters/RsaKeyParameters.cs
+++ b/crypto/src/crypto/parameters/RsaKeyParameters.cs
@@ -8,6 +8,26 @@ namespace Org.BouncyCastle.Crypto.Parameters
 	public class RsaKeyParameters
 		: AsymmetricKeyParameter
     {
+        // the value is the product of the 132 smallest primes from 3 to 751
+        private static BigInteger SmallPrimesProduct = new BigInteger( 
+            "8138E8A0FCF3A4E84A771D40FD305D7F4AA59306D7251DE54D98AF8FE95729A1" +
+            "F73D893FA424CD2EDC8636A6C3285E022B0E3866A565AE8108EED8591CD4FE8D" +
+            "2CE86165A978D719EBF647F362D33FCA29CD179FB42401CBAF3DF0C614056F9C" +
+            "8F3CFD51E474AFB6BC6974F78DB8ABA8E9E517FDED658591AB7502BD41849462F",
+            16);
+
+        private static BigInteger Validate(BigInteger modulus)
+        {
+            if ((modulus.IntValue & 1) == 0)
+                throw new ArgumentException("RSA modulus is even", "modulus");
+            if (!modulus.Gcd(SmallPrimesProduct).Equals(BigInteger.One))
+                throw new ArgumentException("RSA modulus has a small prime factor");
+
+            // TODO: add additional primePower/Composite test - expensive!!
+
+            return modulus;
+        }
+
         private readonly BigInteger modulus;
         private readonly BigInteger exponent;
 
@@ -25,8 +45,10 @@ namespace Org.BouncyCastle.Crypto.Parameters
 				throw new ArgumentException("Not a valid RSA modulus", "modulus");
 			if (exponent.SignValue <= 0)
 				throw new ArgumentException("Not a valid RSA exponent", "exponent");
+            if (!isPrivate && (exponent.IntValue & 1) == 0)
+                throw new ArgumentException("RSA publicExponent is even", "exponent");
 
-			this.modulus = modulus;
+            this.modulus = Validate(modulus);
 			this.exponent = exponent;
         }
 
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
index 5c5bda399..30c838c1b 100644
--- a/crypto/src/crypto/prng/SP800SecureRandom.cs
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -76,5 +76,20 @@ namespace Org.BouncyCastle.Crypto.Prng
         {
             return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
         }
+
+        /// <summary>Force a reseed of the DRBG.</summary>
+        /// <param name="additionalInput">optional additional input</param>
+        public virtual void Reseed(byte[] additionalInput)
+        {
+            lock (this)
+            {
+                if (mDrbg == null)
+                {
+                    mDrbg = mDrbgProvider.Get(mEntropySource);
+                }
+
+                mDrbg.Reseed(additionalInput);
+            }
+        }
     }
 }
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index 3aa2e3719..6b8037095 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -516,6 +516,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             if (!isOkay)
             {
                 fullMessage = false;
+                messageLength = 0;
                 ClearBlock(recoveredMessage);
                 return false;
             }
@@ -528,12 +529,14 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 if (!IsSameAs(mBuf, recoveredMessage))
                 {
+                    messageLength = 0;
                     ClearBlock(mBuf);
                     return false;
                 }
-                messageLength = 0;
             }
 
+            messageLength = 0;
+
             ClearBlock(mBuf);
             return true;
         }
diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs
index b90ed8f0b..303913068 100644
--- a/crypto/src/crypto/signers/Iso9796d2Signer.cs
+++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -360,6 +360,8 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             byte[] b = cipher.ProcessBlock(block, 0, block.Length);
 
+            messageLength = 0;
+
             ClearBlock(mBuf);
             ClearBlock(block);
 
@@ -526,11 +528,15 @@ namespace Org.BouncyCastle.Crypto.Signers
             ClearBlock(mBuf);
             ClearBlock(block);
 
+            messageLength = 0;
+
             return true;
         }
 
         private bool ReturnFalse(byte[] block)
         {
+            messageLength = 0;
+
             ClearBlock(mBuf);
             ClearBlock(block);
 
diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
index 96037ed20..45eef18e3 100644
--- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs
+++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -56,10 +56,9 @@ namespace Org.BouncyCastle.Crypto.Tls
         public const int CAMELLIA_256_GCM = 20;
 
         /*
-         * draft-ietf-tls-chacha20-poly1305-04
+         * RFC 7905
          */
-        public const int CHACHA20_POLY1305 = 102;
-        [Obsolete] public const int AEAD_CHACHA20_POLY1305 = CHACHA20_POLY1305;
+        public const int CHACHA20_POLY1305 = 21;
 
         /*
          * draft-zauner-tls-aes-ocb-04
diff --git a/crypto/src/crypto/tls/ExtensionType.cs b/crypto/src/crypto/tls/ExtensionType.cs
index bff9332a0..f17210b80 100644
--- a/crypto/src/crypto/tls/ExtensionType.cs
+++ b/crypto/src/crypto/tls/ExtensionType.cs
@@ -99,6 +99,16 @@ namespace Org.BouncyCastle.Crypto.Tls
         public const int extended_master_secret = 23;
 
         /*
+         * draft-ietf-tokbind-negotiation-08
+         */
+        public static readonly int DRAFT_token_binding = 24;
+
+        /*
+         * RFC 7924
+         */
+        public const int cached_info = 25;
+
+        /*
          * RFC 5077 7.
          */
         public const int session_ticket = 35;
diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs
index 46673cf7e..5d556ad06 100644
--- a/crypto/src/crypto/tls/RecordStream.cs
+++ b/crypto/src/crypto/tls/RecordStream.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         private Stream mOutput;
         private TlsCompression mPendingCompression = null, mReadCompression = null, mWriteCompression = null;
         private TlsCipher mPendingCipher = null, mReadCipher = null, mWriteCipher = null;
-        private long mReadSeqNo = 0, mWriteSeqNo = 0;
+        private SequenceNumber mReadSeqNo = new SequenceNumber(), mWriteSeqNo = new SequenceNumber();
         private MemoryStream mBuffer = new MemoryStream();
 
         private TlsHandshakeHash mHandshakeHash = null;
@@ -100,7 +100,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             this.mWriteCompression = this.mPendingCompression;
             this.mWriteCipher = this.mPendingCipher;
-            this.mWriteSeqNo = 0;
+            this.mWriteSeqNo = new SequenceNumber();
         }
 
         internal virtual void ReceivedReadCipherSpec()
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             this.mReadCompression = this.mPendingCompression;
             this.mReadCipher = this.mPendingCipher;
-            this.mReadSeqNo = 0;
+            this.mReadSeqNo = new SequenceNumber();
         }
 
         internal virtual void FinaliseHandshake()
@@ -203,7 +203,9 @@ namespace Org.BouncyCastle.Crypto.Tls
         internal virtual byte[] DecodeAndVerify(byte type, Stream input, int len)
         {
             byte[] buf = TlsUtilities.ReadFully(len, input);
-            byte[] decoded = mReadCipher.DecodeCiphertext(mReadSeqNo++, type, buf, 0, buf.Length);
+
+            long seqNo = mReadSeqNo.NextValue(AlertDescription.unexpected_message);
+            byte[] decoded = mReadCipher.DecodeCiphertext(seqNo, type, buf, 0, buf.Length);
 
             CheckLength(decoded.Length, mCompressedLimit, AlertDescription.record_overflow);
 
@@ -262,10 +264,12 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             Stream cOut = mWriteCompression.Compress(mBuffer);
 
+            long seqNo = mWriteSeqNo.NextValue(AlertDescription.internal_error);
+
             byte[] ciphertext;
             if (cOut == mBuffer)
             {
-                ciphertext = mWriteCipher.EncodePlaintext(mWriteSeqNo++, type, plaintext, plaintextOffset, plaintextLength);
+                ciphertext = mWriteCipher.EncodePlaintext(seqNo, type, plaintext, plaintextOffset, plaintextLength);
             }
             else
             {
@@ -279,7 +283,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                  */
                 CheckLength(compressed.Length, plaintextLength + 1024, AlertDescription.internal_error);
 
-                ciphertext = mWriteCipher.EncodePlaintext(mWriteSeqNo++, type, compressed, 0, compressed.Length);
+                ciphertext = mWriteCipher.EncodePlaintext(seqNo, type, compressed, 0, compressed.Length);
             }
 
             /*
@@ -384,5 +388,25 @@ namespace Org.BouncyCastle.Crypto.Tls
                 mOuter.mHandshakeHash.BlockUpdate(buf, off, len);
             }
         }
+
+        private class SequenceNumber
+        {
+            private long value = 0L;
+            private bool exhausted = false;
+
+            internal long NextValue(byte alertDescription)
+            {
+                if (exhausted)
+                {
+                    throw new TlsFatalAlert(alertDescription);
+                }
+                long result = value;
+                if (++value == 0)
+                {
+                    exhausted = true;
+                }
+                return result;
+            }
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index eec9daaca..d179068bb 100644
--- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -151,6 +151,9 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
         {
+            if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
             byte[] types = certificateRequest.CertificateTypes;
             for (int i = 0; i < types.Length; ++i)
             {
diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
index 03c162904..c508fb993 100644
--- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -153,6 +153,9 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
         {
+            if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
             /*
              * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
              * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
diff --git a/crypto/src/crypto/tls/TlsException.cs b/crypto/src/crypto/tls/TlsException.cs
new file mode 100644
index 000000000..cea9e3e77
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsException.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class TlsException
+        : IOException
+    {
+        public TlsException(string message, Exception cause)
+            : base(message, cause)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsFatalAlert.cs b/crypto/src/crypto/tls/TlsFatalAlert.cs
index 55d784dd9..6f1898179 100644
--- a/crypto/src/crypto/tls/TlsFatalAlert.cs
+++ b/crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -1,10 +1,9 @@
 using System;
-using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
     public class TlsFatalAlert
-        : IOException
+        : TlsException
     {
         private readonly byte alertDescription;
 
diff --git a/crypto/src/crypto/tls/TlsFatalAlertReceived.cs b/crypto/src/crypto/tls/TlsFatalAlertReceived.cs
new file mode 100644
index 000000000..044fc8027
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsFatalAlertReceived.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class TlsFatalAlertReceived
+        : TlsException
+    {
+        private readonly byte alertDescription;
+
+        public TlsFatalAlertReceived(byte alertDescription)
+            : base(Tls.AlertDescription.GetText(alertDescription), null)
+        {
+            this.alertDescription = alertDescription;
+        }
+
+        public virtual byte AlertDescription
+        {
+            get { return alertDescription; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs b/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
index 72159ba47..0bafd820b 100644
--- a/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
+++ b/crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
@@ -15,5 +15,9 @@ namespace Org.BouncyCastle.Crypto.Tls
     public class TlsNoCloseNotifyException
         :   EndOfStreamException
     {
+        public TlsNoCloseNotifyException()
+            : base("No close_notify alert received before connection closed")
+        {
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index 490580fad..72151d414 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -10,8 +10,6 @@ namespace Org.BouncyCastle.Crypto.Tls
 {
     public abstract class TlsProtocol
     {
-        private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
-
         /*
          * Our Connection states
          */
@@ -110,16 +108,95 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         protected abstract TlsPeer Peer { get; }
 
+        protected virtual void HandleAlertMessage(byte alertLevel, byte alertDescription)
+        {
+            Peer.NotifyAlertReceived(alertLevel, alertDescription);
+
+            if (alertLevel == AlertLevel.warning)
+            {
+                HandleAlertWarningMessage(alertDescription);
+            }
+            else
+            {
+                HandleFailure();
+
+                throw new TlsFatalAlertReceived(alertDescription);
+            }
+        }
+
+        protected virtual void HandleAlertWarningMessage(byte alertDescription)
+        {
+            /*
+             * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
+             * and close down the connection immediately, discarding any pending writes.
+             */
+            if (alertDescription == AlertDescription.close_notify)
+            {
+                if (!mAppDataReady)
+                    throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+                HandleClose(false);
+            }
+        }
+
         protected virtual void HandleChangeCipherSpecMessage()
         {
         }
 
-        protected abstract void HandleHandshakeMessage(byte type, MemoryStream buf);
+        protected virtual void HandleClose(bool user_canceled)
+        {
+            if (!mClosed)
+            {
+                this.mClosed = true;
+
+                if (user_canceled && !mAppDataReady)
+                {
+                    RaiseAlertWarning(AlertDescription.user_canceled, "User canceled handshake");
+                }
+
+                RaiseAlertWarning(AlertDescription.close_notify, "Connection closed");
+
+                mRecordStream.SafeClose();
+
+                if (!mAppDataReady)
+                {
+                    CleanupHandshake();
+                }
+            }
+        }
+
+        protected virtual void HandleException(byte alertDescription, string message, Exception cause)
+        {
+            if (!mClosed)
+            {
+                RaiseAlertFatal(alertDescription, message, cause);
+
+                HandleFailure();
+            }
+        }
 
-        protected virtual void HandleWarningMessage(byte description)
+        protected virtual void HandleFailure()
         {
+            this.mClosed = true;
+            this.mFailedWithError = true;
+
+            /*
+             * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
+             * without proper close_notify messages with level equal to warning.
+             */
+            // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete.
+            InvalidateSession();
+
+            mRecordStream.SafeClose();
+
+            if (!mAppDataReady)
+            {
+                CleanupHandshake();
+            }
         }
 
+        protected abstract void HandleHandshakeMessage(byte type, MemoryStream buf);
+
         protected virtual void ApplyMaxFragmentLengthExtension()
         {
             if (mSecurityParameters.maxFragmentLength >= 0)
@@ -368,47 +445,11 @@ namespace Org.BouncyCastle.Crypto.Tls
                 /*
                  * An alert is always 2 bytes. Read the alert.
                  */
-                byte[] tmp = mAlertQueue.RemoveData(2, 0);
-                byte level = tmp[0];
-                byte description = tmp[1];
-
-                Peer.NotifyAlertReceived(level, description);
-
-                if (level == AlertLevel.fatal)
-                {
-                    /*
-                     * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
-                     * without proper close_notify messages with level equal to warning.
-                     */
-                    InvalidateSession();
-
-                    this.mFailedWithError = true;
-                    this.mClosed = true;
-
-                    mRecordStream.SafeClose();
-
-                    throw new IOException(TLS_ERROR_MESSAGE);
-                }
-                else
-                {
-                    /*
-                     * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
-                     * and close down the connection immediately, discarding any pending writes.
-                     */
-                    if (description == AlertDescription.close_notify)
-                    {
-                        if (!mAppDataReady)
-                        {
-                            throw new TlsFatalAlert(AlertDescription.handshake_failure);
-                        }
-                        HandleClose(false);
-                    }
+                byte[] alert = mAlertQueue.RemoveData(2, 0);
+                byte alertLevel = alert[0];
+                byte alertDescription = alert[1];
 
-                    /*
-                     * If it is just a warning, we continue.
-                     */
-                    HandleWarningMessage(description);
-                }
+                HandleAlertMessage(alertLevel, alertDescription);
             }
         }
 
@@ -464,22 +505,14 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             while (mApplicationDataQueue.Available == 0)
             {
-                /*
-                 * We need to read some data.
-                 */
                 if (this.mClosed)
                 {
                     if (this.mFailedWithError)
-                    {
-                        /*
-                         * Something went terribly wrong, we should throw an IOException
-                         */
-                        throw new IOException(TLS_ERROR_MESSAGE);
-                    }
+                        throw new IOException("Cannot read application data on failed TLS connection");
+
+                    if (!mAppDataReady)
+                        throw new InvalidOperationException("Cannot read application data until initial handshake completed.");
 
-                    /*
-                     * Connection has been closed, there is no more data to read.
-                     */
                     return 0;
                 }
 
@@ -499,45 +532,55 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
             catch (TlsFatalAlert e)
             {
-                this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e);
+                HandleException(e.AlertDescription, "Failed to read record", e);
                 throw e;
             }
-            catch (Exception e)
+            catch (IOException e)
             {
-                this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e);
+                HandleException(AlertDescription.internal_error, "Failed to read record", e);
                 throw e;
             }
+            catch (Exception e)
+            {
+                HandleException(AlertDescription.internal_error, "Failed to read record", e);
+                throw new TlsFatalAlert(AlertDescription.internal_error, e);
+            }
         }
 
         protected virtual void SafeReadRecord()
         {
             try
             {
-                if (!mRecordStream.ReadRecord())
-                {
-                    if (!mAppDataReady)
-                    {
-                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
-                    }
-                    throw new TlsNoCloseNotifyException();
-                }
+                if (mRecordStream.ReadRecord())
+                    return;
+
+                if (!mAppDataReady)
+                    throw new TlsFatalAlert(AlertDescription.handshake_failure);
+            }
+            catch (TlsFatalAlertReceived e)
+            {
+                // Connection failure already handled at source
+                throw e;
             }
             catch (TlsFatalAlert e)
             {
-                if (!mClosed)
-                {
-                    this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e);
-                }
+                HandleException(e.AlertDescription, "Failed to read record", e);
                 throw e;
             }
-            catch (Exception e)
+            catch (IOException e)
             {
-                if (!mClosed)
-                {
-                    this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e);
-                }
+                HandleException(AlertDescription.internal_error, "Failed to read record", e);
                 throw e;
             }
+            catch (Exception e)
+            {
+                HandleException(AlertDescription.internal_error, "Failed to read record", e);
+                throw new TlsFatalAlert(AlertDescription.internal_error, e);
+            }
+
+            HandleFailure();
+
+            throw new TlsNoCloseNotifyException();
         }
 
         protected virtual void SafeWriteRecord(byte type, byte[] buf, int offset, int len)
@@ -548,20 +591,19 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
             catch (TlsFatalAlert e)
             {
-                if (!mClosed)
-                {
-                    this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to write record", e);
-                }
+                HandleException(e.AlertDescription, "Failed to write record", e);
                 throw e;
             }
-            catch (Exception e)
+            catch (IOException e)
             {
-                if (!mClosed)
-                {
-                    this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to write record", e);
-                }
+                HandleException(AlertDescription.internal_error, "Failed to write record", e);
                 throw e;
             }
+            catch (Exception e)
+            {
+                HandleException(AlertDescription.internal_error, "Failed to write record", e);
+                throw new TlsFatalAlert(AlertDescription.internal_error, e);
+            }
         }
 
         /**
@@ -577,12 +619,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         protected internal virtual void WriteData(byte[] buf, int offset, int len)
         {
             if (this.mClosed)
-            {
-                if (this.mFailedWithError)
-                    throw new IOException(TLS_ERROR_MESSAGE);
-
-                throw new IOException("Sorry, connection has been closed, you cannot write more data");
-            }
+                throw new IOException("Cannot write application data on closed/failed TLS connection");
 
             while (len > 0)
             {
@@ -843,50 +880,6 @@ namespace Org.BouncyCastle.Crypto.Tls
             return mOutputBuffer.Read(buffer, offset, length);
         }
 
-        /**
-         * Terminate this connection with an alert. Can be used for normal closure too.
-         * 
-         * @param alertLevel
-         *            See {@link AlertLevel} for values.
-         * @param alertDescription
-         *            See {@link AlertDescription} for values.
-         * @throws IOException
-         *             If alert was fatal.
-         */
-        protected virtual void FailWithError(byte alertLevel, byte alertDescription, string message, Exception cause)
-        {
-            /*
-             * Check if the connection is still open.
-             */
-            if (!mClosed)
-            {
-                /*
-                 * Prepare the message
-                 */
-                this.mClosed = true;
-
-                if (alertLevel == AlertLevel.fatal)
-                {
-                    /*
-                     * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
-                     * without proper close_notify messages with level equal to warning.
-                     */
-                    // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete.
-                    InvalidateSession();
-
-                    this.mFailedWithError = true;
-                }
-                RaiseAlert(alertLevel, alertDescription, message, cause);
-                mRecordStream.SafeClose();
-                if (alertLevel != AlertLevel.fatal)
-                {
-                    return;
-                }
-            }
-
-            throw new IOException(TLS_ERROR_MESSAGE);
-        }
-
         protected virtual void InvalidateSession()
         {
             if (this.mSessionParameters != null)
@@ -923,18 +916,29 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        protected virtual void RaiseAlert(byte alertLevel, byte alertDescription, string message, Exception cause)
+        protected virtual void RaiseAlertFatal(byte alertDescription, string message, Exception cause)
         {
-            Peer.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
+            Peer.NotifyAlertRaised(AlertLevel.fatal, alertDescription, message, cause);
 
-            byte[] error = new byte[]{ alertLevel, alertDescription };
+            byte[] alert = new byte[]{ AlertLevel.fatal, alertDescription };
 
-            SafeWriteRecord(ContentType.alert, error, 0, 2);
+            try
+            {
+                mRecordStream.WriteRecord(ContentType.alert, alert, 0, 2);
+            }
+            catch (Exception)
+            {
+                // We are already processing an exception, so just ignore this
+            }
         }
 
-        protected virtual void RaiseWarning(byte alertDescription, string message)
+        protected virtual void RaiseAlertWarning(byte alertDescription, string message)
         {
-            RaiseAlert(AlertLevel.warning, alertDescription, message, null);
+            Peer.NotifyAlertRaised(AlertLevel.warning, alertDescription, message, null);
+
+            byte[] alert = new byte[]{ AlertLevel.warning, alertDescription };
+
+            SafeWriteRecord(ContentType.alert, alert, 0, 2);
         }
 
         protected virtual void SendCertificateMessage(Certificate certificate)
@@ -953,7 +957,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                     if (serverVersion.IsSsl)
                     {
                         string errorMessage = serverVersion.ToString() + " client didn't provide credentials";
-                        RaiseWarning(AlertDescription.no_certificate, errorMessage);
+                        RaiseAlertWarning(AlertDescription.no_certificate, errorMessage);
                         return;
                     }
                 }
@@ -1012,18 +1016,6 @@ namespace Org.BouncyCastle.Crypto.Tls
             HandleClose(true);
         }
 
-        protected virtual void HandleClose(bool user_canceled)
-        {
-            if (!mClosed)
-            {
-                if (user_canceled && !mAppDataReady)
-                {
-                    RaiseWarning(AlertDescription.user_canceled, "User canceled handshake");
-                }
-                this.FailWithError(AlertLevel.warning, AlertDescription.close_notify, "Connection closed", null);
-            }
-        }
-
         protected internal virtual void Flush()
         {
             mRecordStream.Flush();
@@ -1059,7 +1051,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             if (TlsUtilities.IsSsl(Context))
                 throw new TlsFatalAlert(AlertDescription.handshake_failure);
 
-            RaiseWarning(AlertDescription.no_renegotiation, "Renegotiation not supported");
+            RaiseAlertWarning(AlertDescription.no_renegotiation, "Renegotiation not supported");
         }
 
         /**
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index 5f3ce18e2..c2bfbcb74 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -386,28 +386,39 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        protected override void HandleWarningMessage(byte description)
+        protected override void HandleAlertWarningMessage(byte alertDescription)
         {
-            switch (description)
+            base.HandleAlertWarningMessage(alertDescription);
+
+            switch (alertDescription)
             {
             case AlertDescription.no_certificate:
             {
                 /*
-                 * SSL 3.0 If the server has sent a certificate request Message, the client must Send
+                 * SSL 3.0 If the server has sent a certificate request Message, the client must send
                  * either the certificate message or a no_certificate alert.
                  */
-                if (TlsUtilities.IsSsl(Context) && mCertificateRequest != null)
+                if (TlsUtilities.IsSsl(Context) && this.mCertificateRequest != null)
                 {
-                    NotifyClientCertificate(Certificate.EmptyChain);
+                    switch (this.mConnectionState)
+                    {
+                    case CS_SERVER_HELLO_DONE:
+                    case CS_CLIENT_SUPPLEMENTAL_DATA:
+                    {
+                        if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+                        {
+                            mTlsServer.ProcessClientSupplementalData(null);
+                        }
+
+                        NotifyClientCertificate(Certificate.EmptyChain);
+                        this.mConnectionState = CS_CLIENT_CERTIFICATE;
+                        return;
+                    }
+                    }
                 }
-                break;
-            }
-            default:
-            {
-                base.HandleWarningMessage(description);
-                break;
-            }
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
             }
+            } 
         }
 
         protected virtual void NotifyClientCertificate(Certificate clientCertificate)
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 96f293d72..ebe5b7af1 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -298,5 +298,14 @@ namespace Org.BouncyCastle.Crypto.Utilities
             uint hi = LE_To_UInt32(bs, off + 4);
             return ((ulong)hi << 32) | (ulong)lo;
         }
+
+        internal static void LE_To_UInt64(byte[] bs, int off, ulong[] ns)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                ns[i] = LE_To_UInt64(bs, off);
+                off += 8;
+            }
+        }
     }
 }
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
new file mode 100644
index 000000000..70b1190c9
--- /dev/null
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+    internal class SM2P256V1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"));
+
+        private const int SM2P256V1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SM2P256V1Point m_infinity;
+
+        public SM2P256V1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SM2P256V1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93")));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SM2P256V1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SM2P256V1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SM2P256V1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SM2P256V1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SM2P256V1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Field.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Field.cs
new file mode 100644
index 000000000..b1d232347
--- /dev/null
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1Field.cs
@@ -0,0 +1,307 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+    internal class SM2P256V1Field
+    {
+        // 2^256 - 2^224 - 2^96 + 2^64 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFE };
+        internal static readonly uint[] PExt = new uint[]{ 00000001, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000001,
+            0xFFFFFFFE, 0x00000000, 0x00000002, 0xFFFFFFFE, 0xFFFFFFFD, 0x00000003, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+            0x00000000, 0xFFFFFFFE };
+        internal const uint P7 = 0xFFFFFFFE;
+        internal const uint PExt15 = 0xFFFFFFFE;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat256.Add(x, y, z);
+            if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(16, xx, yy, zz);
+            if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+            {
+                Nat.SubFrom(16, PExt, zz);
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(8, x, z);
+            if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat256.FromBigInteger(x);
+            if (z[7] >= P7 && Nat256.Gte(z, P))
+            {
+                Nat256.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(8, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat256.Add(x, P, z);
+                Nat.ShiftDownBit(8, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat256.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+            {
+                Nat.SubFrom(16, PExt, zz);
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat256.IsZero(x))
+            {
+                Nat256.Zero(z);
+            }
+            else
+            {
+                Nat256.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            long xx08 = xx[8], xx09 = xx[9], xx10 = xx[10], xx11 = xx[11];
+            long xx12 = xx[12], xx13 = xx[13], xx14 = xx[14], xx15 = xx[15];
+
+            long t0 = xx08 + xx09;
+            long t1 = xx10 + xx11;
+            long t2 = xx12 + xx15;
+            long t3 = xx13 + xx14;
+            long t4 = t3 + (xx15 << 1);
+
+            long ts = t0 + t3;
+            long tt = t1 + t2 + ts;
+
+            long cc = 0;
+            cc += (long)xx[0] + tt + xx13 + xx14 + xx15;
+            z[0] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[1] + tt - xx08 + xx14 + xx15;
+            z[1] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[2] - ts;
+            z[2] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[3] + tt - xx09 - xx10 + xx13;
+            z[3] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[4] + tt - t1 - xx08 + xx14;
+            z[4] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[5] + t4 + xx10;
+            z[5] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[6] + xx11 + xx14 + xx15;
+            z[6] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[7] + tt + t4 + xx12;
+            z[7] = (uint)cc;
+            cc >>= 32;
+
+            Debug.Assert(cc >= 0);
+
+            Reduce32((uint)cc, z);
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            long cc = 0;
+
+            if (x != 0)
+            {
+                long xx08 = x;
+
+                cc += (long)z[0] + xx08;
+                z[0] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (long)z[1];
+                    z[1] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (long)z[2] - xx08;
+                z[2] = (uint)cc;
+                cc >>= 32;
+                cc += (long)z[3] + xx08;
+                z[3] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (long)z[4];
+                    z[4] = (uint)cc;
+                    cc >>= 32;
+                    cc += (long)z[5];
+                    z[5] = (uint)cc;
+                    cc >>= 32;
+                    cc += (long)z[6];
+                    z[6] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (long)z[7] + xx08;
+                z[7] = (uint)cc;
+                cc >>= 32;
+
+                Debug.Assert(cc == 0 || cc == 1);
+            }
+
+            if (cc != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat256.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat256.Sub(x, y, z);
+            if (c != 0)
+            {
+                SubPInvFrom(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(16, xx, yy, zz);
+            if (c != 0)
+            {
+                Nat.AddTo(16, PExt, zz);
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(8, x, 0, z);
+            if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        private static void AddPInvTo(uint[] z)
+        {
+            long c = (long)z[0] + 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[2] - 1;
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] + 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[4];
+                z[4] = (uint)c;
+                c >>= 32;
+                c += (long)z[5];
+                z[5] = (uint)c;
+                c >>= 32;
+                c += (long)z[6];
+                z[6] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[7] + 1;
+            z[7] = (uint)c;
+            //c >>= 32;
+        }
+
+        private static void SubPInvFrom(uint[] z)
+        {
+            long c = (long)z[0] - 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[2] + 1;
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[4];
+                z[4] = (uint)c;
+                c >>= 32;
+                c += (long)z[5];
+                z[5] = (uint)c;
+                c >>= 32;
+                c += (long)z[6];
+                z[6] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[7] - 1;
+            z[7] = (uint)c;
+            //c >>= 32;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
new file mode 100644
index 000000000..4f6428f9e
--- /dev/null
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
@@ -0,0 +1,211 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+    internal class SM2P256V1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SM2P256V1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SM2P256V1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SM2P256V1FieldElement", "x");
+
+            this.x = SM2P256V1Field.FromBigInteger(x);
+        }
+
+        public SM2P256V1FieldElement()
+        {
+            this.x = Nat256.Create();
+        }
+
+        protected internal SM2P256V1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat256.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat256.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat256.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat256.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SM2P256V1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SM2P256V1Field.Add(x, ((SM2P256V1FieldElement)b).x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat256.Create();
+            SM2P256V1Field.AddOne(x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SM2P256V1Field.Subtract(x, ((SM2P256V1FieldElement)b).x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SM2P256V1Field.Multiply(x, ((SM2P256V1FieldElement)b).x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat256.Create();
+            Mod.Invert(SM2P256V1Field.P, ((SM2P256V1FieldElement)b).x, z);
+            SM2P256V1Field.Multiply(z, x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat256.Create();
+            SM2P256V1Field.Negate(x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat256.Create();
+            SM2P256V1Field.Square(x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SM2P256V1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat256.Create();
+            Mod.Invert(SM2P256V1Field.P, x, z);
+            return new SM2P256V1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Raise this element to the exponent 2^254 - 2^222 - 2^94 + 2^62
+             *
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             * { 31 1s } { 1 0s } { 128 1s } { 31 0s } { 1 1s } { 62 0s}
+             *
+             * We use an addition chain for the beginning: [1], 2, 3, 6, 12, [24], 30, [31] 
+             */
+
+            uint[] x1 = this.x;
+            if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+            {
+                return this;
+            }
+
+            uint[] x2 = Nat256.Create();
+            SM2P256V1Field.Square(x1, x2);
+            SM2P256V1Field.Multiply(x2, x1, x2);
+            uint[] x4 = Nat256.Create();
+            SM2P256V1Field.SquareN(x2, 2, x4);
+            SM2P256V1Field.Multiply(x4, x2, x4);
+            uint[] x6 = Nat256.Create();
+            SM2P256V1Field.SquareN(x4, 2, x6);
+            SM2P256V1Field.Multiply(x6, x2, x6);
+            uint[] x12 = x2;
+            SM2P256V1Field.SquareN(x6, 6, x12);
+            SM2P256V1Field.Multiply(x12, x6, x12);
+            uint[] x24 = Nat256.Create();
+            SM2P256V1Field.SquareN(x12, 12, x24);
+            SM2P256V1Field.Multiply(x24, x12, x24);
+            uint[] x30 = x12;
+            SM2P256V1Field.SquareN(x24, 6, x30);
+            SM2P256V1Field.Multiply(x30, x6, x30);
+            uint[] x31 = x6;
+            SM2P256V1Field.Square(x30, x31);
+            SM2P256V1Field.Multiply(x31, x1, x31);
+
+            uint[] t1 = x24;
+            SM2P256V1Field.SquareN(x31, 31, t1);
+
+            uint[] x62 = x30;
+            SM2P256V1Field.Multiply(t1, x31, x62);
+
+            SM2P256V1Field.SquareN(t1, 32, t1);
+            SM2P256V1Field.Multiply(t1, x62, t1);
+            SM2P256V1Field.SquareN(t1, 62, t1);
+            SM2P256V1Field.Multiply(t1, x62, t1);
+            SM2P256V1Field.SquareN(t1, 4, t1);
+            SM2P256V1Field.Multiply(t1, x4, t1);
+            SM2P256V1Field.SquareN(t1, 32, t1);
+            SM2P256V1Field.Multiply(t1, x1, t1);
+            SM2P256V1Field.SquareN(t1, 62, t1);
+
+            uint[] t2 = x4;
+            SM2P256V1Field.Square(t1, t2);
+
+            return Nat256.Eq(x1, t2) ? new SM2P256V1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SM2P256V1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SM2P256V1FieldElement);
+        }
+
+        public virtual bool Equals(SM2P256V1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat256.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Point.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Point.cs
new file mode 100644
index 000000000..916c90633
--- /dev/null
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+    internal class SM2P256V1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SM2P256V1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SM2P256V1FieldElement X1 = (SM2P256V1FieldElement)this.RawXCoord, Y1 = (SM2P256V1FieldElement)this.RawYCoord;
+            SM2P256V1FieldElement X2 = (SM2P256V1FieldElement)b.RawXCoord, Y2 = (SM2P256V1FieldElement)b.RawYCoord;
+
+            SM2P256V1FieldElement Z1 = (SM2P256V1FieldElement)this.RawZCoords[0];
+            SM2P256V1FieldElement Z2 = (SM2P256V1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat256.CreateExt();
+            uint[] t2 = Nat256.Create();
+            uint[] t3 = Nat256.Create();
+            uint[] t4 = Nat256.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SM2P256V1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SM2P256V1Field.Multiply(S2, X2.x, U2);
+
+                SM2P256V1Field.Multiply(S2, Z1.x, S2);
+                SM2P256V1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SM2P256V1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SM2P256V1Field.Multiply(S1, X1.x, U1);
+
+                SM2P256V1Field.Multiply(S1, Z2.x, S1);
+                SM2P256V1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat256.Create();
+            SM2P256V1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SM2P256V1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat256.IsZero(H))
+            {
+                if (Nat256.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SM2P256V1Field.Square(H, HSquared);
+
+            uint[] G = Nat256.Create();
+            SM2P256V1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SM2P256V1Field.Multiply(HSquared, U1, V);
+
+            SM2P256V1Field.Negate(G, G);
+            Nat256.Mul(S1, G, tt1);
+
+            c = Nat256.AddBothTo(V, V, G);
+            SM2P256V1Field.Reduce32(c, G);
+
+            SM2P256V1FieldElement X3 = new SM2P256V1FieldElement(t4);
+            SM2P256V1Field.Square(R, X3.x);
+            SM2P256V1Field.Subtract(X3.x, G, X3.x);
+
+            SM2P256V1FieldElement Y3 = new SM2P256V1FieldElement(G);
+            SM2P256V1Field.Subtract(V, X3.x, Y3.x);
+            SM2P256V1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SM2P256V1Field.Reduce(tt1, Y3.x);
+
+            SM2P256V1FieldElement Z3 = new SM2P256V1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SM2P256V1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SM2P256V1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+            return new SM2P256V1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SM2P256V1FieldElement Y1 = (SM2P256V1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SM2P256V1FieldElement X1 = (SM2P256V1FieldElement)this.RawXCoord, Z1 = (SM2P256V1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat256.Create();
+            uint[] t2 = Nat256.Create();
+
+            uint[] Y1Squared = Nat256.Create();
+            SM2P256V1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat256.Create();
+            SM2P256V1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SM2P256V1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SM2P256V1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SM2P256V1Field.Add(X1.x, Z1Squared, M);
+            SM2P256V1Field.Multiply(M, t1, M);
+            c = Nat256.AddBothTo(M, M, M);
+            SM2P256V1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SM2P256V1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(8, S, 2, 0);
+            SM2P256V1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(8, T, 3, 0, t1);
+            SM2P256V1Field.Reduce32(c, t1);
+
+            SM2P256V1FieldElement X3 = new SM2P256V1FieldElement(T);
+            SM2P256V1Field.Square(M, X3.x);
+            SM2P256V1Field.Subtract(X3.x, S, X3.x);
+            SM2P256V1Field.Subtract(X3.x, S, X3.x);
+
+            SM2P256V1FieldElement Y3 = new SM2P256V1FieldElement(S);
+            SM2P256V1Field.Subtract(S, X3.x, Y3.x);
+            SM2P256V1Field.Multiply(Y3.x, M, Y3.x);
+            SM2P256V1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SM2P256V1FieldElement Z3 = new SM2P256V1FieldElement(M);
+            SM2P256V1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SM2P256V1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SM2P256V1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SM2P256V1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Field.cs b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
index ff6fb6b65..d1ac009b3 100644
--- a/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
@@ -19,7 +19,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         public static void Add(uint[] x, uint[] y, uint[] z)
         {
             uint c = Nat128.Add(x, y, z);
-            if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+            if (c != 0 || (z[3] >= P3 && Nat128.Gte(z, P)))
             {
                 AddPInvTo(z);
             }
@@ -28,7 +28,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
         {
             uint c = Nat256.Add(xx, yy, zz);
-            if (c != 0 || (zz[7] == PExt7 && Nat256.Gte(zz, PExt)))
+            if (c != 0 || (zz[7] >= PExt7 && Nat256.Gte(zz, PExt)))
             {
                 Nat.AddTo(PExtInv.Length, PExtInv, zz);
             }
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         public static void AddOne(uint[] x, uint[] z)
         {
             uint c = Nat.Inc(4, x, z);
-            if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+            if (c != 0 || (z[3] >= P3 && Nat128.Gte(z, P)))
             {
                 AddPInvTo(z);
             }
@@ -46,7 +46,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         public static uint[] FromBigInteger(BigInteger x)
         {
             uint[] z = Nat128.FromBigInteger(x);
-            if (z[3] == P3 && Nat128.Gte(z, P))
+            if (z[3] >= P3 && Nat128.Gte(z, P))
             {
                 Nat128.SubFrom(P, z);
             }
@@ -76,7 +76,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
         {
             uint c = Nat128.MulAddTo(x, y, zz);
-            if (c != 0 || (zz[7] == PExt7 && Nat256.Gte(zz, PExt)))
+            if (c != 0 || (zz[7] >= PExt7 && Nat256.Gte(zz, PExt)))
             {
                 Nat.AddTo(PExtInv.Length, PExtInv, zz);
             }
@@ -179,7 +179,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         public static void Twice(uint[] x, uint[] z)
         {
             uint c = Nat.ShiftUpBit(4, x, 0, z);
-            if (c != 0 || (z[3] == P3 && Nat128.Gte(z, P)))
+            if (c != 0 || (z[3] >= P3 && Nat128.Gte(z, P)))
             {
                 AddPInvTo(z);
             }
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index d9e7882fa..5ea2907e8 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -417,7 +417,20 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 				return inputStream;
             }
-            else
+
+            if (!IsPossiblyBase64(ch))
+            {
+                inputStream.Position = markedPos;
+
+				return new ArmoredInputStream(inputStream);
+            }
+
+			byte[]	buf = new byte[ReadAhead];
+            int		count = 1;
+            int		index = 1;
+
+			buf[0] = (byte)ch;
+            while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0)
             {
                 if (!IsPossiblyBase64(ch))
                 {
@@ -426,51 +439,49 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 					return new ArmoredInputStream(inputStream);
                 }
 
-				byte[]	buf = new byte[ReadAhead];
-                int		count = 1;
-                int		index = 1;
-
-				buf[0] = (byte)ch;
-                while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0)
+				if (ch != '\n' && ch != '\r')
                 {
-                    if (!IsPossiblyBase64(ch))
-                    {
-                        inputStream.Position = markedPos;
+                    buf[index++] = (byte)ch;
+                }
 
-						return new ArmoredInputStream(inputStream);
-                    }
+				count++;
+            }
 
-					if (ch != '\n' && ch != '\r')
-                    {
-                        buf[index++] = (byte)ch;
-                    }
+			inputStream.Position = markedPos;
 
-					count++;
-                }
+			//
+            // nothing but new lines, little else, assume regular armoring
+            //
+            if (count < 4)
+            {
+                return new ArmoredInputStream(inputStream);
+            }
 
-				inputStream.Position = markedPos;
+			//
+            // test our non-blank data
+            //
+            byte[] firstBlock = new byte[8];
 
-				//
-                // nothing but new lines, little else, assume regular armoring
-                //
-                if (count < 4)
-                {
-                    return new ArmoredInputStream(inputStream);
-                }
+			Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length);
 
-				//
-                // test our non-blank data
-                //
-                byte[] firstBlock = new byte[8];
-				Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length);
-				byte[] decoded = Base64.Decode(firstBlock);
+            try
+            {
+                byte[] decoded = Base64.Decode(firstBlock);
 
-				//
+                //
                 // it's a base64 PGP block.
                 //
-				bool hasHeaders = (decoded[0] & 0x80) == 0;
+                bool hasHeaders = (decoded[0] & 0x80) == 0;
 
-				return new ArmoredInputStream(inputStream, hasHeaders);
+                return new ArmoredInputStream(inputStream, hasHeaders);
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new IOException(e.Message);
             }
         }
 
diff --git a/crypto/src/security/CipherUtilities.cs b/crypto/src/security/CipherUtilities.cs
index 3217f3183..de05bc9ef 100644
--- a/crypto/src/security/CipherUtilities.cs
+++ b/crypto/src/security/CipherUtilities.cs
@@ -323,7 +323,7 @@ namespace Org.BouncyCastle.Security
                         "PBEWITHMD5AND256BITAES-CBC-OPENSSL"))
                     {
                         return new PaddedBufferedBlockCipher(
-                            new CbcBlockCipher(new AesFastEngine()));
+                            new CbcBlockCipher(new AesEngine()));
                     }
                 }
             }
@@ -358,7 +358,7 @@ namespace Org.BouncyCastle.Security
             switch (cipherAlgorithm)
             {
                 case CipherAlgorithm.AES:
-                    blockCipher = new AesFastEngine();
+                    blockCipher = new AesEngine();
                     break;
                 case CipherAlgorithm.ARC4:
                     streamCipher = new RC4Engine();
@@ -722,7 +722,7 @@ namespace Org.BouncyCastle.Security
         {
             switch (cipherAlgorithm)
             {
-                case CipherAlgorithm.AES: return new AesFastEngine();
+                case CipherAlgorithm.AES: return new AesEngine();
                 case CipherAlgorithm.BLOWFISH: return new BlowfishEngine();
                 case CipherAlgorithm.CAMELLIA: return new CamelliaEngine();
                 case CipherAlgorithm.CAST5: return new Cast5Engine();
diff --git a/crypto/src/security/MacUtilities.cs b/crypto/src/security/MacUtilities.cs
index fab9b1d41..278f3bec1 100644
--- a/crypto/src/security/MacUtilities.cs
+++ b/crypto/src/security/MacUtilities.cs
@@ -136,7 +136,7 @@ namespace Org.BouncyCastle.Security
 
             if (mechanism == "AESCMAC")
             {
-                return new CMac(new AesFastEngine());
+                return new CMac(new AesEngine());
             }
             if (mechanism == "DESMAC")
             {
diff --git a/crypto/src/security/WrapperUtilities.cs b/crypto/src/security/WrapperUtilities.cs
index ce31ea519..c57632081 100644
--- a/crypto/src/security/WrapperUtilities.cs
+++ b/crypto/src/security/WrapperUtilities.cs
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Security
                     case WrapAlgorithm.RC2WRAP:				return new RC2WrapEngine();
                     case WrapAlgorithm.SEEDWRAP:			return new SeedWrapEngine();
                     case WrapAlgorithm.DESEDERFC3211WRAP:	return new Rfc3211WrapEngine(new DesEdeEngine());
-                    case WrapAlgorithm.AESRFC3211WRAP:		return new Rfc3211WrapEngine(new AesFastEngine());
+                    case WrapAlgorithm.AESRFC3211WRAP:		return new Rfc3211WrapEngine(new AesEngine());
                     case WrapAlgorithm.CAMELLIARFC3211WRAP:	return new Rfc3211WrapEngine(new CamelliaEngine());
                 }
             }
diff --git a/crypto/test/src/asn1/test/MiscTest.cs b/crypto/test/src/asn1/test/MiscTest.cs
index 877925526..553a72ef4 100644
--- a/crypto/test/src/asn1/test/MiscTest.cs
+++ b/crypto/test/src/asn1/test/MiscTest.cs
@@ -12,9 +12,72 @@ namespace Org.BouncyCastle.Asn1.Tests
 {
     [TestFixture]
     public class MiscTest
-        : ITest
+        : SimpleTest
     {
-        public ITestResult Perform()
+        private void DoShouldFailOnExtraData()
+        {
+            // basic construction
+            DerBitString s1 = new DerBitString(new byte[0], 0);
+
+            Asn1Object.FromByteArray(s1.GetEncoded());
+
+            Asn1Object.FromByteArray(new BerSequence(s1).GetEncoded());
+
+            try
+            {
+                Asn1Object obj = Asn1Object.FromByteArray(Arrays.Concatenate(s1.GetEncoded(), new byte[1]));
+                Fail("no exception");
+            }
+            catch (IOException e)
+            {
+                //if (!"Extra data detected in stream".Equals(e.Message))
+                if (!"extra data found after object".Equals(e.Message))
+                {
+                        Fail("wrong exception");
+                }
+            }
+        }
+
+        private void DoDerIntegerTest()
+        {
+            try
+            {
+                new DerInteger(new byte[] { 0, 0, 0, 1});
+            }
+            catch (ArgumentException e)
+            {
+                IsTrue("wrong exc", "malformed integer".Equals(e.Message));
+            }
+
+            try
+            {
+                new DerInteger(new byte[] {(byte)0xff, (byte)0x80, 0, 1});
+            }
+            catch (ArgumentException e)
+            {
+                IsTrue("wrong exc", "malformed integer".Equals(e.Message));
+            }
+
+            try
+            {
+                new DerEnumerated(new byte[] { 0, 0, 0, 1});
+            }
+            catch (ArgumentException e)
+            {
+                IsTrue("wrong exc", "malformed enumerated".Equals(e.Message));
+            }
+
+            try
+            {
+                new DerEnumerated(new byte[] {(byte)0xff, (byte)0x80, 0, 1});
+            }
+            catch (ArgumentException e)
+            {
+                IsTrue("wrong exc", "malformed enumerated".Equals(e.Message));
+            }
+        }
+
+        public override void PerformTest()
         {
             byte[] testIv = { 1, 2, 3, 4, 5, 6, 7, 8 };
 
@@ -29,47 +92,41 @@ namespace Org.BouncyCastle.Asn1.Tests
 
             byte[] data = Base64.Decode("MA4ECAECAwQFBgcIAgIAgAMCBSAWBWhlbGxvMAoECAECAwQFBgcIFgtodHRwOi8vdGVzdA==");
 
-            try
+            MemoryStream bOut = new MemoryStream();
+            Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+            for (int i = 0; i != values.Length; i++)
             {
-                MemoryStream bOut = new MemoryStream();
-                Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+                aOut.WriteObject(values[i]);
+            }
 
-                for (int i = 0; i != values.Length; i++)
-                {
-                    aOut.WriteObject(values[i]);
-                }
+            if (!Arrays.AreEqual(bOut.ToArray(), data))
+            {
+                Fail("Failed data check");
+            }
 
-                if (!Arrays.AreEqual(bOut.ToArray(), data))
-                {
-                    return new SimpleTestResult(false, Name + ": Failed data check");
-                }
+            Asn1InputStream aIn = new Asn1InputStream(bOut.ToArray());
 
-                Asn1InputStream aIn = new Asn1InputStream(bOut.ToArray());
+            for (int i = 0; i != values.Length; i++)
+            {
+                Asn1Object o = aIn.ReadObject();
 
-                for (int i = 0; i != values.Length; i++)
+                if (!values[i].Equals(o))
                 {
-                    Asn1Object o = aIn.ReadObject();
-
-                    if (!values[i].Equals(o))
-                    {
-                        return new SimpleTestResult(false, Name + ": Failed equality test for " + o);
-                    }
-
-                    if (o.GetHashCode() != values[i].GetHashCode())
-                    {
-                        return new SimpleTestResult(false, Name + ": Failed hashCode test for " + o);
-                    }
+                    Fail("Failed equality test for " + o);
                 }
 
-                return new SimpleTestResult(true, Name + ": Okay");
-            }
-            catch (Exception e)
-            {
-                return new SimpleTestResult(false, Name + ": Failed - exception " + e.ToString(), e);
+                if (o.GetHashCode() != values[i].GetHashCode())
+                {
+                    Fail("Failed hashCode test for " + o);
+                }
             }
+
+            DoShouldFailOnExtraData();
+            DoDerIntegerTest();
         }
 
-        public string Name
+        public override string Name
         {
             get { return "Misc"; }
         }
@@ -77,10 +134,7 @@ namespace Org.BouncyCastle.Asn1.Tests
         public static void MainOld(
             string[] args)
         {
-            ITest test = new MiscTest();
-            ITestResult result = test.Perform();
-
-            Console.WriteLine(result);
+            RunTest(new MiscTest());
         }
 #endif
 
diff --git a/crypto/test/src/crypto/examples/DESExample.cs b/crypto/test/src/crypto/examples/DESExample.cs
index c026d3159..788fd643f 100644
--- a/crypto/test/src/crypto/examples/DESExample.cs
+++ b/crypto/test/src/crypto/examples/DESExample.cs
@@ -247,10 +247,11 @@ namespace Org.BouncyCastle.Crypto.Examples
 				outStr.Flush();
 				outStr.Close();
 			}
-			catch (IOException)
+			catch (IOException closing)
 			{
-			}
-		}
+                Console.Error.WriteLine("exception closing resources: " + closing.Message);
+            }
+        }
 
 		/*
 		* This method performs all the encryption and writes
diff --git a/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs b/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
index 6db1fc95e..e7e03b888 100644
--- a/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
+++ b/crypto/test/src/crypto/prng/test/CtrDrbgTest.cs
@@ -149,7 +149,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C")
                 .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 128,
+                    new AesEngine(), 128,
                     new Bit256EntropyProvider().Get(256),
                     false,
                     "2021222324252627",
@@ -161,7 +161,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                     }
                 ),
                 new DrbgTestVector(
-                    new AesFastEngine(), 128,
+                    new AesEngine(), 128,
                     new Bit256EntropyProvider().Get(256),
                     false,
                     "2021222324252627",
@@ -175,7 +175,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")
                 .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 128,
+                    new AesEngine(), 128,
                     new Bit256EntropyProvider().Get(256),
                     false,
                     "2021222324252627",
@@ -188,7 +188,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 )
                .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 128,
+                    new AesEngine(), 128,
                     new Bit256EntropyProvider().Get(256),
                     true,
                     "2021222324252627",
@@ -200,7 +200,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                     }
                 ),
                 new DrbgTestVector(
-                    new AesFastEngine(), 128,
+                    new AesEngine(), 128,
                     new Bit256EntropyProvider().Get(256),
                     true,
                     "2021222324252627",
@@ -214,7 +214,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")
                 .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 128,
+                    new AesEngine(), 128,
                     new Bit256EntropyProvider().Get(256),
                     true,
                     "2021222324252627",
@@ -227,7 +227,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 )
                .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 192,
+                    new AesEngine(), 192,
                     new Bit320EntropyProvider().Get(320),
                     false,
                     "202122232425262728292A2B",
@@ -240,7 +240,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 )
                 .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 192,
+                    new AesEngine(), 192,
                     new Bit320EntropyProvider().Get(320),
                     true,
                     "202122232425262728292A2B",
@@ -253,7 +253,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 )
                 .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 256,
+                    new AesEngine(), 256,
                     new Bit384EntropyProvider().Get(384),
                     false,
                     "202122232425262728292A2B2C2D2E2F",
@@ -268,7 +268,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
                 .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 256,
+                    new AesEngine(), 256,
                     new Bit384EntropyProvider().Get(384),
                     true,
                     "202122232425262728292A2B2C2D2E2F",
@@ -282,7 +282,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
                 .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 256,
+                    new AesEngine(), 256,
                     new Bit384EntropyProvider().Get(384),
                     true,
                     "202122232425262728292A2B2C2D2E2F",
@@ -295,7 +295,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 )
                 .SetPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 256,
+                    new AesEngine(), 256,
                     new Bit384EntropyProvider().Get(384),
                     true,
                     "202122232425262728292A2B2C2D2E2F",
@@ -310,7 +310,7 @@ namespace Org.BouncyCastle.Crypto.Prng.Test
                 .AddAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F")
                 .AddAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"),
                 new DrbgTestVector(
-                    new AesFastEngine(), 256,
+                    new AesEngine(), 256,
                     new Bit384EntropyProvider().Get(384),
                     true,
                     "202122232425262728292A2B2C2D2E2F",
diff --git a/crypto/test/src/crypto/test/CMacTest.cs b/crypto/test/src/crypto/test/CMacTest.cs
index 2e76a188f..1e4154e77 100644
--- a/crypto/test/src/crypto/test/CMacTest.cs
+++ b/crypto/test/src/crypto/test/CMacTest.cs
@@ -57,7 +57,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
         public override void PerformTest()
         {
-            IBlockCipher cipher = new AesFastEngine();
+            IBlockCipher cipher = new AesEngine();
             IMac mac = new CMac(cipher, 128);
 
             //128 bytes key
diff --git a/crypto/test/src/crypto/test/DSTU7564Test.cs b/crypto/test/src/crypto/test/DSTU7564Test.cs
new file mode 100644
index 000000000..98f0bbdea
--- /dev/null
+++ b/crypto/test/src/crypto/test/DSTU7564Test.cs
@@ -0,0 +1,645 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for SHA-384 from FIPS Draft 180-2.
+     *
+     * Note, the first two vectors are _not_ from the draft, the last three are.
+     */
+    [TestFixture]
+    public class Dstu7564Test
+        : DigestTest
+    {
+        private static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+        };
+
+        private static string[] digests =
+        {
+            "cd5101d1ccdf0d1d1f4ada56e888cd724ca1a0838a3521e7131d4fb78d0f5eb6",
+            "c51a1d639596fb613d86557314a150c40f8fff3de48bc93a3b03c161f4105ee4",
+            "0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04",
+            "02621dbb53f2c7001be64d7308ecb80d21ba7797c92e98d1efc240d41e4c414b"
+        };
+
+        public Dstu7564Test()
+            : base(new Dstu7564Digest(256), messages, digests)
+        {
+        }
+
+
+        public override void PerformTest()
+        {
+            base.PerformTest();
+   
+               hash256Tests();
+        hash384Tests();
+        hash512Tests();
+        macTests();
+        overflowTest();
+    }
+
+    private void overflowTest()
+    {
+            int macBitSize = 256;
+            byte[] input = new byte[1024];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+            byte[] key = Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100");
+
+            byte[] expectedMac = Hex.Decode("165382df70adcb040b17c1aced117d26d598b239ab631271a05f6d0f875ae9ea");
+            byte[] mac = new byte[macBitSize / 8];
+
+            Dstu7564Mac dstu7564mac = new Dstu7564Mac(macBitSize);
+
+            dstu7564mac.Init(new KeyParameter(key));
+            dstu7564mac.BlockUpdate(input, 0, input.Length);
+            dstu7564mac.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(expectedMac, mac))
+            {
+                Fail("Failed overflow test 1 - expected "
+                    + Hex.ToHexString(expectedMac)
+                    + " got " + Hex.ToHexString(mac));
+            }
+
+            macBitSize = 256;
+            input = new byte[1023];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+            key = Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100");
+
+            expectedMac = Hex.Decode("ed45f163e694d990d2d835dca2f3f869a55a31396c8138161b190d5914d50686");
+            mac = new byte[macBitSize / 8];
+
+            dstu7564mac = new Dstu7564Mac(macBitSize);
+
+            dstu7564mac.Init(new KeyParameter(key));
+            dstu7564mac.BlockUpdate(input, 0, input.Length);
+            dstu7564mac.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(expectedMac, mac))
+            {
+                Fail("Failed overflow test 2 - expected "
+                    + Hex.ToHexString(expectedMac)
+                    + " got " + Hex.ToHexString(mac));
+            }
+
+            Dstu7564Digest digest = new Dstu7564Digest(macBitSize);
+            byte[] expectedDigest = Hex.Decode("6bfc5ec8c1f5963fbed89da115d86e9330634eca341dd42fd94a7007e4af7942");
+            byte[] digestBuf = new byte[macBitSize / 8];
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 3 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            expectedDigest = Hex.Decode("6f8f0a3f8261af77581ab01cb89d4cb5ed87ca1d9954f11d5586e94b45c82fb8");
+
+            input = new byte[51];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 4 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[52];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("8b6fe2ba77e684b2a1ac82232f4efc49f681cd18c82a0cfff530186a2fc642d2");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 5 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+
+            input = new byte[53];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("837f2b0cbe39a4defdfcb44272288d4091cab850161c70695d7831fc5f00e171");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 6 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[54];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("21d423d5b8c7f18a0da42cdd95b36b66344125e2adc6edeab5899926442113bc");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 7 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[55];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("0e7bf74464b81b3ae7d904170776d29f4b02a7227da578dd562d01027af7fd0e");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 8 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[56];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("badea1f49cbcec94acec52b4c695acdddd786cca5a6763929f341a58c5134b3b");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 9 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[57];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("a13b5f6f53ee043292ed65b66c1d49759be4d2fe0c2f6148f2416487965f7bde");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 10 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[63];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("03a44a02c9ffafb43addb290bbcf3b8168f624e8cbd332dc6a9dc7df9d39cbc2");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 11 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[64];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("08f4ee6f1be6903b324c4e27990cb24ef69dd58dbe84813ee0a52f6631239875");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 12 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+
+            input = new byte[65];
+            for (int i = 0; i != input.Length; i++)
+            {
+                input[i] = (byte)(i & 0xff);
+            }
+
+            expectedDigest = Hex.Decode("a81c2fb92351f370050b7c36cd51736d5603a50ec1106cbd5fe1c9be2e5c77a6");
+
+            digest.BlockUpdate(input, 0, input.Length);
+            digest.DoFinal(digestBuf, 0);
+
+            if (!Arrays.AreEqual(expectedDigest, digestBuf))
+            {
+                Fail("Failed overflow test 13 - expected "
+                    + Hex.ToHexString(expectedDigest)
+                    + " got " + Hex.ToHexString(digestBuf));
+            }
+        }
+
+    private void macTests()
+    {
+
+        //test1
+        int macBitSize = 256;
+        byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E");
+        byte[] key = Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100");
+
+        byte[] expectedMac = Hex.Decode("B60594D56FA79BA210314C72C2495087CCD0A99FC04ACFE2A39EF669925D98EE");
+        byte[] mac = new byte[macBitSize / 8];
+
+        Dstu7564Mac dstu7564mac = new Dstu7564Mac(macBitSize);
+
+        dstu7564mac.Init(new KeyParameter(key));
+        dstu7564mac.BlockUpdate(input, 0, input.Length);
+        dstu7564mac.DoFinal(mac, 0);
+
+        if (!Arrays.AreEqual(expectedMac, mac))
+        {
+            Fail("Failed mac test 1 - expected "
+                + Hex.ToHexString(expectedMac)
+                + " got " + Hex.ToHexString(mac));
+        }
+
+            //test1a
+            input = Hex.Decode("0001020304050607");
+            key = Hex.Decode("08F4EE6F1BE6903B324C4E27990CB24EF69DD58DBE84813EE0A52F6631239875");
+
+            expectedMac = Hex.Decode("383A0B11989ABF61B2CF3EB489351EB7C9AEF70CF5A9D6DBD90F340FF151BA2D");
+            mac = new byte[macBitSize / 8];
+
+            dstu7564mac = new Dstu7564Mac(macBitSize);
+
+            dstu7564mac.Init(new KeyParameter(key));
+            dstu7564mac.BlockUpdate(input, 0, input.Length);
+            dstu7564mac.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(expectedMac, mac))
+            {
+                Fail("Failed mac test 1a - expected "
+                    + Hex.ToHexString(expectedMac)
+                    + " got " + Hex.ToHexString(mac));
+            }
+
+            //test 2
+            macBitSize = 384;
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E");
+        key = Hex.Decode("2F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100");
+
+        expectedMac = Hex.Decode("BEBFD8D730336F043ABACB41829E79A4D320AEDDD8D14024D5B805DA70C396FA295C281A38B30AE728A304B3F5AE490E");
+        mac = new byte[macBitSize / 8];
+
+        dstu7564mac = new Dstu7564Mac(macBitSize);
+
+        dstu7564mac.Init(new KeyParameter(key));
+        dstu7564mac.BlockUpdate(input, 0, input.Length);
+        dstu7564mac.DoFinal(mac, 0);
+
+        if (!Arrays.AreEqual(expectedMac, mac))
+        {
+            Fail("Failed mac test 2 - expected "
+                + Hex.ToHexString(expectedMac)
+                + " got " + Hex.ToHexString(mac));
+        }
+
+        //test 3
+        macBitSize = 512;
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E");
+        key = Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100");
+
+        expectedMac = Hex.Decode("F270043C06A5C37E65D9D791C5FBFB966E5EE709F8F54019C9A55B76CA40B70100579F269CEC24E347A9D864614CF3ABBF6610742E4DB3BD2ABC000387C49D24");
+        mac = new byte[macBitSize / 8];
+
+        dstu7564mac = new Dstu7564Mac(macBitSize);
+
+        dstu7564mac.Init(new KeyParameter(key));
+        dstu7564mac.BlockUpdate(input, 0, input.Length);
+        dstu7564mac.DoFinal(mac, 0);
+
+        if (!Arrays.AreEqual(expectedMac, mac))
+        {
+            Fail("Failed mac test 3 - expected "
+                + Hex.ToHexString(expectedMac)
+                + " got " + Hex.ToHexString(mac));
+        }
+    }
+
+    private void hash512Tests()
+    {
+
+        int hashBitSize = 512;
+
+        //test 1
+        byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F");
+        byte[] expectedHash = Hex.Decode("3813E2109118CDFB5A6D5E72F7208DCCC80A2DFB3AFDFB02F46992B5EDBE536B3560DD1D7E29C6F53978AF58B444E37BA685C0DD910533BA5D78EFFFC13DE62A");
+        byte[] hash = new byte[hashBitSize / 8];
+
+
+        Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-512 test 1 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 2
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F");
+        expectedHash = Hex.Decode("76ED1AC28B1D0143013FFA87213B4090B356441263C13E03FA060A8CADA32B979635657F256B15D5FCA4A174DE029F0B1B4387C878FCC1C00E8705D783FD7FFE");
+        hash = new byte[hashBitSize / 8];
+
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-512 test 2 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 3
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF");
+        expectedHash = Hex.Decode("0DD03D7350C409CB3C29C25893A0724F6B133FA8B9EB90A64D1A8FA93B56556611EB187D715A956B107E3BFC76482298133A9CE8CBC0BD5E1436A5B197284F7E");
+        hash = new byte[hashBitSize / 8];
+
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-512 test 3 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 4
+        input = Hex.Decode("FF");
+        expectedHash = Hex.Decode("871B18CF754B72740307A97B449ABEB32B64444CC0D5A4D65830AE5456837A72D8458F12C8F06C98C616ABE11897F86263B5CB77C420FB375374BEC52B6D0292");
+        hash = new byte[hashBitSize / 8];
+
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-512 test 4 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 5
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF");
+        expectedHash = Hex.Decode("B189BFE987F682F5F167F0D7FA565330E126B6E592B1C55D44299064EF95B1A57F3C2D0ECF17869D1D199EBBD02E8857FB8ADD67A8C31F56CD82C016CF743121");
+        hash = new byte[hashBitSize / 8];
+
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-512 test 5 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+
+        //test 6
+        input = Hex.Decode("");
+        expectedHash = Hex.Decode("656B2F4CD71462388B64A37043EA55DBE445D452AECD46C3298343314EF04019BCFA3F04265A9857F91BE91FCE197096187CEDA78C9C1C021C294A0689198538");
+        hash = new byte[hashBitSize / 8];
+
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-512 test 6 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+    }
+
+    private void hash384Tests()
+    {
+
+        int hashBitSize = 384;
+
+        //test 1
+        byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E");
+        byte[] expectedHash = Hex.Decode("D9021692D84E5175735654846BA751E6D0ED0FAC36DFBC0841287DCB0B5584C75016C3DECC2A6E47C50B2F3811E351B8");
+        byte[] hash = new byte[hashBitSize / 8];
+
+
+        Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-384 test 1 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+    }
+
+    private void hash256Tests()
+    {
+
+        int hashBitSize = 256;
+
+        //test 1
+        byte[] input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F");
+        byte[] expectedHash = Hex.Decode("08F4EE6F1BE6903B324C4E27990CB24EF69DD58DBE84813EE0A52F6631239875");
+        byte[] hash = new byte[hashBitSize / 8];
+
+
+        Dstu7564Digest dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-256 test 1 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 2
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F");
+        expectedHash = Hex.Decode("0A9474E645A7D25E255E9E89FFF42EC7EB31349007059284F0B182E452BDA882");
+        hash = new byte[hashBitSize / 8];
+
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-256 test 2 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 3
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF");
+        expectedHash = Hex.Decode("D305A32B963D149DC765F68594505D4077024F836C1BF03806E1624CE176C08F");
+        hash = new byte[hashBitSize / 8];
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-256 test 3 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 4
+        input = Hex.Decode("FF");
+        expectedHash = Hex.Decode("EA7677CA4526555680441C117982EA14059EA6D0D7124D6ECDB3DEEC49E890F4");
+        hash = new byte[hashBitSize / 8];
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-256 test 4 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 5
+        input = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E");
+        expectedHash = Hex.Decode("1075C8B0CB910F116BDA5FA1F19C29CF8ECC75CAFF7208BA2994B68FC56E8D16");
+        hash = new byte[hashBitSize / 8];
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-256 test 5 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+
+        //test 6
+        input = Hex.Decode("");
+        expectedHash = Hex.Decode("CD5101D1CCDF0D1D1F4ADA56E888CD724CA1A0838A3521E7131D4FB78D0F5EB6");
+        hash = new byte[hashBitSize / 8];
+
+        dstu7564 = new Dstu7564Digest(hashBitSize);
+        dstu7564.BlockUpdate(input, 0, input.Length);
+        dstu7564.DoFinal(hash, 0);
+
+        if (!Arrays.AreEqual(expectedHash, hash))
+        {
+            Fail("Failed hash-256 test 6 - expected "
+                + Hex.ToHexString(expectedHash)
+                + " got " + Hex.ToHexString(hash));
+        }
+    }
+
+    protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new Dstu7564Digest((Dstu7564Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Dstu7564Test());
+        }
+
+        [Test]
+        public void Dstu7564TestFunction()
+        {
+            string resultText = Perform().ToString();
+            Console.WriteLine(resultText);
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/DSTU7624Test.cs b/crypto/test/src/crypto/test/DSTU7624Test.cs
new file mode 100644
index 000000000..67dcd4420
--- /dev/null
+++ b/crypto/test/src/crypto/test/DSTU7624Test.cs
@@ -0,0 +1,481 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class Dstu7624Test : CipherTest
+    {
+        public Dstu7624Test()
+            : base(tests, new Dstu7624Engine(256), new KeyParameter(new byte[32])) { }
+
+
+
+        internal static SimpleTest[] tests = new SimpleTest[]
+          {
+
+               //ECB mode
+               /*
+               new KBlockCipherVectorTest(0, new Dstu7624Engine(128, 128), new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), "101112131415161718191A1B1C1D1E1F", "81BF1C7D779BAC20E1C9EA39B4D2AD06"),
+               new KBlockCipherVectorTest(1, new Dstu7624Engine(128, 256), new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F", "58EC3E091000158A1148F7166F334F14"),
+               new KBlockCipherVectorTest(2, new Dstu7624Engine(256, 256), new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F", "F66E3D570EC92135AEDAE323DCBD2A8CA03963EC206A0D5A88385C24617FD92C"),
+               new KBlockCipherVectorTest(3, new Dstu7624Engine(256, 512), new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", "606990E9E6B7B67A4BD6D893D72268B78E02C83C3CD7E102FD2E74A8FDFE5DD9"),
+               new KBlockCipherVectorTest(4, new Dstu7624Engine(512, 512), new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F", "4A26E31B811C356AA61DD6CA0596231A67BA8354AA47F3A13E1DEEC320EB56B895D0F417175BAB662FD6F134BB15C86CCB906A26856EFEB7C5BC6472940DD9D9"),
+            */
+               //CTR mode
+              // new BlockCipherVectorTest(5, new KCtrBlockCipher(new Dstu7624Engine(128, 128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"),
+                  /*      
+               //CFB mode (THERE ARE DIFFERENCE IN LAST BLOCK PROCESSING, SO KBufferedBlockCipher WRAPPER IS USED)
+               new KBlockCipherVectorTest(6, new KCfbBlockCipher(new Dstu7624Engine(128, 128), 128), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "A19E3E5E53BE8A07C9E0C01298FF83291F8EE6212110BE3FA5C72C88A082520B265570FE28680719D9B4465E169BC37A"),
+               new KBlockCipherVectorTest(7, new KCfbBlockCipher(new Dstu7624Engine(256, 256), 128), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90", "E07821AF642F4B1DC071166F2D329763C2CF3B9E39CD0B52BDD33A0DC7B6B6BB201C4A1CD0F5DCB693ABEEA120DACA3A29C73D1D6E87FD75B7DE9E3BE4D256791C2E44583DE8E061E45834A24262BDEBBE"),
+               new KBlockCipherVectorTest(8, new KCfbBlockCipher(new Dstu7624Engine(128, 256), 64), new ParametersWithIV(new KeyParameter(Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("2F2E2D2C2B2A29282726252423222120")), "26319A368D85DE43DD5FDB928D91A441493D8CE07B64797C8F9676C5921CD1EA743F5E2777C327AC58", "5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837"),
+               new KBlockCipherVectorTest(9, new KCfbBlockCipher(new Dstu7624Engine(256, 256), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120")), "7758A939DD6BD00CAF9153E5A5D5A66129105CA1EA54A97C06FA4A40960A068F61C3E424DE950151AC46879D84A3BCC24EC8FB69008DAF016EF9832FFD3DB39D02185FDB782DC28EAC27B35179FCA40640", "9F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F"),
+               new KBlockCipherVectorTest(10, new KCfbBlockCipher(new Dstu7624Engine(256, 512), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")), "606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0", "0008F28A82D2D01D23BFB2F8BB4F06D8FE73BA4F48A2977585570ED3818323A6DBAD3D9DD580D9D8F787CE55FAB90735F6B2D6152D56C0C787E6F4B6A2F557DF707A671D06AED196DD7D7E2320D8E45C4C"),
+               new KBlockCipherVectorTest(11, new KCfbBlockCipher(new Dstu7624Engine(256, 512), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "98E122708FDABB1B1A5765C396DC79D7573221EC486ADDABD1770B147A6DD00BDD5E4F1496D4D573923F9809EEEEF46B063C64A5E875E77E65EC6832ECE3C24A4B8FD40B04088CBEE2CDECE4DC3CC5573A", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F"),
+               new KBlockCipherVectorTest(12, new KCfbBlockCipher(new Dstu7624Engine(512, 512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0", "CAA761980599B3ED2E945C41891BAD95F72B11C73ED26536A6847458BC76C827357156B4B3FE0DC1877F5B9F17B866C37B21D89531DB48007D05DEC928B06766C67D6F3F4C2B82D7A836FAD160905C1C7576243877DC3ADE4AA057966E0023F069"),
+               new KBlockCipherVectorTest(13, new KCfbBlockCipher(new Dstu7624Engine(512, 512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "06C061A4A66DFC0910034B3CFBDC4206D8908241C56BF41C4103CFD6DF322210B87F57EAE9F9AD815E606a7D1E8E6BD7CB1EBFBDBCB085C2D06BF3CC1586CB2E88C9155E95B4872D86B49D80F5745B605EAF488AA520A717A92F4D68838E42C995", "EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F"),
+               */
+               //CBC mode (PADDING NOT SUPPORTED)
+               new BlockCipherVectorTest(14, new CbcBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "A73625D7BE994E85469A9FAABCEDAAB6DBC5F65DD77BB35E06BD7D1D8EAFC8624D6CB31CE189C82B8979F2936DE9BF14"),
+               new BlockCipherVectorTest(15, new CbcBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("0F0E0D0C0B0A09080706050403020100")), Hex.Decode("1F1E1D1C1B1A19181716151413121110")), "88F2F048BA696170E3818915E0DBC0AFA6F141FEBC2F817138DA4AAB2DBF9CE490A488C9C82AC83FB0A6C0EEB64CFD22", "4F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120"),
+               new BlockCipherVectorTest(16, new CbcBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.Decode("202122232425262728292A2B2C2D2E2F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D8000", "13EA15843AD14C50BC03ECEF1F43E398E4217752D3EB046AC393DACC5CA1D6FA0EB9FCEB229362B4F1565527EE3D8433"),
+               new BlockCipherVectorTest(17, new CbcBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("2F2E2D2C2B2A29282726252423222120")), "BC8F026FC603ECE05C24FDE87542730999B381870882AC0535D4368C4BABD81B884E96E853EE7E055262D9D204FBE212", "5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A39383736353433323130"),
+               new BlockCipherVectorTest(18, new CbcBlockCipher(new Dstu7624Engine(256)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F", "9CDFDAA75929E7C2A5CFC1BF16B42C5AE3886D0258E8C577DC01DAF62D185FB999B9867736B87110F5F1BC7481912C593F48FF79E2AFDFAB9F704A277EC3E557B1B0A9F223DAE6ED5AF591C4F2D6FB22E48334F5E9B96B1A2EA5200F30A406CE"),
+               new BlockCipherVectorTest(19, new CbcBlockCipher(new Dstu7624Engine(256)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")), "606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF", "B8A2474578C2FEBF3F94703587BD5FDC3F4A4D2F43575B6144A1E1031FB3D1452B7FD52F5E3411461DAC506869FF8D2FAEF4FEE60379AE00B33AA3EAF911645AF8091CD8A45D141D1FB150E5A01C1F26FF3DBD26AC4225EC7577B2CE57A5B0FF"),
+               new BlockCipherVectorTest(20, new CbcBlockCipher(new Dstu7624Engine(256)), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "C69A59E10D00F087319B62288A57417C074EAD07C732A87055F0A5AD2BB288105705C45E091A9A6726E9672DC7D8C76FC45C782BCFEF7C39D94DEB84B17035BC8651255A0D34373451B6E1A2C827DB97566C9FF5506C5579F982A0EFC5BA7C28", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160"),
+               new BlockCipherVectorTest(21, new CbcBlockCipher(new Dstu7624Engine(512)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF", "D4739B829EF901B24C1162AE4FDEF897EDA41FAC7F5770CDC90E1D1CDF124E8D7831E06B4498A4B6F6EC815DF2461DC99BB0449B0F09FCAA2C84090534BCC9329626FD74EF8F0A0BCB5765184629C3CBF53B0FB134F6D0421174B1C4E884D1CD1069A7AD19752DCEBF655842E79B7858BDE01390A760D85E88925BFE38B0FA57"),
+               new BlockCipherVectorTest(22, new CbcBlockCipher(new Dstu7624Engine(512)), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "5D5B3E3DE5BAA70E0A0684D458856CE759C6018D0B3F087FC1DAC101D380236DD934F2880B02D56A575BCA35A0CE4B0D9BA1F4A39C16CA7D80D59956630F09E54EC91E32B6830FE08323ED393F8028D150BF03CAD0629A5AFEEFF6E44257980618DB2F32B7B2B65B96E8451F1090829D2FFFC615CC1581E9221438DCEAD1FD12", "FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A89888786858483828180"),
+
+               //OFB mode
+               new BlockCipherVectorTest(23, new OfbBlockCipher(new Dstu7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "A19E3E5E53BE8A07C9E0C01298FF832953205C661BD85A51F3A94113BC785CAB634B36E89A8FDD16A12E4467F5CC5A26"),
+               new BlockCipherVectorTest(24, new OfbBlockCipher(new Dstu7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.Decode("0F0E0D0C0B0A09080706050403020100")), Hex.Decode("1F1E1D1C1B1A19181716151413121110")), "649A1EAAE160AF20F5B3EF2F58D66C1178B82E00D26F30689C8EC22E8E86E9CBB0BD4FFEE39EB13C2311276A906DD636", "4F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120"),
+               new BlockCipherVectorTest(25, new OfbBlockCipher(new Dstu7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("2F2E2D2C2B2A29282726252423222120")), "1A66CFBFEC00C6D52E39923E858DD64B214AB787798D3D5059A6B498AD66B34EAC48C4074BEC0D98C6", "5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837"),
+               new BlockCipherVectorTest(26, new OfbBlockCipher(new Dstu7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90", "B62F7F144A8C6772E693A96890F064C3F06831BF743F5B0DD061067F3D22877331AA6A99D939F05B7550E9402BD1615CC7B2D4A167E83EC0D8A894F92C72E176F3880B61C311D69CE1210C59184E818E19"),
+               new BlockCipherVectorTest(27, new OfbBlockCipher(new Dstu7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120")), "7758A939DD6BD00CAF9153E5A5D5A66129105CA1EA54A97C06FA4A40960A068F55E34F9339A14436216948F92FA2FB5286D3AB1E81543FC0018A0C4E8C493475F4D35DCFB0A7A5377F6669B857CDC978E4", "9F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F"),
+               new BlockCipherVectorTest(28, new OfbBlockCipher(new Dstu7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")), "606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0", "0008F28A82D2D01D23BFB2F8BB4F06D8FE73BA4F48A2977585570ED3818323A668883C9DCFF610CC7E3EA5C025FBBC5CA6520F8F11CA35CEB9B07031E6DBFABE39001E9A3CC0A24BBC565939592B4DEDBD"),
+               new BlockCipherVectorTest(29, new OfbBlockCipher(new Dstu7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "98E122708FDABB1B1A5765C396DC79D7573221EC486ADDABD1770B147A6DD00B5FBC4F1EC68C59775B7AAA4D43C4CCE4F396D982DF64D30B03EF6C3B997BA0ED940BBC590BD30D64B5AE207147D71086B5", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F"),
+               new BlockCipherVectorTest(30, new OfbBlockCipher(new Dstu7624Engine(512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0", "CAA761980599B3ED2E945C41891BAD95F72B11C73ED26536A6847458BC76C827357156B4B3FE0DC1877F5B9F17B866C37B21D89531DB48007D05DEC928B06766C014BB9080385EDF0677E48A0A39B5E7489E28E82FFFD1F84694F17296CB701656"),
+               new BlockCipherVectorTest(31, new OfbBlockCipher(new Dstu7624Engine(512), 512), new ParametersWithIV(new KeyParameter(Hex.Decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.Decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "06C061A4A66DFC0910034B3CFBDC4206D8908241C56BF41C4103CFD6DF322210B87F57EAE9F9AD815E606A7D1E8E6BD7CB1EBFBDBCB085C2D06BF3CC1586CB2EE1D81D38437F425131321647E42F5DE309D33F25B89DE37124683E4B44824FC56D", "EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F"),
+
+               //CTR mode
+               new BlockCipherVectorTest(24, new KCtrBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"),
+               new BlockCipherVectorTest(25, new KCtrBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51"),
+               new StreamCipherVectorTest(26, new KCtrBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"),
+               new StreamCipherVectorTest(27, new KCtrBlockCipher(new Dstu7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.Decode("000102030405060708090A0B0C0D0E0F")), Hex.Decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51")
+        };
+
+        public override ITestResult Perform()
+        {
+
+            ITestResult result = base.Perform();
+
+            result = MacTests(); //Mac tests
+
+            result = KeyWrapTests(); //Key wrapping tests
+
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+            else
+            {
+                return new SimpleTestResult(true, Name + ": Okay");
+            }
+
+        }
+
+        private ITestResult MacTests()
+        {
+            //MAC mode (PADDING NOT SUPPORTED)
+            //test 1
+            byte[] key = Hex.Decode("000102030405060708090A0B0C0D0E0F");
+
+            byte[] authtext = Hex.Decode("202122232425262728292A2B2C2D2E2F" +
+                                         "303132333435363738393A3B3C3D3E3F" +
+                                         "404142434445464748494A4B4C4D4E4F");
+
+            byte[] expectedMac = Hex.Decode("123B4EAB8E63ECF3E645A99C1115E241");
+
+            byte[] mac = new byte[128 / 8];
+
+            Dstu7624Mac dstu7624Mac = new Dstu7624Mac(128, 128);
+            dstu7624Mac.Init(new KeyParameter(key));
+            dstu7624Mac.BlockUpdate(authtext, 0, authtext.Length);
+            dstu7624Mac.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(mac, expectedMac))
+            {
+                return new SimpleTestResult(false, Name + ": Failed MAC test 1 - expected "
+                     + Hex.ToHexString(expectedMac)
+                     + " got " + Hex.ToHexString(mac));
+            }
+
+
+            //test 2
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F" +
+                             "101112131415161718191A1B1C1D1E1F" +
+                             "202122232425262728292A2B2C2D2E2F" +
+                             "303132333435363738393A3B3C3D3E3F");
+
+            authtext = Hex.Decode("404142434445464748494A4B4C4D4E4F" +
+                                  "505152535455565758595A5B5C5D5E5F" +
+                                  "606162636465666768696A6B6C6D6E6F" +
+                                  "707172737475767778797A7B7C7D7E7F" +
+                                  "808182838485868788898A8B8C8D8E8F" +
+                                  "909192939495969798999A9B9C9D9E9F" +
+                                  "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" +
+                                  "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF");
+
+            expectedMac = Hex.Decode("7279FA6BC8EF7525B2B35260D00A1743");
+
+            dstu7624Mac = new Dstu7624Mac(512, 128);
+            dstu7624Mac.Init(new KeyParameter(key));
+            dstu7624Mac.BlockUpdate(authtext, 0, authtext.Length);
+            dstu7624Mac.DoFinal(mac, 0);
+
+            if (!Arrays.AreEqual(mac, expectedMac))
+            {
+                return new SimpleTestResult(false, Name + ": Failed MAC test 2 - expected "
+                     + Hex.ToHexString(expectedMac)
+                     + " got " + Hex.ToHexString(mac));
+            }
+        
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+        private ITestResult KeyWrapTests()
+        {
+            //KW mode (PADDING NOT SUPPORTED)
+            //test 1
+            byte[] key = Hex.Decode("000102030405060708090A0B0C0D0E0F");
+            byte[] textToWrap = Hex.Decode("101112131415161718191A1B1C1D1E1F");
+            byte[] expectedWrappedText = Hex.Decode("1DC91DC6E52575F6DBED25ADDA95A1B6AD3E15056E489738972C199FB9EE2913");
+
+            byte[] output = new byte[expectedWrappedText.Length];
+
+            Dstu7624WrapEngine wrapper = new Dstu7624WrapEngine(128);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 1 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 1 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            //test 2
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F");
+            textToWrap = Hex.Decode("101112131415161718191A1B1C1D1E1F20219000000000000000800000000000");
+            expectedWrappedText = Hex.Decode("0EA983D6CE48484D51462C32CC61672210FCC44196ABE635BAF878FDB83E1A63114128585D49DB355C5819FD38039169");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 2 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 2 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+
+            //test 3
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+            textToWrap = Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F");
+            expectedWrappedText = Hex.Decode("2D09A7C18E6A5A0816331EC27CEA596903F77EC8D63F3BDB73299DE7FD9F4558E05992B0B24B39E02EA496368E0841CC1E3FA44556A3048C5A6E9E335717D17D");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(128);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 3 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 3 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            //test 4
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+            textToWrap = Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464E8040000000000020");
+            expectedWrappedText = Hex.Decode("37E3EECB91150C6FA04CFD19D6FC57B7168C9FA5C5ED18601C68EE4AFD7301F8C8C51D7A0A5CD34F6FAB0D8AF11845CC1E4B16E0489FDA1D76BA4EFCFD161F76");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(128);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 4 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 4 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            //test 5
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+            textToWrap = Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F");
+            expectedWrappedText = Hex.Decode("BE59D3C3C31B2685A8FA57CD000727F16AF303F0D87BC2D7ABD80DC2796BBC4CDBC4E0408943AF4DAF7DE9084DC81BFEF15FDCDD0DF399983DF69BF730D7AE2A199CA4F878E4723B7171DD4D1E8DF59C0F25FA0C20946BA64F9037D724BB1D50B6C2BD9788B2AF83EF6163087CD2D4488BC19F3A858D813E3A8947A529B6D65D");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(256);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 5 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 5 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+
+            //test 6
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+            textToWrap = Hex.Decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F708802000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000");
+            expectedWrappedText = Hex.Decode("CC41D643B08592F509432E3C6F4B73156907A53B9FFB99B157DEC708F917AEA1E41D76475EDFB138A8B0220A152B673E9713DE7A2791E3573FE257C3FF3C0DAA9AD13477E52770F54CBF94D1603AED7CA876FB7913BC359D2B89562299FA92D32A9C17DBE4CC21CCE097089B9FBC245580D6DB59F8731D864B604E654397E5F5E7A79A6A777C75856039C8C86140D0CB359CA3923D902D08269F8D48E7F0F085");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(256);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 6 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 6 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+
+            //test 7
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F");
+            textToWrap = Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F");
+            expectedWrappedText = Hex.Decode("599217EB2B5270ECEF0BB716D70E251234A2451CE04FCFBAEEA92022C581F19B7C9386BB7476B4AD721D40778F49062C3605F1E8FAC9F3F3AC04E46E89E1844DBF4F18FA9303B288741ABD71013CF208F31B4C76FBE342F89B1ABFD97E830457555651B74D3CCDBF94CC5E5EEC22821536A96F44C8BC4346B0271303E67FD313");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(256);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 7 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 7 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            //test 8
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F");
+            textToWrap = Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F908802000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000");
+            expectedWrappedText = Hex.Decode("B92E58F53C38F7D23F1068FA98B921AC800AD0D1947BD620700D0B6088F87D03D6A516F54198154D0C71169C2BCF520F3DF3DF527FC23E800E9A65158D45BB253A3BD0493E4822DF0DB5A366BC2F47551C5D477DDDE724A0B869F562223CEDB9D4AA36C750FA864ADF938273FBC859F7D4930F6B70C6474304AB670BA32CB0C41023769338A29EA1555F526CDFEB75C72212CD2D29F4BA49C2A62ACBE4F3272B");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(256);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 8 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 8 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            //test 9
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F");
+            textToWrap = Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF");
+            expectedWrappedText = Hex.Decode("9618AE6065069D5054464040F17337D58BEB51AE92391D740BDF7ABB239709C46270832039FF045BCF7878E7DA9C3B4CF89326CA8B4D29DB8680EEAE1B5A18463284713A323A69AEBF33CFC4B11283C7C8041FFC97668EDF727823411C9559816C108C11EC401643765527860D8DA0ED7254792C21DB775DEB1D6971C924CC83EB626173D894694943B1828ABDE8F9495BCEBA9AC3A4A03592C085AA29CC9A0C65786E631A702D589B819C89E79EEFF29C4EC312C8860BB68F02272EA770FB8D");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(512);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 9 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 9 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+
+            //test 10
+            key = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F");
+            textToWrap = Hex.Decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE00805000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+            expectedWrappedText = Hex.Decode("3A05BB41513555F171E9234D4834EDAD16C0BAA6136197650138219C5DA406A703C39259E9DCCF6F2691EC691CE7414B5D3CDA006DE6D6C62142FAAA742C5F8AF64FCE95BE7ABA7FE5E06C3C33EE67BAEAB196E3A71132CAE78CD605A22E34D53CD159217E7B692CC79FAC66BF5E08DBC4FE274299474E176DDDF9F462AC63F4872E9B7F16B98AA56707EE5F2F94616CFC6A9548ADBD7DCB73664C331213964593F712ECCDFA7A94E3ABA7995176EA4B7E77096A3A3FF4E4087F430B62D5DEE64999F235FA9EAC79896A1C2258BF1DFC8A6AD0E5E7E06EAEEA0CCC2DEF62F67ECE8D12EFF432277C40A7BF1A23440B3533AF1E2F7AE1BBC076D12628BB4BC7B2E4D4B4353BCEAF9A67276B3FA23CADCA80062B95EBB2D51510AFA16F97249DF98E7B845C9A410F24B3C8B3E838E58D22BC2D14F46190FC1BFDB60C9691404F99");
+
+            output = new byte[expectedWrappedText.Length];
+
+            wrapper = new Dstu7624WrapEngine(512);
+            wrapper.Init(true, new KeyParameter(key));
+            output = wrapper.Wrap(textToWrap, 0, textToWrap.Length);
+
+
+            if (!Arrays.AreEqual(output, expectedWrappedText))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (wrapping) test 10 - expected "
+                     + Hex.ToHexString(expectedWrappedText)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            wrapper.Init(false, new KeyParameter(key));
+            output = wrapper.Unwrap(expectedWrappedText, 0, expectedWrappedText.Length);
+
+            if (!Arrays.AreEqual(output, textToWrap))
+            {
+                return new SimpleTestResult(false, Name + ": Failed KW (unwrapping) test 10 - expected "
+                     + Hex.ToHexString(textToWrap)
+                     + " got " + Hex.ToHexString(output));
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+
+        [Test]
+        public void Dstu7624TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        public override string Name
+        {
+            get { return "Dstu7624"; }
+        }
+
+        public static void Main(
+           string[] args)
+        {
+            Dstu7624Test test = new Dstu7624Test();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result.ToString());
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/EAXTest.cs b/crypto/test/src/crypto/test/EAXTest.cs
index 38e58c0a8..93c9f45b0 100644
--- a/crypto/test/src/crypto/test/EAXTest.cs
+++ b/crypto/test/src/crypto/test/EAXTest.cs
@@ -186,8 +186,8 @@ namespace Org.BouncyCastle.Crypto.Tests
             byte[] t,
             byte[] c)
         {
-			EaxBlockCipher encEax = new EaxBlockCipher(new AesFastEngine());
-			EaxBlockCipher decEax = new EaxBlockCipher(new AesFastEngine());
+			EaxBlockCipher encEax = new EaxBlockCipher(new AesEngine());
+			EaxBlockCipher decEax = new EaxBlockCipher(new AesEngine());
 
 			AeadParameters parameters = new AeadParameters(new KeyParameter(k), macSize, n, a);
 			encEax.Init(true, parameters);
@@ -313,7 +313,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			srng.NextBytes(datIn);
 			srng.NextBytes(key);
 
-			AesFastEngine engine = new AesFastEngine();
+            IBlockCipher engine = new AesEngine();
 			KeyParameter sessKey = new KeyParameter(key);
 			EaxBlockCipher eaxCipher = new EaxBlockCipher(engine);
 
diff --git a/crypto/test/src/crypto/test/GCMTest.cs b/crypto/test/src/crypto/test/GCMTest.cs
index 078aa87c4..b6b919623 100644
--- a/crypto/test/src/crypto/test/GCMTest.cs
+++ b/crypto/test/src/crypto/test/GCMTest.cs
@@ -327,7 +327,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
         protected IBlockCipher CreateAesEngine()
         {
-            return new AesFastEngine();
+            return new AesEngine();
         }
 
         private void DoTestExceptions()
@@ -357,12 +357,38 @@ namespace Org.BouncyCastle.Crypto.Tests
             }
 
             // TODO
-            //AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
             //AEADTestUtil.testTampering(this, gcm, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
-            //AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(
-            //        new byte[16]), 128, new byte[16]));
-            //AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(
-            //        new KeyParameter(new byte[16]), 128, new byte[16]));
+
+            //byte[] P = Strings.toByteArray("Hello world!");
+            //byte[] buf = new byte[100];
+
+            //GCMBlockCipher c = new GCMBlockCipher(createAESEngine());
+            //AEADParameters aeadParameters = new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]);
+            //c.init(true, aeadParameters);
+
+            //c.processBytes(P, 0, P.length, buf, 0);
+
+            //c.doFinal(buf, 0);
+
+            //try
+            //{
+            //    c.doFinal(buf, 0);
+            //    fail("no exception on reuse");
+            //}
+            //catch (IllegalStateException e)
+            //{
+            //    isTrue("wrong message", e.getMessage().equals("GCM cipher cannot be reused for encryption"));
+            //}
+
+            //try
+            //{
+            //    c.init(true, aeadParameters);
+            //    fail("no exception on reuse");
+            //}
+            //catch (IllegalArgumentException e)
+            //{
+            //    isTrue("wrong message", e.getMessage().equals("cannot reuse nonce for GCM encryption"));
+            //}
         }
 
         private void RunTestCase(string[] testVector)
@@ -433,13 +459,21 @@ namespace Org.BouncyCastle.Crypto.Tests
             GcmBlockCipher encCipher = InitCipher(encM, true, parameters);
             GcmBlockCipher decCipher = InitCipher(decM, false, parameters);
             CheckTestCase(encCipher, decCipher, testName, SA, P, C, T);
+            encCipher = InitCipher(encM, true, parameters);
             CheckTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T);
 
             // Key reuse
             AeadParameters keyReuseParams = AeadTestUtilities.ReuseKey(parameters);
-            encCipher.Init(true, keyReuseParams);
-            decCipher.Init(false, keyReuseParams);
-            CheckTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T);
+
+            try
+            {
+                encCipher.Init(true, keyReuseParams);
+                Fail("no exception");
+            }
+            catch (ArgumentException e)
+            {
+                IsTrue("wrong message", "cannot reuse nonce for GCM encryption".Equals(e.Message));
+            }
         }
 
         private GcmBlockCipher InitCipher(
diff --git a/crypto/test/src/crypto/test/GMacTest.cs b/crypto/test/src/crypto/test/GMacTest.cs
index eff351b81..42e6e4ebd 100644
--- a/crypto/test/src/crypto/test/GMacTest.cs
+++ b/crypto/test/src/crypto/test/GMacTest.cs
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Tests
             {
                 TestCase testCase = TEST_VECTORS[i];
 
-                IMac mac = new GMac(new GcmBlockCipher(new AesFastEngine()), testCase.getTag().Length * 8);
+                IMac mac = new GMac(new GcmBlockCipher(new AesEngine()), testCase.getTag().Length * 8);
                 ICipherParameters key = new KeyParameter(testCase.getKey());
                 mac.Init(new ParametersWithIV(key, testCase.getIv()));
 
@@ -125,7 +125,7 @@ namespace Org.BouncyCastle.Crypto.Tests
         {
             try
             {
-                GMac mac = new GMac(new GcmBlockCipher(new AesFastEngine()), size);
+                GMac mac = new GMac(new GcmBlockCipher(new AesEngine()), size);
                 mac.Init(new ParametersWithIV(null, new byte[16]));
                 Fail("Expected failure for illegal mac size " + size);
             }
diff --git a/crypto/test/src/crypto/test/OAEPTest.cs b/crypto/test/src/crypto/test/OAEPTest.cs
index 437ee7484..39af21137 100644
--- a/crypto/test/src/crypto/test/OAEPTest.cs
+++ b/crypto/test/src/crypto/test/OAEPTest.cs
@@ -5,7 +5,7 @@ using NUnit.Framework;
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Encodings;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
@@ -779,6 +779,47 @@ namespace Org.BouncyCastle.Crypto.Tests
             OaepVecTest(1027, 4, pubParam, privParam, seed_1027_4, input_1027_4, output_1027_4);
             OaepVecTest(1027, 5, pubParam, privParam, seed_1027_5, input_1027_5, output_1027_5);
             OaepVecTest(1027, 6, pubParam, privParam, seed_1027_6, input_1027_6, output_1027_6);
+
+            //
+            // OAEP - public encrypt, private decrypt  differring hashes
+            //
+            IAsymmetricBlockCipher cipher = new OaepEncoding(new RsaEngine(), new Sha256Digest(), new Sha1Digest(), new byte[10]);
+
+            cipher.Init(true, new ParametersWithRandom(pubParam, new SecureRandom()));
+
+            byte[] input = new byte[10];
+
+            byte[] output = cipher.ProcessBlock(input, 0, input.Length);
+
+            cipher.Init(false, privParam);
+
+            output = cipher.ProcessBlock(output, 0, output.Length);
+
+            for (int i = 0; i != input.Length; i++)
+            {
+                if (output[i] != input[i])
+                {
+                    Fail("mixed digest failed decoding");
+                }
+            }
+
+            cipher = new OaepEncoding(new RsaEngine(), new Sha1Digest(), new Sha256Digest(), new byte[10]);
+
+            cipher.Init(true, new ParametersWithRandom(pubParam, new SecureRandom()));
+
+            output = cipher.ProcessBlock(input, 0, input.Length);
+
+            cipher.Init(false, privParam);
+
+            output = cipher.ProcessBlock(output, 0, output.Length);
+
+            for (int i = 0; i != input.Length; i++)
+            {
+                if (output[i] != input[i])
+                {
+                    Fail("mixed digest failed decoding");
+                }
+            }
         }
 
         public static void MainOld(
diff --git a/crypto/test/src/crypto/test/Poly1305Test.cs b/crypto/test/src/crypto/test/Poly1305Test.cs
index 7375b09be..8b48c40d5 100644
--- a/crypto/test/src/crypto/test/Poly1305Test.cs
+++ b/crypto/test/src/crypto/test/Poly1305Test.cs
@@ -129,7 +129,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 			else
 			{
-				mac = new Poly1305(new AesFastEngine());
+				mac = new Poly1305(new AesEngine());
 				mac.Init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce));
 			}
 			mac.BlockUpdate(tc.message, 0, tc.message.Length);
@@ -151,7 +151,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			byte[] output = new byte[16];
 
 			int c = 0;
-			IMac mac = new Poly1305(new AesFastEngine());
+			IMac mac = new Poly1305(new AesEngine());
 			for (int loop = 0; loop < 13; loop++)
 			{
 				len = 0;
@@ -228,7 +228,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			byte[] output = new byte[16];
 
 			// Generate baseline
-			IMac poly = new Poly1305(new AesFastEngine());
+			IMac poly = new Poly1305(new AesEngine());
 			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
 
 			poly.BlockUpdate(m, 0, m.Length);
@@ -274,7 +274,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			gen.Init(new KeyGenerationParameters(new SecureRandom(), 256));
 			byte[] k = gen.GenerateKey();
 
-			IMac poly = new Poly1305(new AesFastEngine());
+			IMac poly = new Poly1305(new AesEngine());
 			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
 
 			try
diff --git a/crypto/test/src/crypto/test/RSABlindedTest.cs b/crypto/test/src/crypto/test/RSABlindedTest.cs
index d90a9973b..c353e6eff 100644
--- a/crypto/test/src/crypto/test/RSABlindedTest.cs
+++ b/crypto/test/src/crypto/test/RSABlindedTest.cs
@@ -103,22 +103,22 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 		private void doTestTruncatedPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated");
+			checkForPkcs1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect");
 		}
 
 		private void doTestDudPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, dudBlock, "unknown block type");
+			checkForPkcs1Exception(pubParameters, privParameters, dudBlock, "block incorrect");
 		}
 
 		private void doTestWrongPaddingPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect");
+			checkForPkcs1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect");
 		}
 
 		private void doTestMissingDataPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, missingDataBlock, "no data in block");
+			checkForPkcs1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect");
 		}
 
 		private void checkForPkcs1Exception(RsaKeyParameters pubParameters, RsaKeyParameters privParameters, byte[] inputData, string expectedMessage)
diff --git a/crypto/test/src/crypto/test/RsaTest.cs b/crypto/test/src/crypto/test/RsaTest.cs
index c512da16f..6ecaea59b 100644
--- a/crypto/test/src/crypto/test/RsaTest.cs
+++ b/crypto/test/src/crypto/test/RsaTest.cs
@@ -54,10 +54,11 @@ namespace Org.BouncyCastle.Crypto.Tests
 			eng.Init(true, privParameters);
 
 			byte[] data = null;
+            byte[] overSized = null;
 
-			try
-			{
-				data = eng.ProcessBlock(oversizedSig, 0, oversizedSig.Length);
+            try
+            {
+				overSized = data = eng.ProcessBlock(oversizedSig, 0, oversizedSig.Length);
 			}
 			catch (Exception e)
 			{
@@ -70,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 			try
 			{
-				data = eng.ProcessBlock(data, 0, data.Length);
+				data = eng.ProcessBlock(overSized, 0, overSized.Length);
 
 				Fail("oversized signature block not recognised");
 			}
@@ -82,9 +83,22 @@ namespace Org.BouncyCastle.Crypto.Tests
 				}
 			}
 
+            eng = new Pkcs1Encoding(new RsaEngine(), Hex.Decode("feedbeeffeedbeeffeedbeef"));
+            eng.Init(false, new ParametersWithRandom(privParameters, new SecureRandom()));
+
+            try
+            {
+                data = eng.ProcessBlock(overSized, 0, overSized.Length);
+                IsTrue("not fallback", Arrays.AreEqual(Hex.Decode("feedbeeffeedbeeffeedbeef"), data));
+            }
+            catch (InvalidCipherTextException e)
+            {
+                Fail("RSA: failed - exception " + e.ToString(), e);
+            }
+
 
-			// Create the encoding with StrictLengthEnabled=false (done thru environment in Java version)
-			Pkcs1Encoding.StrictLengthEnabled = false;
+            // Create the encoding with StrictLengthEnabled=false (done thru environment in Java version)
+            Pkcs1Encoding.StrictLengthEnabled = false;
 
 			eng = new Pkcs1Encoding(new RsaEngine());
 
@@ -92,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 			try
 			{
-				data = eng.ProcessBlock(data, 0, data.Length);
+				data = eng.ProcessBlock(overSized, 0, overSized.Length);
 			}
 			catch (InvalidCipherTextException e)
 			{
@@ -104,22 +118,22 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 		private void doTestTruncatedPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated");
+			checkForPkcs1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect");
 		}
 
 		private void doTestDudPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, dudBlock, "unknown block type");
+			checkForPkcs1Exception(pubParameters, privParameters, dudBlock, "block incorrect");
 		}
 
 		private void doTestWrongPaddingPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect");
+			checkForPkcs1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect");
 		}
 
 		private void doTestMissingDataPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
 		{
-			checkForPkcs1Exception(pubParameters, privParameters, missingDataBlock, "no data in block");
+			checkForPkcs1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect");
 		}
 
 		private void checkForPkcs1Exception(RsaKeyParameters pubParameters, RsaKeyParameters privParameters, byte[] inputData, string expectedMessage)
@@ -192,13 +206,34 @@ namespace Org.BouncyCastle.Crypto.Tests
 			{
 				Fail("failed OAEP Test");
 			}
-		}
 
-		// TODO Move this when other JCE tests are ported from Java
-		/**
+            // check for oversized input
+            byte[] message = new byte[87];
+            RsaEngine rsaEngine = new RsaEngine();
+            IAsymmetricBlockCipher cipher = new OaepEncoding(rsaEngine, new Sha1Digest(), new Sha1Digest(), message);
+            cipher.Init(true, new ParametersWithRandom(pubParameters, new SecureRandom()));
+
+            try
+            {
+                cipher.ProcessBlock(message, 0, message.Length);
+
+                Fail("no exception thrown");
+            }
+            catch (DataLengthException e)
+            {
+                IsTrue("message mismatch", "input data too long".Equals(e.Message));
+            }
+            catch (InvalidCipherTextException e)
+            {
+                Fail("failed - exception " + e.ToString(), e);
+            }
+        }
+
+        // TODO Move this when other JCE tests are ported from Java
+        /**
 		 * signature with a "forged signature" (sig block not at end of plain text)
 		 */
-		private void doTestBadSig()//PrivateKey priv, PublicKey pub)
+        private void doTestBadSig()//PrivateKey priv, PublicKey pub)
 		{
 //			Signature           sig = Signature.getInstance("SHA1WithRSAEncryption", "BC");
 			ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
@@ -410,30 +445,65 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 			eng.Init(false, privParameters);
 
-			try
-			{
-				data = eng.ProcessBlock(data, 0, data.Length);
+            byte[] plainData = null;
+            try
+            {
+				plainData = eng.ProcessBlock(data, 0, data.Length);
 			}
 			catch (Exception e)
 			{
 				Fail("failed - exception " + e.ToString());
 			}
 
-			if (!input.Equals(Hex.ToHexString(data)))
-			{
-				Fail("failed PKCS1 public/private Test");
-			}
-
-			//
-			// PKCS1 - private encrypt, public decrypt
-			//
-			eng = new Pkcs1Encoding(((Pkcs1Encoding)eng).GetUnderlyingCipher());
+            if (!input.Equals(Hex.ToHexString(plainData)))
+            {
+                Fail("failed PKCS1 public/private Test");
+			}
+
+            Pkcs1Encoding fEng = new Pkcs1Encoding(new RsaEngine(), input.Length / 2);
+            fEng.Init(false, new ParametersWithRandom(privParameters, new SecureRandom()));
+            try
+            {
+                plainData = fEng.ProcessBlock(data, 0, data.Length);
+            }
+            catch (Exception e)
+            {
+                Fail("failed - exception " + e.ToString(), e);
+            }
+
+            if (!input.Equals(Hex.ToHexString(plainData)))
+            {
+                Fail("failed PKCS1 public/private fixed Test");
+            }
+
+            fEng = new Pkcs1Encoding(new RsaEngine(), input.Length);
+            fEng.Init(false, new ParametersWithRandom(privParameters, new SecureRandom()));
+            try
+            {
+                data = fEng.ProcessBlock(data, 0, data.Length);
+            }
+            catch (Exception e)
+            {
+                Fail("failed - exception " + e.ToString(), e);
+            }
+
+            if (input.Equals(Hex.ToHexString(data)))
+            {
+                Fail("failed to recognise incorrect plaint text length");
+            }
+
+            data = plainData;
+
+            //
+            // PKCS1 - private encrypt, public decrypt
+            //
+            eng = new Pkcs1Encoding(((Pkcs1Encoding)eng).GetUnderlyingCipher());
 
 			eng.Init(true, privParameters);
 
 			try
 			{
-				data = eng.ProcessBlock(data, 0, data.Length);
+				data = eng.ProcessBlock(plainData, 0, plainData.Length);
 			}
 			catch (Exception e)
 			{
@@ -542,7 +612,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 			}
 
 			genParam = new RsaKeyGenerationParameters(
-				BigInteger.ValueOf(0x11), new SecureRandom(), 16, 25);
+				BigInteger.ValueOf(0x11), new SecureRandom(), 128, 25);
 			pGen.Init(genParam);
 
 			for (int i = 0; i < 100; ++i)
@@ -551,7 +621,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 				RsaPrivateCrtKeyParameters privKey = (RsaPrivateCrtKeyParameters) pair.Private;
 				BigInteger pqDiff = privKey.P.Subtract(privKey.Q).Abs();
 
-				if (pqDiff.BitLength < 5)
+				if (pqDiff.BitLength < 42)
 				{
 					Fail("P and Q too close in RSA key pair");
 				}
diff --git a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
index ead2f16c3..c807a6841 100644
--- a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
+++ b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Tests
      * a basic test that takes a stream cipher, key parameter, and an input
      * and output string.
      */
-    public class StreamCipherVectorTest: ITest
+    public class StreamCipherVectorTest: SimpleTest
     {
         int                 id;
         IStreamCipher       cipher;
@@ -33,12 +33,12 @@ namespace Org.BouncyCastle.Crypto.Tests
             this.output = Hex.Decode(output);
         }
 
-		public string Name
+		public override string Name
 		{
 			get { return cipher.AlgorithmName + " Vector Test " + id; }
 		}
 
-		public ITestResult Perform()
+		public override void PerformTest()
         {
             cipher.Init(true, param);
 
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             if (!Arrays.AreEqual(outBytes, output))
             {
-                return new SimpleTestResult(false, Name + ": failed - "
+                Fail("failed - "
 					+ "expected " + Hex.ToHexString(output)
 					+ " got " + Hex.ToHexString(outBytes));
             }
@@ -59,10 +59,8 @@ namespace Org.BouncyCastle.Crypto.Tests
 
             if (!Arrays.AreEqual(input, outBytes))
             {
-                return new SimpleTestResult(false, Name + ": failed reversal");
+                Fail("failed reversal");
             }
-
-            return new SimpleTestResult(true, Name + ": OKAY");
         }
     }
 }
diff --git a/crypto/test/src/openpgp/test/PGPArmoredTest.cs b/crypto/test/src/openpgp/test/PGPArmoredTest.cs
index b06275840..6dad6bcd6 100644
--- a/crypto/test/src/openpgp/test/PGPArmoredTest.cs
+++ b/crypto/test/src/openpgp/test/PGPArmoredTest.cs
@@ -87,6 +87,22 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 			return matches;
 		}
 
+        private void pgpUtilTest()
+        {
+            // check decoder exception isn't escaping.
+            MemoryStream bIn = new MemoryStream(Strings.ToByteArray("abcde"), false);
+
+            try
+            {
+                PgpUtilities.GetDecoderStream(bIn);
+                Fail("no exception");
+            }
+            catch (IOException)
+            {
+                // expected: ignore.
+            }
+        }
+
 		private void blankLineTest()
 		{
 			byte[] blankLineBytes = Encoding.ASCII.GetBytes(blankLineData);
@@ -241,6 +257,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 			}
 
 			blankLineTest();
+            pgpUtilTest();
 		}
 
 		public override string Name
diff --git a/crypto/test/src/security/test/SecureRandomTest.cs b/crypto/test/src/security/test/SecureRandomTest.cs
index f1d83b29c..98bf75508 100644
--- a/crypto/test/src/security/test/SecureRandomTest.cs
+++ b/crypto/test/src/security/test/SecureRandomTest.cs
@@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Security.Tests
         [Test]
         public void TestSP800Ctr()
         {
-            SecureRandom random = new SP800SecureRandomBuilder().BuildCtr(new AesFastEngine(), 256, new byte[32], false);
+            SecureRandom random = new SP800SecureRandomBuilder().BuildCtr(new AesEngine(), 256, new byte[32], false);
 
             CheckSecureRandom(random);
         }
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Security.Tests
         [Test]
         public void TestX931()
         {
-            SecureRandom random = new X931SecureRandomBuilder().Build(new AesFastEngine(), new KeyParameter(new byte[16]), false);
+            SecureRandom random = new X931SecureRandomBuilder().Build(new AesEngine(), new KeyParameter(new byte[16]), false);
 
             CheckSecureRandom(random);
         }
diff --git a/crypto/test/src/test/DHTest.cs b/crypto/test/src/test/DHTest.cs
index 9657ee6b4..150b81bcb 100644
--- a/crypto/test/src/test/DHTest.cs
+++ b/crypto/test/src/test/DHTest.cs
@@ -633,6 +633,98 @@ namespace Org.BouncyCastle.Tests
             }
         }
 
+        internal static readonly string Message = "Hello";
+
+        internal static readonly SecureRandom rand = new SecureRandom();
+
+        public static DHParameters Ike2048()
+        {
+            BigInteger p = new BigInteger(
+                "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74"
+                    + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437"
+                    + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed"
+                    + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05"
+                    + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb"
+                    + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b"
+                    + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718"
+                    + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff", 16);
+            BigInteger g = new BigInteger("2");
+            return new DHParameters(p, g);
+        }
+
+        internal class DHWeakPubKey
+            : DHPublicKeyParameters
+        {
+            private readonly BigInteger weakY;
+
+            public DHWeakPubKey(BigInteger weakY, DHParameters parameters)
+			    : base(BigInteger.Two, parameters)
+            {
+                this.weakY = weakY;
+            }
+
+            public override BigInteger Y
+            {
+                get { return weakY; }
+            }
+        }
+
+        /**
+         * Tests whether a provider accepts invalid public keys that result in predictable shared secrets.
+         * This test is based on RFC 2785, Section 4 and NIST SP 800-56A,
+         * If an attacker can modify both public keys in an ephemeral-ephemeral key agreement scheme then
+         * it may be possible to coerce both parties into computing the same predictable shared key.
+         * <p/>
+         * Note: the test is quite whimsical. If the prime p is not a safe prime then the provider itself
+         * cannot prevent all small-subgroup attacks because of the missing parameter q in the
+         * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones
+         * proposed in RFC 2785.
+         */
+        [Test]
+        public void TestSubgroupConfinement()
+        {
+            DHParameters parameters = Ike2048();
+            BigInteger p = parameters.P, g = parameters.G;
+
+            IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("DH");
+
+            //keyGen.initialize(params);
+            keyGen.Init(new DHKeyGenerationParameters(new SecureRandom(), parameters));
+
+            AsymmetricCipherKeyPair kp = keyGen.GenerateKeyPair();
+            AsymmetricKeyParameter priv = kp.Private;
+
+            IBasicAgreement ka = AgreementUtilities.GetBasicAgreement("DH");
+
+            BigInteger[] weakPublicKeys = { BigInteger.Zero, BigInteger.One, p.Subtract(BigInteger.One), p,
+                p.Add(BigInteger.One), BigInteger.One.Negate() };
+
+            foreach (BigInteger weakKey in weakPublicKeys)
+            {
+                try
+                {
+                    new DHPublicKeyParameters(weakKey, parameters);
+                    Fail("Generated weak public key");
+                }
+                catch (ArgumentException ex)
+                {
+                    IsTrue("wrong message (constructor)", Platform.StartsWith(ex.Message, "invalid DH public key"));
+                }
+
+                ka.Init(priv);
+
+                try
+                {
+                    ka.CalculateAgreement(new DHWeakPubKey(weakKey, parameters));
+                    Fail("Generated secrets with weak public key");
+                }
+                catch (ArgumentException ex)
+                {
+                    IsTrue("wrong message (CalculateAgreement)", "Diffie-Hellman public key is weak".Equals(ex.Message));
+                }
+            }
+        }
+
         public override void PerformTest()
         {
             TestEnc();
@@ -640,6 +732,7 @@ namespace Org.BouncyCastle.Tests
             TestECDH();
             TestECDHC();
             TestExceptions();
+            TestSubgroupConfinement();
         }
 
         public static void MainOld(
diff --git a/crypto/test/src/test/NamedCurveTest.cs b/crypto/test/src/test/NamedCurveTest.cs
index 4c91f64fe..96b246981 100644
--- a/crypto/test/src/test/NamedCurveTest.cs
+++ b/crypto/test/src/test/NamedCurveTest.cs
@@ -1,11 +1,10 @@
 using System;
-using System.Collections;
 
 using NUnit.Framework;
 
-using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Anssi;
 using Org.BouncyCastle.Asn1.CryptoPro;
-using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.GM;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X9;
@@ -358,6 +357,16 @@ namespace Org.BouncyCastle.Tests
                 doTestECDsa(name);
             }
 
+            foreach (string name in AnssiNamedCurves.Names)
+            {
+                doTestECDsa(name);
+            }
+
+            foreach (string name in GMNamedCurves.Names)
+            {
+                doTestECDsa(name);
+            }
+
             foreach (string name in ECGost3410NamedCurves.Names)
             {
                 doTestECGost(name);