I have this snippet on my local machine (dotnet 8.0) which is working fine.
using System.Security.Cryptography;
using (ECDsa ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256))
{
string input = "some base64 encoded data";
byte[] data_bytes = Convert.FromBase64String(input);
byte[] hash = SHA256.Create().ComputeHash(data_bytes);
byte[] publicKeyBytes = ecdsa.ExportSubjectPublicKeyInfo();
Console.WriteLine($"Public Key:\n{Convert.ToBase64String(publicKeyBytes)}\n");
// Sign the hash using the Rfc3279DerSequence format
byte[] signature_der = ecdsa.SignHash(hash, DSASignatureFormat.Rfc3279DerSequence);
bool isValid_der = ecdsa.VerifyHash(hash, signature_der, DSASignatureFormat.Rfc3279DerSequence);
Console.WriteLine($"Signature valid: {isValid_der}\n");
string signature_b64_der = Convert.ToBase64String(signature_der);
Console.WriteLine($"DER Signature:\n{signature_b64_der}\n");
// Sign the hash using the IeeeP1363FixedFieldConcatenation format
byte[] signature_ieee = ecdsa.SignHash(hash, DSASignatureFormat.IeeeP1363FixedFieldConcatenation);
bool isValid_ieee = ecdsa.VerifyHash(hash, signature_ieee, DSASignatureFormat.IeeeP1363FixedFieldConcatenation);
Console.WriteLine($"Signature valid: {isValid_ieee}\n");
string signature_b64_ieee = Convert.ToBase64String(signature_ieee);
Console.WriteLine($"IEEE Signature:\n{signature_b64_ieee}\n");
}
I want to implement the same logic, but this time I want to use Azure Key vault REST APIs to sign and verify same kind of data. I aimed for this approach so I can rotate keys regularly.
The signature return by Azure Key Vault seems to be returned as IEEE P1363 format only and I did not find a way to return the RFC 3279 DER Sequence format.
My question: Is there a way to obtain from Azure Key Vault signature in a different format, and of course to be able to verify that signature?
I've tried to use the CryptographyClient.SignAsync, but again it returns only the IEEE P1363 format, and I want the other format too (if possible).
I generated EC key type with P-256 Elliptic curve:
ConvertIeeeP1363ToDer
function to convert it to DER.ECDsa.VerifyHash
to verify the DER-formatted signature.Make use of below code:
public class AzureKeyVaultECDSASignature
{
private static string keyVaultUrl = "https://rrruuukkk.vault.azure.net/";
private static string keyName = "myECDSAKey";
public static async Task Main(string[] args)
{
var client = new KeyClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
var key = await client.GetKeyAsync(keyName);
var keyId = key.Value.Id;
var cryptoClient = new CryptographyClient(keyId, new DefaultAzureCredential());
string message = "Hello, Azure Key Vault!";
byte[] messageHash = SHA256.HashData(Encoding.UTF8.GetBytes(message));
byte[] ieeeSignature = await SignMessageAsync(cryptoClient, messageHash);
Console.WriteLine("IEEE P1363 Signature (Base64): " + Convert.ToBase64String(ieeeSignature));
byte[] derSignature = ConvertIeeeP1363ToDer(ieeeSignature);
Console.WriteLine("DER Signature (Base64): " + Convert.ToBase64String(derSignature));
bool isValid = await VerifySignatureAsync(messageHash, derSignature);
Console.WriteLine($"Signature valid in DER format: {isValid}");
}
private static async Task<byte[]> SignMessageAsync(CryptographyClient cryptoClient, byte[] messageHash)
{
var signResult = await cryptoClient.SignAsync(SignatureAlgorithm.ES256, messageHash);
return signResult.Signature;
}
private static async Task<bool> VerifySignatureAsync(byte[] hash, byte[] derSignature)
{
var client = new KeyClient(new Uri(keyVaultUrl), new DefaultAzureCredential());
var key = await client.GetKeyAsync(keyName);
var jsonWebKey = key.Value.Key;
if (jsonWebKey.X != null && jsonWebKey.Y != null)
{
using (ECDsa ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256))
{
ecdsa.ImportParameters(new ECParameters
{
Curve = ECCurve.NamedCurves.nistP256,
Q = new ECPoint
{
X = jsonWebKey.X,
Y = jsonWebKey.Y
}
});
// Verify the signature
return ecdsa.VerifyHash(hash, derSignature, DSASignatureFormat.Rfc3279DerSequence);
}
}
throw new InvalidOperationException("Invalid public key in the key vault.");
}
// Method to convert IEEE P1363 signature to DER sequence format
private static byte[] ConvertIeeeP1363ToDer(byte[] ieeeSignature)
{
if (ieeeSignature.Length % 2 != 0)
{
throw new ArgumentException("Invalid IEEE P1363 signature length");
}
int halfLength = ieeeSignature.Length / 2;
byte[] r = new byte[halfLength];
byte[] s = new byte[halfLength];
Array.Copy(ieeeSignature, 0, r, 0, halfLength);
Array.Copy(ieeeSignature, halfLength, s, 0, halfLength);
var writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
writer.WriteInteger(r);
writer.WriteInteger(s);
writer.PopSequence();
return writer.Encode();
}
}