Last active
January 13, 2021 01:16
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// #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