diff --git a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
index 404277ba6..c5be7a315 100644
--- a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
+++ b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -29,14 +29,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
}
- public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Object privateKey)
+ public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Encodable privateKey)
: this(algID, privateKey, null)
{
}
public PrivateKeyInfo(
AlgorithmIdentifier algID,
- Asn1Object privateKey,
+ Asn1Encodable privateKey,
Asn1Set attributes)
{
this.algID = algID;
diff --git a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
index 8d805fa30..32e020c0b 100644
--- a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
+++ b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -23,6 +23,7 @@ namespace Org.BouncyCastle.Asn1.Sec
return new ECPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
}
+ [Obsolete("Use 'GetInstance' instead")]
public ECPrivateKeyStructure(
Asn1Sequence seq)
{
@@ -32,6 +33,7 @@ namespace Org.BouncyCastle.Asn1.Sec
this.seq = seq;
}
+ [Obsolete("Use constructor which takes 'orderBitLength' instead, to guarantee correct encoding")]
public ECPrivateKeyStructure(
BigInteger key)
{
@@ -44,12 +46,30 @@ namespace Org.BouncyCastle.Asn1.Sec
}
public ECPrivateKeyStructure(
+ int orderBitLength,
+ BigInteger key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (orderBitLength < key.BitLength)
+ throw new ArgumentException("must be >= key bitlength", "orderBitLength");
+
+ byte[] bytes = BigIntegers.AsUnsignedByteArray((orderBitLength + 7) / 8, key);
+
+ this.seq = new DerSequence(
+ new DerInteger(1),
+ new DerOctetString(bytes));
+ }
+
+ [Obsolete("Use constructor which takes 'orderBitLength' instead, to guarantee correct encoding")]
+ public ECPrivateKeyStructure(
BigInteger key,
Asn1Encodable parameters)
: this(key, null, parameters)
{
}
+ [Obsolete("Use constructor which takes 'orderBitLength' instead, to guarantee correct encoding")]
public ECPrivateKeyStructure(
BigInteger key,
DerBitString publicKey,
@@ -75,6 +95,44 @@ namespace Org.BouncyCastle.Asn1.Sec
this.seq = new DerSequence(v);
}
+ public ECPrivateKeyStructure(
+ int orderBitLength,
+ BigInteger key,
+ Asn1Encodable parameters)
+ : this(orderBitLength, key, null, parameters)
+ {
+ }
+
+ public ECPrivateKeyStructure(
+ int orderBitLength,
+ BigInteger key,
+ DerBitString publicKey,
+ Asn1Encodable parameters)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (orderBitLength < key.BitLength)
+ throw new ArgumentException("must be >= key bitlength", "orderBitLength");
+
+ byte[] bytes = BigIntegers.AsUnsignedByteArray((orderBitLength + 7) / 8, key);
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger(1),
+ new DerOctetString(bytes));
+
+ if (parameters != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, parameters));
+ }
+
+ if (publicKey != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, publicKey));
+ }
+
+ this.seq = new DerSequence(v);
+ }
+
public virtual BigInteger GetKey()
{
Asn1OctetString octs = (Asn1OctetString) seq[1];
diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs
index 987f4471c..9a5f99b1a 100644
--- a/crypto/src/openssl/PEMReader.cs
+++ b/crypto/src/openssl/PEMReader.cs
@@ -311,7 +311,7 @@ namespace Org.BouncyCastle.OpenSsl
case "EC":
{
- ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq);
+ ECPrivateKeyStructure pKey = ECPrivateKeyStructure.GetInstance(seq);
AlgorithmIdentifier algId = new AlgorithmIdentifier(
X9ObjectIdentifiers.IdECPublicKey, pKey.GetParameters());
diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
index c6aab4884..aafc4c292 100644
--- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -106,49 +106,46 @@ namespace Org.BouncyCastle.Pkcs
if (key is ECPrivateKeyParameters)
{
- ECPrivateKeyParameters _key = (ECPrivateKeyParameters)key;
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)key;
+ ECDomainParameters dp = priv.Parameters;
+ int orderBitLength = dp.N.BitLength;
+
AlgorithmIdentifier algID;
ECPrivateKeyStructure ec;
- if (_key.AlgorithmName == "ECGOST3410")
+ if (priv.AlgorithmName == "ECGOST3410")
{
- if (_key.PublicKeyParamSet == null)
+ if (priv.PublicKeyParamSet == null)
throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
- _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+ priv.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
- algID = new AlgorithmIdentifier(
- CryptoProObjectIdentifiers.GostR3410x2001,
- gostParams.ToAsn1Object());
+ algID = new AlgorithmIdentifier(CryptoProObjectIdentifiers.GostR3410x2001, gostParams);
// TODO Do we need to pass any parameters here?
- ec = new ECPrivateKeyStructure(_key.D);
+ ec = new ECPrivateKeyStructure(orderBitLength, priv.D);
}
else
{
X962Parameters x962;
- if (_key.PublicKeyParamSet == null)
+ if (priv.PublicKeyParamSet == null)
{
- ECDomainParameters kp = _key.Parameters;
- X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
-
+ X9ECParameters ecP = new X9ECParameters(dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed());
x962 = new X962Parameters(ecP);
}
else
{
- x962 = new X962Parameters(_key.PublicKeyParamSet);
+ x962 = new X962Parameters(priv.PublicKeyParamSet);
}
- Asn1Object x962Object = x962.ToAsn1Object();
-
// TODO Possible to pass the publicKey bitstring here?
- ec = new ECPrivateKeyStructure(_key.D, x962Object);
+ ec = new ECPrivateKeyStructure(orderBitLength, priv.D, x962);
- algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962Object);
+ algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962);
}
- return new PrivateKeyInfo(algID, ec.ToAsn1Object());
+ return new PrivateKeyInfo(algID, ec);
}
if (key is Gost3410PrivateKeyParameters)
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index b9538b33d..8c2ecfdb0 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -117,8 +117,7 @@ namespace Org.BouncyCastle.Security
x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
}
- ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
- Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey()));
+ ECPrivateKeyStructure ec = ECPrivateKeyStructure.GetInstance(keyInfo.ParsePrivateKey());
BigInteger d = ec.GetKey();
if (para.IsNamedCurve)
@@ -134,24 +133,24 @@ namespace Org.BouncyCastle.Security
Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+ if (ecP == null)
+ throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key");
+
Asn1Object privKey = keyInfo.ParsePrivateKey();
ECPrivateKeyStructure ec;
if (privKey is DerInteger)
{
// TODO Do we need to pass any parameters here?
- ec = new ECPrivateKeyStructure(((DerInteger)privKey).Value);
+ ec = new ECPrivateKeyStructure(ecP.N.BitLength, ((DerInteger)privKey).Value);
}
else
{
ec = ECPrivateKeyStructure.GetInstance(privKey);
}
- ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
-
- if (ecP == null)
- throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key");
-
return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet);
}
else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
|