summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorMegan Woods <megan@flygfisk.com>2019-01-14 00:17:24 +1100
committerMegan Woods <megan@flygfisk.com>2019-01-14 00:17:24 +1100
commit785d36daf1d125b3fba16e1d92719e2a0f67698e (patch)
tree2dfb561f0be1a55b87f135997d5d3c1e552c05da /crypto
parentFix some comments (diff)
downloadBouncyCastle.NET-ed25519-785d36daf1d125b3fba16e1d92719e2a0f67698e.tar.xz
Added ECGOST3410_2012Signer
Updated encoding of SubjectPublicKeyInfo and PrivateKeyInfo
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs52
-rw-r--r--crypto/src/crypto/parameters/ECGOST3410Parameters.cs51
-rw-r--r--crypto/src/crypto/parameters/ECNamedDomainParameters.cs35
-rw-r--r--crypto/src/crypto/signers/EcGost3410_2012Signer.cs151
-rw-r--r--crypto/src/crypto/signers/GOST3410DigestSigner.cs237
-rw-r--r--crypto/src/pkcs/PrivateKeyInfoFactory.cs44
-rw-r--r--crypto/src/security/PrivateKeyFactory.cs162
-rw-r--r--crypto/src/security/PublicKeyFactory.cs36
-rw-r--r--crypto/src/util/BigIntegers.cs11
-rw-r--r--crypto/src/x509/SubjectPublicKeyInfoFactory.cs66
-rw-r--r--crypto/test/src/crypto/test/ECGOST3410_2012Test.cs597
-rw-r--r--crypto/test/src/crypto/test/EGOST3410_2012SignatureTest.cs187
12 files changed, 1462 insertions, 167 deletions
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
index b61da6b57..ccf3155cf 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -115,70 +115,70 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
 
             //GOST34.10 2012
-            mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); //p
-            mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); //q
+            mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", 16); //p
+            mod_q = new BigInteger("400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67", 16); //q
             curve = new FpCurve(
                 mod_p, // p
-                new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
-                new BigInteger("166"), // b
+                new BigInteger("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335", 16), // a
+                new BigInteger("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513", 16), // b
                 mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
-                    new BigInteger("1"), // x
-                    new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
+                    new BigInteger("91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28", 16), // x
+                    new BigInteger("32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C", 16)), // y
                 mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA] = ecParams;
 
-            mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",16); //p
-            mod_q = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",16); //q
+            mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7", 16); //p
+            mod_q = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275", 16); //q
             curve = new FpCurve(
                 mod_p, // p
-                new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",16), // a
-                new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",16), // b
+                new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4", 16), // a
+                new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760", 16), // b
                 mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), // x
-                    new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",16)), // y
+                    new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4", 16)), // y
                 mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA] = ecParams;
 
-            mod_p = new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F",16); //p
-            mod_q = new BigInteger("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD",16); //q
+            mod_p = new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F", 16); //p
+            mod_q = new BigInteger("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD", 16); //q
             curve = new FpCurve(
                 mod_p, // p
-                new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",16), // a
-                new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",16), // b
+                new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C", 16), // a
+                new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116", 16), // b
                 mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), // x
-                    new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD",16)), // y
+                    new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD", 16)), // y
                 mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB] = ecParams;
 
-            mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",16); //p
-            mod_q = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED",16); //q
+            mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7", 16); //p
+            mod_q = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED", 16); //q
             curve = new FpCurve(
                 mod_p, // p
-                new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",16), // a
-                new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",16), // b
+                new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3", 16), // a
+                new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1", 16), // b
                 mod_q, BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
                     new BigInteger("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148", 16), // x
-                    new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",16)), // y
+                    new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F", 16)), // y
                 mod_q, BigInteger.One);
 
             parameters[RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC] = ecParams;
