dotdev
dotdev

Reputation: 3

Azure Managed HSM: Decrypt in C# using encryption result from Azure CLI

I'm encrypting a string using Azure CLI:

az keyvault key encrypt --id "https://myhsmtest.managedhsm.azure.net/keys/aes256/1234aed127f8009e15d6c3a883b91f21" --algorithm A256GCM --value "123" --data-type plaintext

This returns me a JSON:

{
  "aad": null,
  "algorithm": "A256GCM",
  "iv": "8f7f424c8548bac26c947bfd",
  "kid": "https://myhsmtest.managedhsm.azure.net/keys/aes256/1234aed127f8009e15d6c3a883b91f21",
  "result": "PtLm",
  "tag": "e96de8eee3e194529095ef196f54cef0"
}

Now I'd like to decrypt this in C#:

var json =
      "{\n  \"aad\": null,\n  \"algorithm\": \"A256GCM\",\n  \"iv\": \"8f7f424c8548bac26c947bfd\",\n  \"kid\": \"https://myhsmtest.managedhsm.azure.net/keys/aes256/1234aed127f8009e15d6c3a883b91f21\",\n  \"result\": \"PtLm\",\n  \"tag\": \"e96de8eee3e194529095ef196f54cef0\"\n}";
var jsonDocument = JsonDocument.Parse(json);
var cipherText = jsonDocument.RootElement.GetProperty("result").GetString();
var iv = jsonDocument.RootElement.GetProperty("iv").GetString();
var tag = jsonDocument.RootElement.GetProperty("tag").GetString();

var cipherTextBytes = Convert.FromBase64String(cipherText);
var ivBytes = Convert.FromBase64String(iv);
var tagBytes = Convert.FromBase64String(tag);

var keyVaultUrl = "https://myhsmtest.managedhsm.azure.net";
var credential = new DefaultAzureCredential();
var client = new KeyClient(vaultUri: new Uri(keyVaultUrl), credential);
var cryptographyClient = client.GetCryptographyClient("aes256", "1234aed127f8009e15d6c3a883b91f21");

DecryptParameters decryptParameters = DecryptParameters.A256GcmParameters(ciphertext: cipherTextBytes, iv: ivBytes, authenticationTag: tagBytes);
var result = cryptographyClient.Decrypt(decryptParameters);

It fails with the following error:

Azure.RequestFailedException: HSM Error: Invalid input data/params (Activity ID: e947a2ec-9f6d-11ef-846b-000d3a278b83)
Status: 400 (Bad Request)
ErrorCode: BadParameter

Content:
{"error":{"code":"BadParameter","message":"HSM Error: Invalid input data/params (Activity ID: e947a2ec-9f6d-11ef-846b-000d3a278b83)"}}

