I am the author of a .NET library that allows developers to process data provided by a 3rd party. Among the many features my library provides is the ability to validate that received data was indeed signed by the 3rd party in question. The 3rd party provides the following information:
- a string containing base64 encoded DER signature
- a string containing base64 encoded secp256r1/NIST P-256 public key
- a array of bytes containing the data that was encoded by the 3rd party using the private key
The developer expects my library to return a Boolean value indicating whether the data is legitimate or not. I was able to figure out how to convert the signature to Microsoft CNG supported format thanks to this StackOverflow question and, similarly, I figured out how to convert the public key into Microsoft CNG supported format thanks to this other StackOverflow question. I put it all together in the following C# code snippet:
// Convert the signature and public key provided by the 3rd party into formats usable by the .net crypto classes
var signatureBytes = Convert.FromBase64String(signature);
var sig = ConvertECDSASignature.LightweightConvertSignatureFromX9_62ToISO7816_8(256, signatureBytes);
var cngBlob = Utils.ConvertSecp256R1PublicKeyToEccPublicBlob(publicKey);
// Verify the signature
var cngKey = CngKey.Import(cngBlob, CngKeyBlobFormat.EccPublicBlob);
var eCDsaCng = new ECDsaCng(cngKey);
var verified = eCDsaCng.VerifyData(data, sig);
This has been working perfectly until a developer recently complained about System.PlatformNotSupportedException
on Linux/Ubuntu machines. After a quick research, I found out that ECDsaCng is Windows-specific and I should be using ECDsa which is cross-platform.
So I came up with the following code which is no only cross-platform but also is much simpler that my original code because I no longer need to convert the signature and public key to different formats:
var signatureBytes = Convert.FromBase64String(signature);
var publicKeyBytes = Convert.FromBase64String(publicKey);
// Verify the signature
var eCDsa = ECDsa.Create();
eCDsa.ImportSubjectPublicKeyInfo(publicKeyBytes, out _);
var verified = eCDsa.VerifyData(data, signatureBytes, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence);
The only caveat is that Microsoft introduced the ImportSubjectPublicKeyInfo
method in the ECDsa class in more recent versions of the .NET framework (I could be wrong but I believe it was introduced in .NET core 3.1) and my library targets netstandard2.0
so it can be used by developers who are not necessarily using the latest .NET.
So, all this to say: is there a way to validate the data using the provided signature and public key in a way that is cross-platform AND usable in netstandard2.0?