@@ -213,7 +213,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
         public static ECDomainParameters GetByOid(
             DerObjectIdentifier oid)
         {
-            return (ECDomainParameters) parameters[oid];
+            return (ECDomainParameters)parameters[oid];
         }
 
         /**
@@ -228,11 +228,11 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
         public static ECDomainParameters GetByName(
             string name)
         {
-            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+            DerObjectIdentifier oid = (DerObjectIdentifier)objIds[name];
 
             if (oid != null)
             {
-                return (ECDomainParameters) parameters[oid];
+                return (ECDomainParameters)parameters[oid];
             }
 
             return null;
@@ -244,13 +244,13 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
         public static string GetName(
             DerObjectIdentifier oid)
         {
-            return (string) names[oid];
+            return (string)names[oid];
         }
 
         public static DerObjectIdentifier GetOid(
             string name)
         {
-            return (DerObjectIdentifier) objIds[name];
+            return (DerObjectIdentifier)objIds[name];
         }
     }
 }
diff --git a/crypto/src/crypto/parameters/ECGOST3410Parameters.cs b/crypto/src/crypto/parameters/ECGOST3410Parameters.cs
new file mode 100644
index 000000000..ede7433d6
--- /dev/null
+++ b/crypto/src/crypto/parameters/ECGOST3410Parameters.cs
@@ -0,0 +1,51 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ECGOST3410Parameters : ECNamedDomainParameters
+    {
+
+        private readonly DerObjectIdentifier _publicKeyParamSet;
+        private readonly DerObjectIdentifier _digestParamSet;
+        private readonly DerObjectIdentifier _encryptionParamSet;
+
+        public DerObjectIdentifier PublicKeyParamSet
+        {
+            get { return _publicKeyParamSet; }
+        }
+
+        public DerObjectIdentifier DigestParamSet
+        {
+            get { return _digestParamSet; }
+        }
+
+        public DerObjectIdentifier EncryptionParamSet
+        {
+            get { return _encryptionParamSet; }
+        }
+
+        public ECGOST3410Parameters(
+            ECNamedDomainParameters dp,
+            DerObjectIdentifier publicKeyParamSet,
+            DerObjectIdentifier digestParamSet,
+            DerObjectIdentifier encryptionParamSet) : base(dp.Name, dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed())
+        {
+            this._publicKeyParamSet = publicKeyParamSet;
+            this._digestParamSet = digestParamSet;
+            this._encryptionParamSet = encryptionParamSet;
+        }
+
+
+        public ECGOST3410Parameters(ECDomainParameters dp, DerObjectIdentifier publicKeyParamSet,
+            DerObjectIdentifier digestParamSet,
+            DerObjectIdentifier encryptionParamSet) : base(publicKeyParamSet, dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed())
+        {
+            this._publicKeyParamSet = publicKeyParamSet;
+            this._digestParamSet = digestParamSet;
+            this._encryptionParamSet = encryptionParamSet;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/parameters/ECNamedDomainParameters.cs b/crypto/src/crypto/parameters/ECNamedDomainParameters.cs
new file mode 100644
index 000000000..34e390a8f
--- /dev/null
+++ b/crypto/src/crypto/parameters/ECNamedDomainParameters.cs
@@ -0,0 +1,35 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ECNamedDomainParameters : ECDomainParameters
+    {
+        private DerObjectIdentifier name;
+
+        public DerObjectIdentifier Name
+        {
+            get { return name; }
+        }
+
+        public ECNamedDomainParameters(DerObjectIdentifier name, ECDomainParameters dp) : this(name, dp.curve, dp.g, dp.n, dp.h, dp.seed)
+        { }
+
+
+        public ECNamedDomainParameters(DerObjectIdentifier name, ECCurve curve, ECPoint g, BigInteger n) : base(curve, g, n)
+        {
+            this.name = name;
+        }
+
+        public ECNamedDomainParameters(DerObjectIdentifier name, ECCurve curve, ECPoint g, BigInteger n, BigInteger h) : base(curve, g, n, h)
+        {
+            this.name = name;
+        }
+
+        public ECNamedDomainParameters(DerObjectIdentifier name, ECCurve curve, ECPoint g, BigInteger n, BigInteger h, byte[] seed) : base(curve, g, n, h, seed)
+        {
+            this.name = name;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/signers/EcGost3410_2012Signer.cs b/crypto/src/crypto/signers/EcGost3410_2012Signer.cs
new file mode 100644
index 000000000..cd50916dd
--- /dev/null
+++ b/crypto/src/crypto/signers/EcGost3410_2012Signer.cs
@@ -0,0 +1,151 @@
+using Org.BouncyCastle.Math;
+using System;
+using System.IO;
+using NUnit.Core;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class ECGOST3410_2012Signer : IDsaExt
+    {
+        private ECKeyParameters key;
+        private SecureRandom secureRandom;
+        private bool forSigning;
+
+        public BigInteger Order
+        {
+            get { return key.Parameters.N; }
+        }
+
+        public string AlgorithmName
+        {
+            get { return key.AlgorithmName; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+            if (forSigning)
+            {
+                if (parameters is ParametersWithRandom)
+                {
+                    ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+                    this.secureRandom = rParam.Random;
+                    this.key = (ECPrivateKeyParameters)rParam.Parameters;
+                }
+                else
+                {
+                    this.secureRandom = new SecureRandom();
+                    this.key = (ECPrivateKeyParameters)parameters;
+                }
+            }
+            else
+            {
+                this.key = (ECPublicKeyParameters)parameters;
+            }
+        } 
+
+        public BigInteger[] GenerateSignature(byte[] message)
+        {
+            if (!forSigning)
+            {
+                throw new InvalidOperationException("not initialised for signing.");
+            }
+
+            byte[] mRev = new byte[message.Length]; // conversion is little-endian
+            for (int i = 0; i != mRev.Length; i++)
+            {
+                mRev[i] = message[mRev.Length - 1 - i];
+            }
+            BigInteger e = new BigInteger(1, mRev);
+
+            ECDomainParameters ec = key.Parameters;
+            BigInteger n = ec.N;
+            BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+            BigInteger r, s;
+
+            ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
+
+            do // generate s
+            {
+                BigInteger k;
+                do // generate r
+                {
+                    do
+                    {
+                        k = BigIntegers.CreateRandomBigInteger(n.BitLength, secureRandom);
+                    } while (k.Equals(BigInteger.Zero)); //  ECConstants.ZERO));
+
+                    ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
+
+                    r = p.AffineXCoord.ToBigInteger().Mod(n);
+                } while (r.Equals(BigInteger.Zero)); //  ECConstants.ZERO));
+
+                s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n);
+            } while (s.Equals(BigInteger.Zero)); //   ECConstants.ZERO));
+
+            return new BigInteger[] { r, s };
+        }
+
+
+        public bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
+        {
+            if (forSigning)
+            {
+                throw new InvalidOperationException("not initialised for verification.");
+            }
+
+
+            byte[] mRev = new byte[message.Length]; // conversion is little-endian
+            for (int i = 0; i != mRev.Length; i++)
+            {
+                mRev[i] = message[mRev.Length - 1 - i];
+            }
+            BigInteger e = new BigInteger(1, mRev);
+            BigInteger n = key.Parameters.N;
+
+            // r in the range [1,n-1]
+            if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            // s in the range [1,n-1]
+            if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            BigInteger v = e.ModInverse(n);
+
+            BigInteger z1 = s.Multiply(v).Mod(n);
+            BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n);
+
+            ECPoint G = key.Parameters.G; // P
+            ECPoint Q = ((ECPublicKeyParameters)key).Q;
+
+            ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2).Normalize();
+
+            // components must be bogus.
+            if (point.IsInfinity)
+            {
+                return false;
+            }
+
+            BigInteger R = point.AffineXCoord.ToBigInteger().Mod(n);
+
+            return R.Equals(r);
+        }
+
+        protected virtual ECMultiplier CreateBasePointMultiplier()
+        {
+            return new FixedPointCombMultiplier();
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/signers/GOST3410DigestSigner.cs b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
index bc32808df..bff35869b 100644
--- a/crypto/src/crypto/signers/GOST3410DigestSigner.cs
+++ b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -11,135 +11,144 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	public class Gost3410DigestSigner
-		: ISigner
-	{
-		private readonly IDigest digest;
-		private readonly IDsa dsaSigner;
-		private bool forSigning;
-
-		public Gost3410DigestSigner(
-			IDsa	signer,
-			IDigest	digest)
-		{
-			this.dsaSigner = signer;
-			this.digest = digest;
-		}
+    public class Gost3410DigestSigner
+        : ISigner
+    {
+        private readonly IDigest digest;
+        private readonly IDsa dsaSigner;
+        private readonly int size;
+        private int halfSize;
+        private bool forSigning;
+
+
+
+        public Gost3410DigestSigner(
+            IDsa signer,
+            IDigest digest)
+        {
+            this.dsaSigner = signer;
+            this.digest = digest;
+
+            halfSize = digest.GetDigestSize();
+            this.size = halfSize * 2;
+
+        }
 
         public virtual string AlgorithmName
-		{
-			get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
-		}
+        {
+            get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+        }
 
         public virtual void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
-		{
-			this.forSigning = forSigning;
-
-			AsymmetricKeyParameter k;
-			if (parameters is ParametersWithRandom)
-			{
-				k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
-			}
-			else
-			{
-				k = (AsymmetricKeyParameter)parameters;
-			}
-
-			if (forSigning && !k.IsPrivate)
-			{
-				throw new InvalidKeyException("Signing Requires Private Key.");
-			}
-
-			if (!forSigning && k.IsPrivate)
-			{
-				throw new InvalidKeyException("Verification Requires Public Key.");
-			}
-
-			Reset();
-
-			dsaSigner.Init(forSigning, parameters);
-		}
-
-		/**
+            bool forSigning,
+            ICipherParameters parameters)
+        {
+            this.forSigning = forSigning;
+
+            AsymmetricKeyParameter k;
+            if (parameters is ParametersWithRandom)
+            {
+                k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+            }
+            else
+            {
+                k = (AsymmetricKeyParameter)parameters;
+            }
+
+            if (forSigning && !k.IsPrivate)
+            {
+                throw new InvalidKeyException("Signing Requires Private Key.");
+            }
+
+            if (!forSigning && k.IsPrivate)
+            {
+                throw new InvalidKeyException("Verification Requires Public Key.");
+            }
+
+
+            Reset();
+
+            dsaSigner.Init(forSigning, parameters);
+        }
+
+        /**
 		 * update the internal digest with the byte b
 		 */
         public virtual void Update(
-			byte input)
-		{
-			digest.Update(input);
-		}
+            byte input)
+        {
+            digest.Update(input);
+        }
 
-		/**
+        /**
 		 * update the internal digest with the byte array in
 		 */
         public virtual void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		length)
-		{
-			digest.BlockUpdate(input, inOff, length);
-		}
-
-		/**
+            byte[] input,
+            int inOff,
+            int length)
+        {
+            digest.BlockUpdate(input, inOff, length);
+        }
+
+        /**
 		 * Generate a signature for the message we've been loaded with using
 		 * the key we were initialised with.
 		 */
         public virtual byte[] GenerateSignature()
-		{
-			if (!forSigning)
-				throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
-
-			byte[] hash = new byte[digest.GetDigestSize()];
-			digest.DoFinal(hash, 0);
-
-			try
-			{
-				BigInteger[] sig = dsaSigner.GenerateSignature(hash);
-				byte[] sigBytes = new byte[64];
-
-				// TODO Add methods to allow writing BigInteger to existing byte array?
-				byte[] r = sig[0].ToByteArrayUnsigned();
-				byte[] s = sig[1].ToByteArrayUnsigned();
-				s.CopyTo(sigBytes, 32 - s.Length);
-				r.CopyTo(sigBytes, 64 - r.Length);
-				return sigBytes;
-			}
-			catch (Exception e)
-			{
-				throw new SignatureException(e.Message, e);
-			}
-		}
-
-		/// <returns>true if the internal state represents the signature described in the passed in array.</returns>
+        {
+            if (!forSigning)
+                throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
+
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            try
+            {
+                BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+                byte[] sigBytes = new byte[size];
+
+                // TODO Add methods to allow writing BigInteger to existing byte array?
+                byte[] r = sig[0].ToByteArrayUnsigned();
+                byte[] s = sig[1].ToByteArrayUnsigned();
+                s.CopyTo(sigBytes, halfSize - s.Length);
+                r.CopyTo(sigBytes, size - r.Length);
+                return sigBytes;
+            }
+            catch (Exception e)
+            {
+                throw new SignatureException(e.Message, e);
+            }
+        }
+
+        /// <returns>true if the internal state represents the signature described in the passed in array.</returns>
         public virtual bool VerifySignature(
-			byte[] signature)
-		{
-			if (forSigning)
-				throw new InvalidOperationException("DSADigestSigner not initialised for verification");
-
-			byte[] hash = new byte[digest.GetDigestSize()];
-			digest.DoFinal(hash, 0);
-
-			BigInteger R, S;
-			try
-			{
-				R = new BigInteger(1, signature, 32, 32);
-				S = new BigInteger(1, signature, 0, 32);
-			}
-			catch (Exception e)
-			{
-				throw new SignatureException("error decoding signature bytes.", e);
-			}
-
-			return dsaSigner.VerifySignature(hash, R, S);
-		}
-
-		/// <summary>Reset the internal state</summary>
+            byte[] signature)
+        {
+            if (forSigning)
+                throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            BigInteger R, S;
+            try
+            {
+                R = new BigInteger(1, signature, halfSize, halfSize);
+                S = new BigInteger(1, signature, 0, halfSize);
+            }
+            catch (Exception e)
+            {
+                throw new SignatureException("error decoding signature bytes.", e);
+            }
+
+            return dsaSigner.VerifySignature(hash, R, S);
+        }
+
+        /// <summary>Reset the internal state</summary>
         public virtual void Reset()
-		{
-			digest.Reset();
-		}
-	}
+        {
+            digest.Reset();
+        }
+    }
 }
diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
index 3036dc8b6..75a56983a 100644
--- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -5,6 +5,7 @@ using Org.BouncyCastle.Asn1.CryptoPro;
 using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
@@ -117,10 +118,35 @@ namespace Org.BouncyCastle.Pkcs
 
             if (privateKey is ECPrivateKeyParameters)
             {
-                ECPrivateKeyParameters priv = (ECPrivateKeyParameters)privateKey;
+                ECPrivateKeyParameters priv = (ECPrivateKeyParameters) privateKey;                 
                 DerBitString publicKey = new DerBitString(ECKeyPairGenerator.GetCorrespondingPublicKey(priv).Q.GetEncoded(false));
 
                 ECDomainParameters dp = priv.Parameters;
+
+                // ECGOST3410
+                if (dp is ECGOST3410Parameters)
+                {
+                    ECGOST3410Parameters domainParameters = (ECGOST3410Parameters) dp;
+
+                    Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+                        (domainParameters).PublicKeyParamSet,
+                        (domainParameters).DigestParamSet,
+                        (domainParameters).EncryptionParamSet);
+
+                    bool is512 = priv.D.BitLength > 256;
+                    DerObjectIdentifier identifier = (is512) ?
+                        RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512 :
+                        RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256;
+                    int size = (is512) ? 64 : 32;
+
+                    byte[] encKey = new byte[size];
+
+                    ExtractBytes(encKey, size, 0, priv.D);
+
+                    return new PrivateKeyInfo(new AlgorithmIdentifier(identifier, gostParams), new DerOctetString(encKey));
+                } 
+
+
                 int orderBitLength = dp.N.BitLength;
 
                 AlgorithmIdentifier algID;
@@ -245,5 +271,21 @@ namespace Org.BouncyCastle.Pkcs
 
             return PrivateKeyInfo.GetInstance(keyBytes);
         }
+
+        private static void ExtractBytes(byte[] encKey, int size, int offSet, BigInteger bI)
+        {
+            byte[] val = bI.ToByteArray();
+            if (val.Length < size)
+            {
+                byte[] tmp = new byte[size];
+                Array.Copy(val, 0, tmp, tmp.Length - val.Length, val.Length);
+                val = tmp;
+            }
+
+            for (int i = 0; i != size; i++)
+            {
+                encKey[offSet + i] = val[val.Length - 1 - i];
+            }
+        }
     }
 }
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index 0b07d0659..9f2d2e9c1 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -8,6 +8,7 @@ using Org.BouncyCastle.Asn1.CryptoPro;
 using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
@@ -67,7 +68,7 @@ namespace Org.BouncyCastle.Security
                     keyStructure.Coefficient);
             }
             // TODO?
-//			else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
+            //			else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
             else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
             {
                 DHParameter para = new DHParameter(
@@ -82,7 +83,7 @@ namespace Org.BouncyCastle.Security
             }
             else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
             {
-                ElGamalParameter  para = new ElGamalParameter(
+                ElGamalParameter para = new ElGamalParameter(
                     Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
                 DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
 
@@ -126,7 +127,7 @@ namespace Org.BouncyCastle.Security
                     return new ECPrivateKeyParameters("EC", d, (DerObjectIdentifier)para.Parameters);
                 }
 
-                ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H,  x9.GetSeed());
+                ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
                 return new ECPrivateKeyParameters(d, dParams);
             }
             else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
@@ -163,14 +164,14 @@ namespace Org.BouncyCastle.Security
                 if (privKey is DerInteger)
                 {
                     x = DerInteger.GetInstance(privKey).PositiveValue;
-				}
+                }
                 else
                 {
                     x = new BigInteger(1, Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()));
-				}
+                }
 
