Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recreating Keys (ECPublicKeyParameters) in C# with BouncyCastle

I generate an AsymmetricCipherKeyPair as follows:

string curveName = "P-521";
X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
ECDomainParameters ecSpec = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDH");
g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();

My intention was to extract the public and private keys and then rebuild the keys later. I first extracted the keys as follows:

byte[] privateKey = ((ECPrivateKeyParameters)aKeyPair.Private).D.ToByteArray();
byte[] publicKey = ((ECPublicKeyParameters)aKeyPair.Public).Q.GetEncoded();

How do I recreate the public and private key parameters so that I can use them? In this example, I do recreate the private key and then sign the data byte array.

public static byte[] SignData(byte[] data, byte[] privateKey)
{
    string curveName = "P-521";
    X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
    ECDomainParameters ecSpec = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
    ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
    BigInteger biPrivateKey = new BigInteger(privateKey);
    ECPrivateKeyParameters keyParameters = new ECPrivateKeyParameters(biPrivateKey, ecSpec);
    signer.Init(true, keyParameters);
    signer.BlockUpdate(data, 0, data.Length);
    return signer.GenerateSignature();
}

Although it feels like a real hack, it works just fine. How can I do this with the Public Key? I set the variable xxx to (ECPublicKeyParameters)aKeyPair.Public and I can use the code below to verify the signature. Note that I could use xxx directly, but the point is to serialize xxx out and then back in, so, this code actually does convert the xxx variable and creates a new one, which is stored in xx. I then use xx to verify (which shows that I can round trip the key).

var xx = PublicKeyFactory.CreateKey(Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(xxx).GetDerEncoded());
ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
signer.Init(false, xx);
signer.BlockUpdate(data, 0, data.Length);
return signer.VerifySignature(signature);

I had hoped that I could create the key (xx) from Q.GetEncoded() similar to how I did it for the private key.

Is there a better way to rebuild the private key? also using an ASN.1 encoding? If so, perhaps I should use that instead.

like image 591
Andrew Avatar asked Jul 03 '13 04:07

Andrew


1 Answers

I can do this as follows:

string curveName = "P-521";
X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
FpCurve c = (FpCurve)ecP.Curve;
ECFieldElement x = new FpFieldElement(c.Q, xxx.Q.X.ToBigInteger());
ECFieldElement y = new FpFieldElement(c.Q, xxx.Q.Y.ToBigInteger());
ECPoint q = new FpPoint(c, x, y);
ECPublicKeyParameters xxpk = new ECPublicKeyParameters("ECDH", q, SecObjectIdentifiers.SecP521r1);

Then, I can use xxpk to verify the signature.

Disclaimer: I do not claim that this is the best way to do this, just that it works!

like image 115
Andrew Avatar answered Nov 09 '22 00:11

Andrew