diff options
author | Megan Woods <megan@flygfisk.com> | 2019-01-14 00:17:24 +1100 |
---|---|---|
committer | Megan Woods <megan@flygfisk.com> | 2019-01-14 00:17:24 +1100 |
commit | 785d36daf1d125b3fba16e1d92719e2a0f67698e (patch) | |
tree | 2dfb561f0be1a55b87f135997d5d3c1e552c05da /crypto/src | |
parent | Fix some comments (diff) | |
download | BouncyCastle.NET-ed25519-785d36daf1d125b3fba16e1d92719e2a0f67698e.tar.xz |
Added ECGOST3410_2012Signer
Updated encoding of SubjectPublicKeyInfo and PrivateKeyInfo
Diffstat (limited to 'crypto/src')
-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 |
10 files changed, 678 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]; + } + } } } |