-				return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
-			}
+                return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
+            }
             else if (algOid.Equals(EdECObjectIdentifiers.id_X25519))
             {
                 return new X25519PrivateKeyParameters(GetRawKey(keyInfo, X25519PrivateKeyParameters.KeySize), 0);
@@ -187,6 +188,117 @@ namespace Org.BouncyCastle.Security
             {
                 return new Ed448PrivateKeyParameters(GetRawKey(keyInfo, Ed448PrivateKeyParameters.KeySize), 0);
             }
+            else if (algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512)
+                     || algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256))
+            {
+                Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance(keyInfo.PrivateKeyAlgorithm.Parameters);
+                ECGOST3410Parameters ecSpec = null;
+                BigInteger d = null;
+                Asn1Object p = keyInfo.PrivateKeyAlgorithm.Parameters.ToAsn1Object();
+                if (p is Asn1Sequence && (Asn1Sequence.GetInstance(p).Count == 2 || Asn1Sequence.GetInstance(p).Count == 3))
+                {
+
+                    ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+                    ecSpec = new ECGOST3410Parameters(
+                        new ECNamedDomainParameters(
+                            gostParams.PublicKeyParamSet, ecP),
+                            gostParams.PublicKeyParamSet,
+                            gostParams.DigestParamSet,
+                            gostParams.EncryptionParamSet);
+                    Asn1Encodable privKey = keyInfo.ParsePrivateKey();
+                    if (privKey is DerInteger)
+                    {
+                        d = DerInteger.GetInstance(privKey).PositiveValue;
+                    }
+                    else
+                    {
+                        byte[] encVal = Asn1OctetString.GetInstance(privKey).GetOctets();
+                        byte[] dVal = new byte[encVal.Length];
+
+                        for (int i = 0; i != encVal.Length; i++)
+                        {
+                            dVal[i] = encVal[encVal.Length - 1 - i];
+                        }
+
+                        d = new BigInteger(1, dVal);
+                    }
+
+
+                }
+                else
+                {
+                    X962Parameters parameters = X962Parameters.GetInstance(keyInfo.PrivateKeyAlgorithm.Parameters);
+
+                    if (parameters.IsNamedCurve)
+                    {
+                        DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(parameters.Parameters);
+                        X9ECParameters ecP = ECNamedCurveTable.GetByOid(oid);
+                        if (ecP == null)
+                        {
+                            ECDomainParameters gParam = ECGost3410NamedCurves.GetByOid(oid);
+                            ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters(
+                                    oid,
+                                    gParam.Curve,
+                                    gParam.G,
+                                    gParam.N,
+                                    gParam.H,
+                                    gParam.GetSeed()), gostParams.PublicKeyParamSet, gostParams.DigestParamSet,
+                                gostParams.EncryptionParamSet);
+                        }
+                        else
+                        {
+                            ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters(
+                                    oid,
+                                    ecP.Curve,
+                                    ecP.G,
+                                    ecP.N,
+                                    ecP.H,
+                                    ecP.GetSeed()), gostParams.PublicKeyParamSet, gostParams.DigestParamSet,
+                                gostParams.EncryptionParamSet);
+                        }
+                    }
+                    else if (parameters.IsImplicitlyCA)
+                    {
+                        ecSpec = null;
+                    }
+                    else
+                    {
+                        X9ECParameters ecP = X9ECParameters.GetInstance(parameters.Parameters);
+                        ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters(
+                                algOid,
+                                ecP.Curve,
+                                ecP.G,
+                                ecP.N,
+                                ecP.H,
+                                ecP.GetSeed()),
+                            gostParams.PublicKeyParamSet,
+                            gostParams.DigestParamSet,
+                            gostParams.EncryptionParamSet);
+                    }
+
+                    Asn1Encodable privKey = keyInfo.ParsePrivateKey();
+                    if (privKey is DerInteger)
+                    {
+                        DerInteger derD = DerInteger.GetInstance(privKey);
+                        d = derD.Value;
+                    }
+                    else
+                    {
+                        ECPrivateKeyStructure ec = ECPrivateKeyStructure.GetInstance(privKey);
+                        d = ec.GetKey();
+                    }
+                }
+
+                return new ECPrivateKeyParameters(
+                    d,
+                    new ECGOST3410Parameters(
+                        ecSpec,
+                        gostParams.PublicKeyParamSet,
+                        gostParams.DigestParamSet,
+                        gostParams.EncryptionParamSet));
+
+            }
             else
             {
                 throw new SecurityUtilityException("algorithm identifier in private key not recognised");
@@ -203,50 +315,50 @@ namespace Org.BouncyCastle.Security
         }
 
         public static AsymmetricKeyParameter DecryptKey(
-            char[]					passPhrase,
-            EncryptedPrivateKeyInfo	encInfo)
+            char[] passPhrase,
+            EncryptedPrivateKeyInfo encInfo)
         {
             return CreateKey(PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase, encInfo));
         }
 
         public static AsymmetricKeyParameter DecryptKey(
-            char[]	passPhrase,
-            byte[]	encryptedPrivateKeyInfoData)
+            char[] passPhrase,
+            byte[] encryptedPrivateKeyInfoData)
         {
             return DecryptKey(passPhrase, Asn1Object.FromByteArray(encryptedPrivateKeyInfoData));
         }
 
         public static AsymmetricKeyParameter DecryptKey(
-            char[]	passPhrase,
-            Stream	encryptedPrivateKeyInfoStream)
+            char[] passPhrase,
+            Stream encryptedPrivateKeyInfoStream)
         {
             return DecryptKey(passPhrase, Asn1Object.FromStream(encryptedPrivateKeyInfoStream));
         }
 
         private static AsymmetricKeyParameter DecryptKey(
-            char[]		passPhrase,
-            Asn1Object	asn1Object)
+            char[] passPhrase,
+            Asn1Object asn1Object)
         {
             return DecryptKey(passPhrase, EncryptedPrivateKeyInfo.GetInstance(asn1Object));
         }
 
         public static byte[] EncryptKey(
-            DerObjectIdentifier		algorithm,
-            char[]					passPhrase,
-            byte[]					salt,
-            int						iterationCount,
-            AsymmetricKeyParameter	key)
+            DerObjectIdentifier algorithm,
+            char[] passPhrase,
+            byte[] salt,
+            int iterationCount,
+            AsymmetricKeyParameter key)
         {
             return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
                 algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
         }
 
         public static byte[] EncryptKey(
-            string					algorithm,
-            char[]					passPhrase,
-            byte[]					salt,
-            int						iterationCount,
-            AsymmetricKeyParameter	key)
+            string algorithm,
+            char[] passPhrase,
+            byte[] salt,
+            int iterationCount,
+            AsymmetricKeyParameter key)
         {
             return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
                 algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs
index e39748e45..3623c3ee2 100644
--- a/crypto/src/security/PublicKeyFactory.cs
+++ b/crypto/src/security/PublicKeyFactory.cs
@@ -8,6 +8,7 @@ using Org.BouncyCastle.Asn1.CryptoPro;
 using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
@@ -16,6 +17,7 @@ using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Security
 {
@@ -234,6 +236,40 @@ namespace Org.BouncyCastle.Security
             else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448))
             {
                 return new Ed448PublicKeyParameters(GetRawKey(keyInfo, Ed448PublicKeyParameters.KeySize), 0);
+            } else if (
+                algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256) ||
+                algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512))
+            {
+
+                byte[] keyEnc = ((DerOctetString)Asn1Object.FromByteArray(keyInfo.PublicKeyData.GetOctets())).str;
+
+                int fieldSize = 32;
+                if (algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512))
+                {
+                    fieldSize = 64;
+                }
+
+                int keySize = 2 * fieldSize;
+
+                byte[] x9Encoding = new byte[1 + keySize];
+                x9Encoding[0] = 0x04;
+                for (int i = 1; i <= fieldSize; ++i)
+                {
+                    x9Encoding[i] = keyEnc[fieldSize - i];
+                    x9Encoding[i + fieldSize] = keyEnc[keySize - i];
+                }
+
+                Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance(keyInfo.AlgorithmID.Parameters);
+
+                ECGOST3410Parameters ecDomainParameters =
+                    new ECGOST3410Parameters(
+                        new ECNamedDomainParameters(gostParams.PublicKeyParamSet, ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet)),
+                        gostParams.PublicKeyParamSet,
+                        gostParams.DigestParamSet,
+                        gostParams.EncryptionParamSet);
+              
+                return new ECPublicKeyParameters(ecDomainParameters.Curve.DecodePoint(x9Encoding), ecDomainParameters);
+
             }
             else
             {
diff --git a/crypto/src/util/BigIntegers.cs b/crypto/src/util/BigIntegers.cs
index df78d1d86..6674750bb 100644
--- a/crypto/src/util/BigIntegers.cs
+++ b/crypto/src/util/BigIntegers.cs
@@ -46,6 +46,17 @@ namespace Org.BouncyCastle.Utilities
             return tmp;
         }
 
