1

To generate a private and public key with OpenSSL I have run

openssl ecparam -genkey -name secp256k1 -out private-key.pem
openssl ec -in private-key.pem -out public-key.pem -pubout

I upload the public key to the remote server. Then import the private-key.pem to a .Net Framework (it has to be .Net Framework) C# service to use it to sign an API payload:

public string LoadFromCng(byte[] request, string privateKeyFile)
{
    CngKey cng = CngKey.Open(privateKeyFile);

    // Sign the request body with the private key.
    ECDsaCng dsa = new ECDsaCng(cng);
    byte[] signedRequest = dsa.SignData(request, HashAlgorithmName.SHA256);
    return Convert.ToBase64String(signedRequest);
}

With privateKeyFile = private-key.pem the above code gives Keyset does not exist

If I use mkcert and run mkcert -ecdsa -pkcs12 private-key.pem it generates a PKCS#12 key called private-key.pem.p12 and then:

public string LoadFromX509(byte[] request, string privateKeyFile)
{
    var cert = new X509Certificate2(privateKeyFile, "changeit");
    var key = cert.GetECDsaPrivateKey();
    byte[] signedRequest = key.SignData(request, HashAlgorithmName.SHA256);
    return Convert.ToBase64String(signedRequest);
}

With privateKeyFile = private-key.pem.p12 the above code appears to sign the request, but the API response is The remote server returned an error: (400) Bad Request which means the API provider can't decode the payload from the public key.

I get the same 400 error when going through the cheat sheet here and creating an X509 pfx certificate.

openssl req -new -x509 -key private-key.pem -out cert.pem -days 360
openssl pkcs12 -export -inkey private-key.pem -in cert.pem -out cert.pfx

The method above appears to sign the payload but the provider responds with a 400.

The suggestions here and here and here and here and others have not worked.

I can't use Net Core or NET 5 so this doesn't work either. The ImportPkcs8PrivateKey method is not available in Net Framework.

If I try and use Bouncy Castle per here I get Unable to cast object of type 'Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters' to type 'Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters'

Topaco
  • 40,594
  • 4
  • 35
  • 62
rupweb
  • 3,052
  • 1
  • 30
  • 57
  • 1
    One problem is that we don't know exactly what the server expects. Which server are you trying to connect to? Where are the protocol specifications? Without that you're firing shots in the blind. You seem to be able to sign, so the problem must exist somewhere else. – Maarten Bodewes Sep 12 '21 at 11:23

1 Answers1

1

The first OpenSSL statement creates an EC parameter file private-key.pem, which contains, among others, a PEM encoded private EC key in SEC1 format.

With .NET Framework the easiest way is to use BouncyCastle for key import. BouncyCastle also supports the ASN.1/DER format and the IEEE P1363 (r|s) format for EC signatures.

The following code imports a PEM encoded private EC key in SEC1 format and signs a message.

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
...
string pkcs8 =  @"-----BEGIN EC PRIVATE KEY-----
                MHQCAQEEIMmN/YG6BtIqm9eAcYtKdcbJosNKbB76vGMTSltPLNiioAcGBSuBBAAK
                oUQDQgAESGnGxuBPdrwv1TkJEorsaNk74+ZFh2jzww2SpLTqQqkvOf5IP6fuODS/
                hzztSBpsBpX9LUZh8TYHX0HRMagkaA==
                -----END EC PRIVATE KEY-----";

TextReader privateKeyTextReader = new StringReader(pkcs8);
AsymmetricCipherKeyPair privateKeyParams = (AsymmetricCipherKeyPair)new PemReader(privateKeyTextReader).ReadObject();

byte[] message = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog");
ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA"); // ASN.1/DER format
//ISigner signer = SignerUtilities.GetSigner("SHA-256withPLAIN-ECDSA"); // r|s format
signer.Init(true, privateKeyParams.Private);
signer.BlockUpdate(message, 0, message.Length);
byte[] signature = signer.GenerateSignature();
Console.WriteLine(Hex.ToHexString(signature)); // 3046022100967c2e890d933c75468dceaf61152add41f143568dcb967583e1b307a0b495e30221008f6837c0d9cc01fc7bfe54ed5b6267fd3e64c2d3ff771e72762f24c20071c454
Topaco
  • 40,594
  • 4
  • 35
  • 62