From 9dfd5af9b7ed63a33513599ae3e874c85dea15c3 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 6 Nov 2022 22:44:18 +0700 Subject: GOST 2012 private key reading - see https://github.com/bcgit/bc-csharp/issues/365 --- crypto/src/security/PrivateKeyFactory.cs | 96 ++++++++++++++++++++++++++---- crypto/test/src/openssl/test/ReaderTest.cs | 18 ++++++ 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs index c4fabae2d..e66224a67 100644 --- a/crypto/src/security/PrivateKeyFactory.cs +++ b/crypto/src/security/PrivateKeyFactory.cs @@ -130,29 +130,99 @@ namespace Org.BouncyCastle.Security 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)) + else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001) || + algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512) || + algOid.Equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256)) { - Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance( - algID.Parameters.ToAsn1Object()); + Asn1Object p = algID.Parameters.ToAsn1Object(); + Gost3410PublicKeyAlgParameters gostParams = Gost3410PublicKeyAlgParameters.GetInstance(p); - X9ECParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + ECGost3410Parameters ecSpec; + BigInteger d; - if (ecP == null) - throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key"); + if (p is Asn1Sequence seq && (seq.Count == 2 || seq.Count == 3)) + { + X9ECParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet); + if (ecP == null) + throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key"); - Asn1Object privKey = keyInfo.ParsePrivateKey(); - ECPrivateKeyStructure ec; + ecSpec = new ECGost3410Parameters( + new ECNamedDomainParameters(gostParams.PublicKeyParamSet, ecP), + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet); - if (privKey is DerInteger) - { - ec = new ECPrivateKeyStructure(ecP.N.BitLength, ((DerInteger)privKey).PositiveValue); + Asn1OctetString privEnc = keyInfo.PrivateKeyData; + if (privEnc.GetOctets().Length == 32 || privEnc.GetOctets().Length == 64) + { + d = new BigInteger(1, Arrays.Reverse(privEnc.GetOctets())); + } + else + { + Asn1Object privKey = keyInfo.ParsePrivateKey(); + if (privKey is DerInteger derInteger) + { + d = derInteger.PositiveValue; + } + else + { + byte[] dVal = Arrays.Reverse(Asn1OctetString.GetInstance(privKey).GetOctets()); + d = new BigInteger(1, dVal); + } + } } else { - ec = ECPrivateKeyStructure.GetInstance(privKey); + X962Parameters x962Parameters = X962Parameters.GetInstance(p); + + if (x962Parameters.IsNamedCurve) + { + DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(x962Parameters.Parameters); + X9ECParameters ecP = ECNamedCurveTable.GetByOid(oid); + if (ecP == null) + throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key"); + + ecSpec = new ECGost3410Parameters( + new ECNamedDomainParameters(oid, ecP), + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet); + } + else if (x962Parameters.IsImplicitlyCA) + { + ecSpec = null; + } + else + { + X9ECParameters ecP = X9ECParameters.GetInstance(x962Parameters.Parameters); + + ecSpec = new ECGost3410Parameters( + new ECNamedDomainParameters(algOid, ecP), + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet); + } + + Asn1Object privKey = keyInfo.ParsePrivateKey(); + if (privKey is DerInteger derD) + { + d = derD.Value; + } + else + { + ECPrivateKeyStructure ec = ECPrivateKeyStructure.GetInstance(privKey); + + d = ec.GetKey(); + } } - return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet); + return new ECPrivateKeyParameters( + d, + new ECGost3410Parameters( + ecSpec, + gostParams.PublicKeyParamSet, + gostParams.DigestParamSet, + gostParams.EncryptionParamSet)); } else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94)) { diff --git a/crypto/test/src/openssl/test/ReaderTest.cs b/crypto/test/src/openssl/test/ReaderTest.cs index 78b06abc2..8cb66d6a6 100644 --- a/crypto/test/src/openssl/test/ReaderTest.cs +++ b/crypto/test/src/openssl/test/ReaderTest.cs @@ -3,6 +3,7 @@ using System.IO; using NUnit.Framework; +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; @@ -42,6 +43,23 @@ namespace Org.BouncyCastle.OpenSsl.Tests get { return "PEMReaderTest"; } } + [Test] + public void TestGost3410_2012() + { + string data = + "-----BEGIN PRIVATE KEY-----" + + "MEMCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIIBidanaO5G6Go8A" + + "thlDjR9rk4hij/PpjAQvXJr+zTqz" + + "-----END PRIVATE KEY-----"; + + using (var textReader = new StringReader(data)) + { + var pemReader = new PemReader(textReader); + var pemObj = pemReader.ReadPemObject(); + PrivateKeyFactory.CreateKey(pemObj.Content); + } + } + public override void PerformTest() { IPasswordFinder pGet = new Password("secret".ToCharArray()); -- cgit 1.4.1