+        /// <summary>
+        /// Creates a Random BigInteger from the secure random of a given bit length.
+        /// </summary>
+        /// <param name="bitLength"></param>
+        /// <param name="secureRandom"></param>
+        /// <returns></returns>
+        public static BigInteger CreateRandomBigInteger(int bitLength, SecureRandom secureRandom)
+        {
+            return new BigInteger(bitLength, secureRandom);
+        }
+
         /**
         * Return a random BigInteger not less than 'min' and not greater than 'max'
         * 
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
index 2fa8b7a28..234bcff34 100644
--- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -6,12 +6,14 @@ using Org.BouncyCastle.Asn1.CryptoPro;
 using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.X509
 {
@@ -91,9 +93,54 @@ namespace Org.BouncyCastle.X509
             } // End of RSA.
 
             if (publicKey is ECPublicKeyParameters)
-            {
+            {            
+               
                 ECPublicKeyParameters _key = (ECPublicKeyParameters) publicKey;
 
+
+                if (_key.Parameters is ECGOST3410Parameters)
+                {
+                    ECGOST3410Parameters gostParams = (ECGOST3410Parameters)_key.Parameters;
+
+                    BigInteger bX = _key.Q.AffineXCoord.ToBigInteger();
+                    BigInteger bY = _key.Q.AffineYCoord.ToBigInteger();
+                    bool is512 = (bX.BitLength > 256);
+
+                    Gost3410PublicKeyAlgParameters parameters = new Gost3410PublicKeyAlgParameters(
+                        gostParams.PublicKeyParamSet,
+                        gostParams.DigestParamSet,
+                        gostParams.EncryptionParamSet);
+
+                    int encKeySize;
+                    int offset;
+                    DerObjectIdentifier algIdentifier;
+                    if (is512)
+                    {
+                        encKeySize = 128;
+                        offset = 64;
+                        algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512;
+                    }
+                    else
+                    {
+                        encKeySize = 64;
+                        offset = 32;
+                        algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256;
+                    }
+
+                    byte[] encKey = new byte[encKeySize];
+               
+                    ExtractBytes(encKey, encKeySize / 2, 0, bX);
+                    ExtractBytes(encKey, encKeySize / 2, offset, bY);
+                  
+                    return new SubjectPublicKeyInfo(new AlgorithmIdentifier(algIdentifier, parameters), new DerOctetString(encKey));
+                   
+
+                } // End of ECGOST3410_2012
+
+
+
+
+
                 if (_key.AlgorithmName == "ECGOST3410")
                 {
                     if (_key.PublicKeyParamSet == null)
@@ -209,5 +256,22 @@ namespace Org.BouncyCastle.X509
                 encKey[offset + i] = val[val.Length - 1 - i];
             }
         }
+
+
+        private static void ExtractBytes(byte[] encKey, int size, int offSet, BigInteger bI)
+        {
+            byte[] val = bI.ToByteArray();
+            if (val.Length < size)
+            {
+                byte[] tmp = new byte[size];
+                Array.Copy(val, 0, tmp, tmp.Length - val.Length, val.Length);
+                val = tmp;
+            }
+
+            for (int i = 0; i != size; i++)
+            {
+                encKey[offSet + i] = val[val.Length - 1 - i];
+            }
+        }
     }
 }
diff --git a/crypto/test/src/crypto/test/ECGOST3410_2012Test.cs b/crypto/test/src/crypto/test/ECGOST3410_2012Test.cs
new file mode 100644
index 000000000..94726bc92
--- /dev/null
+++ b/crypto/test/src/crypto/test/ECGOST3410_2012Test.cs
@@ -0,0 +1,597 @@
+using System;
+using NUnit.Framework;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class ECGOST3410_2012Test:SimpleTest
+    {
+        public override string Name
+        {
+            get { return "ECGOST3410-2012-Test"; }
+        }
+
+        public SimpleTestResult EncodeRecodePublicKey()
+        {
+
+            DerObjectIdentifier oid = ECGost3410NamedCurves.GetOid("Tc26-Gost-3410-12-512-paramSetA");
+            ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGost3410NamedCurves.GetByOid(oid));
+            ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512,null);
+            ECKeyGenerationParameters paramameters = new ECKeyGenerationParameters(gostParams, new SecureRandom());
+            ECKeyPairGenerator engine = new ECKeyPairGenerator();
+            engine.Init(paramameters);
+            AsymmetricCipherKeyPair pair = engine.GenerateKeyPair();
+
+            ECPublicKeyParameters generatedKeyParameters = (ECPublicKeyParameters)pair.Public;
+            ECPublicKeyParameters keyParameters = generatedKeyParameters;
+
+
+            //
+            // Continuously encode/decode the key and check for loss of information.
+            //          
+                for (int t = 0; t < 3; t++)
+                {
+
+                    SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyParameters);
+                    keyParameters = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(info);
+
+                    { // Specifically cast and test gost parameters.
+                        ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.Parameters;
+                        ECGOST3410Parameters rParam = (ECGOST3410Parameters)keyParameters.Parameters;
+
+
+                        bool ok = SafeEquals(gParam.DigestParamSet, rParam.DigestParamSet) &&
+                            SafeEquals(gParam.EncryptionParamSet, rParam.EncryptionParamSet) &&
+                            SafeEquals(gParam.PublicKeyParamSet, rParam.PublicKeyParamSet);
+
+                        if (!ok)
+                        {
+                            return new SimpleTestResult(false, "GOST parameters does not match");
+                        }
+
+                    }
+
+                    if (!((ECGOST3410Parameters)keyParameters.Parameters).Name.Equals(
+                        ((ECGOST3410Parameters)generatedKeyParameters.Parameters).Name))
+                    {
+                        return new SimpleTestResult(false, "Name does not match");
+                    }
+
+
+                    if (keyParameters.IsPrivate != generatedKeyParameters.IsPrivate)
+                    {
+                        return new SimpleTestResult(false, "isPrivate does not match");
+                    }
+
+                    if (!Arrays.AreEqual(keyParameters.Q.GetEncoded(true), generatedKeyParameters.Q.GetEncoded(true)))
+                    {
+                        return new SimpleTestResult(false, "Q does not match");
+                    }
+
+                    if (!keyParameters.Parameters.Curve.Equals(generatedKeyParameters.Parameters.Curve))
+                    {
+                        return new SimpleTestResult(false, "Curve does not match");
+                    }
+
+                    if (!Arrays.AreEqual(
+                        keyParameters.Parameters.G.GetEncoded(true),
+                        generatedKeyParameters.Parameters.G.GetEncoded(true)))
+                    {
+                        return new SimpleTestResult(false, "G does not match");
+                    }
+
+                    if (!keyParameters.Parameters.H.Equals(generatedKeyParameters.Parameters.H))
+                    {
+                        return new SimpleTestResult(false, "H does not match");
+                    }
+
+                    if (!keyParameters.Parameters.HInv.Equals(generatedKeyParameters.Parameters.HInv))
+                    {
+                        return new SimpleTestResult(false, "Hinv does not match");
+                    }
+
+                    if (!keyParameters.Parameters.N.Equals(generatedKeyParameters.Parameters.N))
+                    {
+                        return new SimpleTestResult(false, "N does not match");
+                    }
+
+                    if (!Arrays.AreEqual(keyParameters.Parameters.GetSeed(), generatedKeyParameters.Parameters.GetSeed()))
+                    {
+                        return new SimpleTestResult(false, "Seed does not match");
+                    }
+                }
+                return new SimpleTestResult(true, null);
+            
+
+        }
+
+
+        private SimpleTestResult EncodeRecodePrivateKey()
+        {
+           
+                DerObjectIdentifier oid = ECGost3410NamedCurves.GetOid("Tc26-Gost-3410-12-512-paramSetA");
+                ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGost3410NamedCurves.GetByOid(oid));
+                ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512,null);
+                ECKeyGenerationParameters parameters = new ECKeyGenerationParameters(gostParams, new SecureRandom());
+                ECKeyPairGenerator engine = new ECKeyPairGenerator();
+                engine.Init(parameters);
+                AsymmetricCipherKeyPair pair = engine.GenerateKeyPair();
+
+                ECPrivateKeyParameters generatedKeyParameters = (ECPrivateKeyParameters)pair.Private;
+                ECPrivateKeyParameters keyParameters = generatedKeyParameters;
+
+
+                //
+                // Continuously encode/decode the key and check for loss of information.
+                //
+
+
+                for (int t = 0; t < 3; t++)
+                {
+                    PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyParameters);
+                    keyParameters = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(info);
+
+                    { // Specifically cast and test gost parameters.
+                        ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.Parameters;
+                        ECGOST3410Parameters rParam = (ECGOST3410Parameters)keyParameters.Parameters;
+
+                        bool ok = SafeEquals(gParam.DigestParamSet, rParam.DigestParamSet) &&
+                            SafeEquals(gParam.EncryptionParamSet, rParam.EncryptionParamSet) &&
+                            SafeEquals(gParam.PublicKeyParamSet, rParam.PublicKeyParamSet);
+
+                        if (!ok)
+                        {
+                            return new SimpleTestResult(false, "GOST parameters does not match");
+                        }
+
+                    }
+
+                    if (keyParameters.IsPrivate != generatedKeyParameters.IsPrivate)
+                    {
+                        return new SimpleTestResult(false, "isPrivate does not match");
+                    }
+
+                    if (!keyParameters.D.Equals(generatedKeyParameters.D))
+                    {
+                        return new SimpleTestResult(false, "D does not match");
+                    }
+
+                    if (!((ECGOST3410Parameters)keyParameters.Parameters).Name.Equals(
+                        ((ECGOST3410Parameters)generatedKeyParameters.Parameters).Name))
+                    {
+                        return new SimpleTestResult(false, "Name does not match");
+                    }
+
+                    if (!keyParameters.Parameters.Curve.Equals(generatedKeyParameters.Parameters.Curve))
+                    {
+                        return new SimpleTestResult(false, "Curve does not match");
+                    }
+
+                    if (!Arrays.AreEqual(
+                        keyParameters.Parameters.G.GetEncoded(true),
+                        generatedKeyParameters.Parameters.G.GetEncoded(true)))
+                    {
+                        return new SimpleTestResult(false, "G does not match");
+                    }
+
+                    if (!keyParameters.Parameters.H.Equals(generatedKeyParameters.Parameters.H))
+                    {
+                        return new SimpleTestResult(false, "H does not match");
+                    }
+
+                    if (!keyParameters.Parameters.HInv.Equals(generatedKeyParameters.Parameters.HInv))
+                    {
+                        return new SimpleTestResult(false, "Hinv does not match");
+                    }
+
+                    if (!keyParameters.Parameters.N.Equals(generatedKeyParameters.Parameters.N))
+                    {
+                        return new SimpleTestResult(false, "N does not match");
+                    }
+
+                    if (!Arrays.AreEqual(keyParameters.Parameters.GetSeed(), generatedKeyParameters.Parameters.GetSeed()))
+                    {
+                        return new SimpleTestResult(false, "Seed does not match");
+                    }
+                }
+
+
+          
+            return new SimpleTestResult(true, null);
+        }
+
+        private SimpleTestResult DecodeJCEPublic()
+        {
+            byte[] pub256 = Hex.Decode("3068302106082a85030701010101301506092a850307010201010106082a850307010102020343000440292335c87d892510c35a033819a13e2b0dc606d911676af2bad8872d74a4b7bae6c729e98ace04c3dee626343f794731e1489edb7bc26f1c8c56e1448c96501a");
+
+                ECPublicKeyParameters pkInfo = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(pub256);
+
+                if (pkInfo.IsPrivate)
+                {
+                    return new SimpleTestResult(false, "isPrivate should be false");
+                }
+
+                if (
+                    !Arrays.AreEqual(
+                        pkInfo.Q.GetEncoded(true),
+                        Hex.Decode("02bab7a4742d87d8baf26a6711d906c60d2b3ea11938035ac31025897dc8352329")))
+                {
+                    return new SimpleTestResult(false, "Q does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).PublicKeyParamSet.ToString().Equals("1.2.643.7.1.2.1.1.1"))
+                {
+                    return new SimpleTestResult(false, "PublicKeyParamSet does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).DigestParamSet.ToString().Equals("1.2.643.7.1.1.2.2"))
+                {
+                    return new SimpleTestResult(false, "DigestParamSet does not match");
+                }
+
+                if (((ECGOST3410Parameters)pkInfo.Parameters).EncryptionParamSet != null)
+                {
+                    return new SimpleTestResult(false, "EncryptionParamSet is not null");
+                }
+
+
+                byte[] pub512 = Hex.Decode("3081aa302106082a85030701010102301506092a850307010201020106082a850307010102030381840004818043ccc22692ee8a1870c7c9de0566d7e3a494cf0e3c80f9e8852a3d1ec10d2a829d357253e0864aee2eaacd5e2d327578dee771f62f24decfd6358e06199efe540e7912db43c4c80fe0fd31f7f67a862f9d44fd0075cfee6e3d638c7520063d26311ef962547e8129fb8c5b194e129370cd30313884b4a60872254a10772fe595");
+
+                pkInfo = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(pub512);
+
+                if (pkInfo.IsPrivate)
+                {
+                    return new SimpleTestResult(false, "isPrivate should be true");
+                }
+
+                if (
+                    !Arrays.AreEqual(
+                        pkInfo.Q.GetEncoded(true),
+                        Hex.Decode("0254fe9e19068e35d6cfde242ff671e7de7875322d5ecdaa2eee4a86e05372359d822a0dc11e3d2a85e8f9803c0ecf94a4e3d76605dec9c770188aee9226c2cc43")))
+                {
+                    return new SimpleTestResult(false, "Q does not match");
+                }
+
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).PublicKeyParamSet.ToString().Equals("1.2.643.7.1.2.1.2.1"))
+                {
+                    return new SimpleTestResult(false, "PublicKeyParamSet does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).DigestParamSet.ToString().Equals("1.2.643.7.1.1.2.3"))
+                {
+                    return new SimpleTestResult(false, "DigestParamSet does not match");
+                }
+
+                if (((ECGOST3410Parameters)pkInfo.Parameters).EncryptionParamSet != null)
+                {
+                    return new SimpleTestResult(false, "EncryptionParamSet is not null");
+                }
+
+           
+
+            return new SimpleTestResult(true, null);
+        }
+
+        private SimpleTestResult DecodeJCEPrivate()
+        {
+            byte[] priv256 = Hex.Decode("304a020100302106082a85030701010101301506092a850307010201010106082a8503070101020204220420fe75ba328d5439ed4859e6dc7e6ca2e9aab0818f094eddeb0d57d1c16a90762b");          
+                ECPrivateKeyParameters pkInfo = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(priv256);
+
+                if (!pkInfo.IsPrivate)
+                {
+                    return new SimpleTestResult(false, "isPrivate should be true");
+                }
+
+                if (
+                    !Arrays.AreEqual(
+                        Hex.Decode("2b76906ac1d1570debdd4e098f81b0aae9a26c7edce65948ed39548d32ba75fe"),
+                        pkInfo.D.ToByteArray()))
+                {
+                    return new SimpleTestResult(false, "D does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).PublicKeyParamSet.ToString().Equals("1.2.643.7.1.2.1.1.1"))
+                {
+                    return new SimpleTestResult(false, "PublicKeyParamSet does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).DigestParamSet.ToString().Equals("1.2.643.7.1.1.2.2"))
+                {
+                    return new SimpleTestResult(false, "DigestParamSet does not match");
+                }
+
+                if (((ECGOST3410Parameters)pkInfo.Parameters).EncryptionParamSet != null)
+                {
+                    return new SimpleTestResult(false, "EncryptionParamSet is not null");
+                }
+
+
+                byte[] priv512 = Hex.Decode("306a020100302106082a85030701010102301506092a850307010201020106082a85030701010203044204402fc35576152f6e873236608b592b4b98d0793bf5184f8dc4a99512be703716991a96061ef46aceeae5319b5c69e6fcbfa7e339207878597ce50f9b7cbf857ff1");
+
+                pkInfo = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(priv512);
+
+                if (!pkInfo.IsPrivate)
+                {
+                    return new SimpleTestResult(false, "isPrivate should be true");
+                }
+
+                if (
+                    !Arrays.AreEqual(
+                        Hex.Decode("00f17f85bf7c9b0fe57c5978782039e3a7bffce6695c9b31e5eace6af41e06961a99163770be1295a9c48d4f18f53b79d0984b2b598b603632876e2f157655c32f"),
+                        pkInfo.D.ToByteArray()))
+                {
+                    return new SimpleTestResult(false, "D does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).PublicKeyParamSet.ToString().Equals("1.2.643.7.1.2.1.2.1"))
+                {
+                    return new SimpleTestResult(false, "PublicKeyParamSet does not match");
+                }
+
+                if (!((ECGOST3410Parameters)pkInfo.Parameters).DigestParamSet.ToString().Equals("1.2.643.7.1.1.2.3"))
+                {
+                    return new SimpleTestResult(false, "DigestParamSet does not match");
+                }
+
+                if (((ECGOST3410Parameters)pkInfo.Parameters).EncryptionParamSet != null)
+                {
+                    return new SimpleTestResult(false, "EncryptionParamSet is not null");
+                }
+
+           
+
+            return new SimpleTestResult(true, null);
+        }
+
+
+
+        public SimpleTestResult EncodeDecodePrivateLW(String oidStr, DerObjectIdentifier digest)
+        {
+            DerObjectIdentifier oid = ECGost3410NamedCurves.GetOid(oidStr);
+            ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGost3410NamedCurves.GetByOid(oid));
+            ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, digest, null);
+            ECKeyGenerationParameters parameters = new ECKeyGenerationParameters(gostParams, new SecureRandom());
+            ECKeyPairGenerator engine = new ECKeyPairGenerator();
+            engine.Init(parameters);
+            AsymmetricCipherKeyPair pair = engine.GenerateKeyPair();
+
+
+            ECPrivateKeyParameters generatedKeyParameters = (ECPrivateKeyParameters) pair.Private;
+
+            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(generatedKeyParameters);
+
+            ECPrivateKeyParameters recoveredKeyParameters = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(info);
+
+
+            { // Specifically cast and test gost parameters.
+                ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.Parameters;
+                ECGOST3410Parameters rParam = (ECGOST3410Parameters)recoveredKeyParameters.Parameters;
+
+                bool ok = SafeEquals(gParam.DigestParamSet, rParam.DigestParamSet) &&
+                    SafeEquals(gParam.EncryptionParamSet, rParam.EncryptionParamSet) &&
+                    SafeEquals(gParam.PublicKeyParamSet, rParam.PublicKeyParamSet);
+
+                if (!ok)
+                {
+                    return new SimpleTestResult(false, "GOST parameters does not match");
+                }
+
+            }
+
+
+            if (recoveredKeyParameters.IsPrivate != generatedKeyParameters.IsPrivate)
+            {
+                return new SimpleTestResult(false, "isPrivate does not match");
+            }
+
+            if (!((ECGOST3410Parameters)recoveredKeyParameters.Parameters).Name.Equals(
+                ((ECGOST3410Parameters)generatedKeyParameters.Parameters).Name))
+            {
+                return new SimpleTestResult(false, "Name does not match");
+            }
+
+
+            if (!recoveredKeyParameters.D.Equals(generatedKeyParameters.D))
+            {
+                return new SimpleTestResult(false, "D does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.Curve.Equals(generatedKeyParameters.Parameters.Curve))
+            {
+                return new SimpleTestResult(false, "Curve does not match");
+            }
+
+            if (!Arrays.AreEqual(
+                recoveredKeyParameters.Parameters.G.GetEncoded(true),
+                generatedKeyParameters.Parameters.G.GetEncoded(true)))
+            {
+                return new SimpleTestResult(false, "G does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.H.Equals(generatedKeyParameters.Parameters.H))
+            {
+                return new SimpleTestResult(false, "H does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.HInv.Equals(generatedKeyParameters.Parameters.HInv))
+            {
+                return new SimpleTestResult(false, "Hinv does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.N.Equals(generatedKeyParameters.Parameters.N))
+            {
+                return new SimpleTestResult(false, "N does not match");
+            }
+
+            if (!Arrays.AreEqual(recoveredKeyParameters.Parameters.GetSeed(), generatedKeyParameters.Parameters.GetSeed()))
+            {
+                return new SimpleTestResult(false, "Seed does not match");
+            }
+
+            return new SimpleTestResult(true, null);
+        }
+
+        public SimpleTestResult EncodeDecodePublicLW(string oidStr, DerObjectIdentifier digest)
+        {         
+            DerObjectIdentifier oid = ECGost3410NamedCurves.GetOid(oidStr);
+            ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGost3410NamedCurves.GetByOid(oid));
+            ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp,oid,digest,null);
+            ECKeyGenerationParameters parameters = new ECKeyGenerationParameters(gostParams, new SecureRandom());
+            ECKeyPairGenerator engine = new ECKeyPairGenerator();
+            engine.Init(parameters);
+            AsymmetricCipherKeyPair pair = engine.GenerateKeyPair();
+            ECPublicKeyParameters generatedKeyParameters = (ECPublicKeyParameters)pair.Public;
+
+            SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(generatedKeyParameters);
+
+            ECPublicKeyParameters recoveredKeyParameters = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(info);
+
+            { // Specifically cast and test gost parameters.
+                ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.Parameters;
+                ECGOST3410Parameters rParam = (ECGOST3410Parameters)recoveredKeyParameters.Parameters;
+
+
+                bool ok = SafeEquals(gParam.DigestParamSet, rParam.DigestParamSet) &&
+                             SafeEquals(gParam.EncryptionParamSet, rParam.EncryptionParamSet) &&
+                             SafeEquals(gParam.PublicKeyParamSet, rParam.PublicKeyParamSet);
+
+                if (!ok)
+                {
+                    return new SimpleTestResult(false, "GOST parameters does not match");
+                }
+
+            }
+
+            if (!((ECGOST3410Parameters)recoveredKeyParameters.Parameters).Name.Equals(
+                   ((ECGOST3410Parameters)generatedKeyParameters.Parameters).Name))
+            {
+                return new SimpleTestResult(false, "Name does not match");
+            }
+
+
+            if (recoveredKeyParameters.IsPrivate != generatedKeyParameters.IsPrivate)
+            {
+                return new SimpleTestResult(false, "isPrivate does not match");
+            }
+
+            if (!Arrays.AreEqual(recoveredKeyParameters.Q.GetEncoded(true), generatedKeyParameters.Q.GetEncoded(true)))
+            {
+                return new SimpleTestResult(false, "Q does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.Curve.Equals(generatedKeyParameters.Parameters.Curve))
+            {
+                return new SimpleTestResult(false, "Curve does not match");
+            }
+
+            if (!Arrays.AreEqual(
+                recoveredKeyParameters.Parameters.G.GetEncoded(true),
+                generatedKeyParameters.Parameters.G.GetEncoded(true)))
+            {
+                return new SimpleTestResult(false, "G does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.H.Equals(generatedKeyParameters.Parameters.H))
+            {
+                return new SimpleTestResult(false, "H does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.HInv.Equals(generatedKeyParameters.Parameters.HInv))
+            {
+                return new SimpleTestResult(false, "Hinv does not match");
+            }
+
+            if (!recoveredKeyParameters.Parameters.N.Equals(generatedKeyParameters.Parameters.N))
+            {
+                return new SimpleTestResult(false, "N does not match");
+            }
+
+            if (!Arrays.AreEqual(recoveredKeyParameters.Parameters.GetSeed(), generatedKeyParameters.Parameters.GetSeed()))
+            {
+                return new SimpleTestResult(false, "Seed does not match");
+            }
+
+            return new SimpleTestResult(true, null);          
+        }
+
+        [Test]
+        public override void PerformTest()
+        {
+
+            SimpleTestResult str = EncodeDecodePublicLW("Tc26-Gost-3410-12-512-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512);
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+            str = EncodeDecodePrivateLW("Tc26-Gost-3410-12-512-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512);
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+
+            str = EncodeDecodePublicLW("Tc26-Gost-3410-12-256-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256);
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+            str = EncodeDecodePrivateLW("Tc26-Gost-3410-12-256-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256);
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+
+            str = DecodeJCEPrivate();
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+            str = DecodeJCEPublic();
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+            str = EncodeRecodePrivateKey();
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+            str = EncodeRecodePublicKey();
+            if (!str.IsSuccessful())
+            {
+                Fail(str.ToString(), str.GetException());
+            }
+
+        }
+
+        private bool SafeEquals(object left, object right)
+        {
+            if (left == null || right == null)
+            {
+                return left == null && right == null;
+            }
+
+            return left.Equals(right);
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/EGOST3410_2012SignatureTest.cs b/crypto/test/src/crypto/test/EGOST3410_2012SignatureTest.cs
new file mode 100644
index 000000000..0065174ed
--- /dev/null
+++ b/crypto/test/src/crypto/test/EGOST3410_2012SignatureTest.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Security.Cryptography.X509Certificates;
+using NUnit.Framework;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Rosstandart;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class EGOST3410_2012SignatureTest : SimpleTest
+    {
+        public override string Name { get; }
+
+        [Test]
+        public override void PerformTest()
+        {
+            EcGOST34102012256Test();
+        }
+
+        
+        public void EcGOST34102012256Test()
+        {
+            BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395");
+            BigInteger s = new BigInteger("574973400270084654178925310019147038455227042649098563933718999175515839552");
+
+            BigInteger e = new BigInteger("20798893674476452017134061561508270130637142515379653289952617252661468872421");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395"));
+            SecureRandom k = new TestRandomBigInteger(kData);
+
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041");
+            BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619");
+
+
+            ECCurve curve = new FpCurve(
+                mod_p,
+                new BigInteger("7"), // a
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b
+                mod_q, BigInteger.One);
+
+            ECDomainParameters spec = new ECDomainParameters(curve,
+                curve.CreatePoint(
+                    new BigInteger("2"), // x
+                    new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y
+                mod_q, BigInteger.One);
+
+            ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(
+                new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d
+                spec);
+
+            ECPublicKeyParameters publicKey = new ECPublicKeyParameters(curve.CreatePoint(
+                    new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"), // x
+                    new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")), // y
+                spec);
+
+            ECGOST3410_2012Signer signer = new ECGOST3410_2012Signer();
+            signer.Init(true, new ParametersWithRandom(privateKey, k));
+
+            byte[] rev = e.ToByteArray();
+            byte[] message = new byte[rev.Length];
+            for (int i = 0; i != rev.Length; i++)
+            {
+                message[i] = rev[rev.Length - 1 - i];
+            }
+            BigInteger[] sig = signer.GenerateSignature(message);
+
+            signer.Init(false, publicKey);
+
+            if (!signer.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("ECGOST3410 2012 verification failed");
+            }
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail(
+                    ": r component wrong." + Environment.NewLine
+                                           + " expecting: " + r + Environment.NewLine
+                                           + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail(
+                    ": s component wrong." + Environment.NewLine
+                                           + " expecting: " + s + Environment.NewLine
+                                           + " got      : " + sig[1]);
+            }
+
+
+            // 256Bit
+            {
+                DerObjectIdentifier oid = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA;
+                ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGost3410NamedCurves.GetByOid(oid));
+                ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid,
+                    RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256, null);
+                ECKeyGenerationParameters parameters = new ECKeyGenerationParameters(gostParams, new SecureRandom());
+                ECKeyPairGenerator engine = new ECKeyPairGenerator();
+                engine.Init(parameters);
+                AsymmetricCipherKeyPair pair = engine.GenerateKeyPair();
+                SignatureGost12Test("ECGOST3410-2012-256", 64, pair);
+            }
+
+            // 512Bit
+
+
+            {
+                DerObjectIdentifier oid = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA;
+                ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGost3410NamedCurves.GetByOid(oid));
+                ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid,
+                    RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512, null);
+                ECKeyGenerationParameters parameters = new ECKeyGenerationParameters(gostParams, new SecureRandom());
+                ECKeyPairGenerator engine = new ECKeyPairGenerator();
+                engine.Init(parameters);
+                AsymmetricCipherKeyPair pair = engine.GenerateKeyPair();
+
+                SignatureGost12Test("ECGOST3410-2012-512", 128, pair);
+
+            }
+        }
+
+
+
+        private void SignatureGost12Test(String signatureAlg, int expectedSignLen, AsymmetricCipherKeyPair p)
+
+        {
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+            ECPrivateKeyParameters sKey = (ECPrivateKeyParameters)p.Private;
+            ECPublicKeyParameters vKey = (ECPublicKeyParameters)p.Public;
+
+            ECGOST3410_2012Signer s = new ECGOST3410_2012Signer();
+
+            s.Init(true, sKey);
+            BigInteger[] sig = s.GenerateSignature(data);
+
+
+            s = new ECGOST3410_2012Signer();
+            s.Init(false, vKey);
+
+            if (!s.VerifySignature(data, sig[0], sig[1]))
+            {
+                Fail("Signature " + signatureAlg + " did not verify");
+            }
+
+            //
+            // Test with Digest signer.
+            //           
+            Gost3410DigestSigner digestSigner = new Gost3410DigestSigner(
+                new ECGOST3410_2012Signer(),
+                DigestUtilities.GetDigest(((ECGOST3410Parameters)vKey.Parameters).DigestParamSet));
+            digestSigner.Init(true, sKey);
+            digestSigner.BlockUpdate(data, 0, data.Length);
+            byte[] sigBytes = digestSigner.GenerateSignature();
+
+            if (sigBytes.Length != expectedSignLen)
+            {
+                Fail(signatureAlg + " signature failed at expected length");
+            }
+
+            digestSigner = new Gost3410DigestSigner(
+                new ECGOST3410_2012Signer(),
+                DigestUtilities.GetDigest(((ECGOST3410Parameters)vKey.Parameters).DigestParamSet));
+            digestSigner.Init(false, vKey);
+            digestSigner.BlockUpdate(data, 0, data.Length);
+
+            if (!digestSigner.VerifySignature(sigBytes))
+            {
+                Fail("Signature " + signatureAlg + " did not verify");
+            }
+        }
+
+
+    }
+}
\ No newline at end of file