Headers:
x-ms-server-latency: REDACTED
Cache-Control: no-cache
X-Content-Type-Options: REDACTED
x-ms-request-id: e947a2ec-9f6d-11ef-846b-000d3a278b83
Strict-Transport-Security: REDACTED
Content-Security-Policy: REDACTED
X-Frame-Options: REDACTED
Content-Type: application/json; charset=utf-8
Content-Length: 134

   at Azure.Security.KeyVault.KeyVaultPipeline.SendRequest(Request request, CancellationToken cancellationToken)
   at Azure.Security.KeyVault.KeyVaultPipeline.SendRequest[TContent,TResult](RequestMethod method, TContent content, Func`1 resultFactory, CancellationToken cancellationToken, String[] path)
   at Azure.Security.KeyVault.Keys.Cryptography.RemoteCryptographyClient.Decrypt(DecryptParameters parameters, CancellationToken cancellationToken)
   at Azure.Security.KeyVault.Keys.Cryptography.RemoteCryptographyClient.Azure.Security.KeyVault.Keys.Cryptography.ICryptographyProvider.Decrypt(DecryptParameters parameters, CancellationToken cancellationToken)
   at Azure.Security.KeyVault.Keys.Cryptography.CryptographyClient.Decrypt(DecryptParameters decryptParameters, CancellationToken cancellationToken)
...

If I encrypt a string in C# and decrypt it right away using EncryptResult.Ciphertext, EncryptResult.Iv and EncryptResult.AuthenticationTag, it works well. But when I'm using JSON from CLI in C# - I have this error.

If I use values from this JSON in CLI (az keyvault key decrypt), it also works well.

So I suppose that I'm not doing decoding of result, iv and tag from JSON to bytes[] well, but I don't get what is exactly wrong.

Upvotes: 0

Views: 92

Answers (1)

Venkatesan
Venkatesan

Reputation: 10455

Azure Managed HSM: Decrypt in C# using encryption result from Azure CLI.

In my environment, I encrypted the azure Managed HSM key same as your Azure CLI command:

az keyvault key encrypt --id "https://xxx.managedhsm.azure.net/keys/Venkatesan326/xxxxxx" --algorithm A256GCM --value "this is plaintext" --data-type plaintext
This command is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
{
  "aad": null,
  "algorithm": "A256GCM",
  "iv": "40f91e6934c5af97b6d18ec6",
  "kid": "https://xxx.managedhsm.azure.net/keys/Venkatesan326/xxx",
  "result": "xxxx=",
  "tag": "ac077axxxxbd15af346"
}

enter image description here

I agree with Topaco's comment it should be in hexa encoded. you can use the below code which decrypt the encryption result from azure cli using C#.

Code:

using Azure.Identity;
using Azure.Security.KeyVault.Keys;
using Azure.Security.KeyVault.Keys.Cryptography;
using System;
using System.Text;

public class AzureHSMDecryptionExample
{
    public static void Main(string[] args)
    {
        // Updated JSON response from Azure CLI (adjust values accordingly)
        var json =
            "{\n  \"aad\": null,\n  \"algorithm\": \"A256GCM\",\n  \"iv\": \"4xxxxx\",\n  \"kid\": \"https://xxxx.managedhsm.azure.net/keys/Venkatesan326/xxxx\",\n  \"result\": \"xxxx\",\n  \"tag\": \"xxxx\"\n}";

        // Parse the JSON response
        var jsonDocument = System.Text.Json.JsonDocument.Parse(json);
        var cipherText = jsonDocument.RootElement.GetProperty("result").GetString();
        var iv = jsonDocument.RootElement.GetProperty("iv").GetString();
        var tag = jsonDocument.RootElement.GetProperty("tag").GetString();

        byte[] ivBytes = HexStringToByteArray(iv);
        byte[] tagBytes = HexStringToByteArray(tag);

        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        // KeyVault URI and credentials
        var keyVaultUrl = "https://xxx.managedhsm.azure.net"; 
        var credential = new DefaultAzureCredential();
        var client = new KeyClient(new Uri(keyVaultUrl), credential);
        var cryptographyClient = client.GetCryptographyClient("Venkatesan326", "xxxx");

        // Create the decrypt parameters using the A256GcmParameters method
        var decryptParameters = DecryptParameters.A256GcmParameters(
            ciphertext: cipherTextBytes,
            iv: ivBytes,
            authenticationTag: tagBytes
        );

        // Perform decryption
        try
        {
            var result = cryptographyClient.Decrypt(decryptParameters);
            string decryptedValue = Encoding.UTF8.GetString(result.Plaintext);
            Console.WriteLine("Decrypted Value: " + decryptedValue);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Decryption failed: {ex.Message}");
        }
    }
    
    public static byte[] HexStringToByteArray(string hex)
    {
        int length = hex.Length / 2;
        byte[] bytes = new byte[length];
        for (int i = 0; i < length; i++)
        {
            bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
        }
        return bytes;
    }
}

Output:

Decrypted Value: this is plaintext

enter image description here

Upvotes: 0

Related Questions