Bouncy Castle Sign and Verify SHA256 Certificate With C#
Bouncy Castle doesn't support XML formats at all. Unless your use-case strictly requires it, you'll find it much easier going just to use Base64 encodings, with certificates (X.509) and private keys (PKCS#8) stored in PEM format. These are all string formats, so should be usable with JSON directly.
There are other problems in the code samples: signing should use the private key, signatures shouldn't be treated as ASCII strings, possibly your messages are actually UTF8. I would expect the inner sign/verify routines to perhaps look like this:
public string SignData(string msg, ECPrivateKeyParameters privKey)
{
try
{
byte[] msgBytes = Encoding.UTF8.GetBytes(msg);
ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
signer.Init(true, privKey);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
byte[] sigBytes = signer.GenerateSignature();
return Convert.ToBase64String(sigBytes);
}
catch (Exception exc)
{
Console.WriteLine("Signing Failed: " + exc.ToString());
return null;
}
}
public bool VerifySignature(ECPublicKeyParameters pubKey, string signature, string msg)
{
try
{
byte[] msgBytes = Encoding.UTF8.GetBytes(msg);
byte[] sigBytes = Convert.FromBase64String(signature);
ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
signer.Init(false, pubKey);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(sigBytes);
}
catch (Exception exc)
{
Console.WriteLine("Verification failed with the error: " + exc.ToString());
return false;
}
}
A further issue is that I think .NET didn't get ECDSA support until .NET 3.5, in any case there's no ECDsa class in .NET 1.1 (which is BC's target for the upcoming 1.8 release - we will be "modernising" after that), so DotNetUtilities doesn't have support for ECDSA. However, we can export to PKCS#12 and import to BC. An example program:
public void Program()
{
Console.WriteLine("Attempting to load cert...");
System.Security.Cryptography.X509Certificates.X509Certificate2 thisCert = LoadCertificate();
Console.WriteLine(thisCert.IssuerName.Name);
Console.WriteLine("Signing the text - Mary had a nuclear bomb");
byte[] pkcs12Bytes = thisCert.Export(X509ContentType.Pkcs12, "dummy");
Pkcs12Store pkcs12 = new Pkcs12StoreBuilder().Build();
pkcs12.Load(new MemoryStream(pkcs12Bytes, false), "dummy".ToCharArray());
ECPrivateKeyParameters privKey = null;
foreach (string alias in pkcs12.Aliases)
{
if (pkcs12.IsKeyEntry(alias))
{
privKey = (ECPrivateKeyParameters)pkcs12.GetKey(alias).Key;
break;
}
}
string signature = SignData("Mary had a nuclear bomb", privKey);
Console.WriteLine("Signature: " + signature);
Console.WriteLine("Verifying Signature");
var bcCert = DotNetUtilities.FromX509Certificate(thisCert);
if (VerifySignature((ECPublicKeyParameters)bcCert.GetPublicKey(), signature, "Mary had a nuclear bomb."))
Console.WriteLine("Valid Signature!");
else
Console.WriteLine("Signature NOT valid!");
}
I haven't really tested any of the above code, but it should give you something to go on. Note that BC has key and certificate generators too, so you could choose to use BC for everything (except XML!), and export/import to/from .NET land only where necessary.
Thanks to Petters answer I wanted to add code to verify the signature with RSA algorithm.
public bool VerifySignature(AsymmetricKeyParameter pubKey, string signature, string msg)
{
try
{
byte[] msgBytes = Encoding.UTF8.GetBytes(msg);
byte[] sigBytes = Convert.FromBase64String(signature);
ISigner signer = SignerUtilities.GetSigner("SHA-256withRSA");
signer.Init(false, pubKey);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(sigBytes);
}
catch (Exception exc)
{
Console.WriteLine("Verification failed with the error: " + exc.ToString());
return false;
}
}