diff options
-rw-r--r-- | crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs | 52 | ||||
-rw-r--r-- | crypto/src/crypto/parameters/ECGOST3410Parameters.cs | 51 | ||||
-rw-r--r-- | crypto/src/crypto/parameters/ECNamedDomainParameters.cs | 35 | ||||
-rw-r--r-- | crypto/src/crypto/signers/EcGost3410_2012Signer.cs | 151 | ||||
-rw-r--r-- | crypto/src/crypto/signers/GOST3410DigestSigner.cs | 237 | ||||
-rw-r--r-- | crypto/src/pkcs/PrivateKeyInfoFactory.cs | 44 | ||||
-rw-r--r-- | crypto/src/security/PrivateKeyFactory.cs | 162 | ||||
-rw-r--r-- | crypto/src/security/PublicKeyFactory.cs | 36 | ||||
-rw-r--r-- | crypto/src/util/BigIntegers.cs | 11 | ||||
-rw-r--r-- | crypto/src/x509/SubjectPublicKeyInfoFactory.cs | 66 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/ECGOST3410_2012Test.cs | 597 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/EGOST3410_2012SignatureTest.cs | 187 |
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 |