Skip to content

Instantly share code, notes, and snippets.

@heaths
Last active January 13, 2021 01:16
Show Gist options
  • Save heaths/551edd53e37c3ad85e62a02dfa56a8ad to your computer and use it in GitHub Desktop.
Save heaths/551edd53e37c3ad85e62a02dfa56a8ad to your computer and use it in GitHub Desktop.
Example of using EC keys to sign remotely using Key Vault and verify locally
// #r "nuget:Azure.Identity,1.3.0"
// #r "nuget:Azure.Security.KeyVault.Keys,4.1.0"
// #r "nuget:System.CommandLine.DragonFruit,0.3.0-alpha.20574.7"
using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Azure;
using Azure.Identity;
using Azure.Security.KeyVault.Keys;
using Azure.Security.KeyVault.Keys.Cryptography;
class Program
{
enum Algorithm
{
ES256K,
ECDSA256,
}
static async Task Main(string vaultName, string name, Algorithm algorithm = default)
{
if (!Uri.TryCreate($"https://{vaultName}.vault.azure.net", UriKind.Absolute, out Uri vaultUri))
{
throw new ArgumentException($"Invalid vault name: {vaultName}");
}
DefaultAzureCredential credential = new DefaultAzureCredential();
KeyClient keyClient = new KeyClient(vaultUri, credential);
Response<KeyVaultKey> keyResponse = await keyClient.GetKeyAsync(name);
KeyVaultKey key = keyResponse.Value;
Console.WriteLine($"Retrieved EC key with curve name: {key.Key.CurveName}");
byte[] plaintext = Encoding.UTF8.GetBytes("plaintext");
Console.WriteLine("Signing 'plaintext' message in Key Vault...");
byte[] digest = ComputeHash(plaintext);
Console.WriteLine($"Digest: {Convert.ToBase64String(digest)}");
CryptographyClient cryptographyClient = new CryptographyClient(key.Id, credential);
// Use ECDSA256 for SECP256K1 keys.
// Since the curve name is not supported, we need to sign the digest (Sign/Async) instead of the data (SignData/Async).
SignatureAlgorithm signAlgorithm = new SignatureAlgorithm(algorithm.ToString());
SignResult result = await cryptographyClient.SignAsync(signAlgorithm, digest);
Console.WriteLine($"Signature hash: {Convert.ToBase64String(result.Signature)}");
Console.WriteLine("Verifying signed 'plaintext' locally...");
// To get the ECDsa we need to convert the curve name.
JsonWebKey jwk = key.Key;
if (jwk.CurveName == "SECP256K1")
{
jwk.CurveName = KeyCurveName.P256K;
}
using ECDsa ec = key.Key.ToECDsa();
string isValid = ec.VerifyData(plaintext, result.Signature, HashAlgorithmName.SHA256) ? "valid" : "invalid";
Console.WriteLine($"Signature: {isValid}");
}
static byte[] ComputeHash(byte[] data)
{
using HashAlgorithm hash = SHA256.Create();
return hash.ComputeHash(data);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment