Michael
Michael

Reputation: 3061

CryptographyClient Decrypt throws 'Key does not exist' exception

I'm trying Microsoft docs example to encrypt/decrypt a text using Azure Key Vault SDK.

I created key manually via Azure Portal. Encryption part succeeds, but decrypt throws 'Key does not exist' exception. I can't understand why, because key exists, it has decrypt as a permitted operation and I can confirm that in VS in a debug mode (KeyVaultKey -> KeyOperations lists 'Decrypt').

This is the full code:

    static void Main(string[] args)
    {
        var keyVaultKeyIdentifier = new KeyVaultKeyIdentifier(new Uri("key-url"));
    
        var keyClient = new KeyClient(keyVaultKeyIdentifier.VaultUri, new DefaultAzureCredential());
    
        var keyVaultKey = keyClient.GetKey(keyVaultKeyIdentifier.Name).Value;
    
        var cryptoClient = new CryptographyClient(keyVaultKey.Key);
    
        byte[] plaintext = Encoding.UTF8.GetBytes("A single block of plaintext");
    
        // encrypt the data using the algorithm RSAOAEP
        EncryptResult encryptResult = cryptoClient.Encrypt(EncryptionAlgorithm.RsaOaep, plaintext);
    
        // decrypt the encrypted data. 
        // **Exception is thrown on this line**
        DecryptResult decryptResult = cryptoClient.Decrypt(EncryptionAlgorithm.RsaOaep, encryptResult.Ciphertext);
    }

For the reference the stack trace of an exception:

   at System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, Boolean encrypt)
   at System.Security.Cryptography.RSAImplementation.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, Boolean encrypt)
   at System.Security.Cryptography.RSAImplementation.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding)
   at Azure.Security.KeyVault.Keys.Cryptography.RsaCryptographyProvider.Decrypt(Byte[] data, RSAEncryptionPadding padding)
   at Azure.Security.KeyVault.Keys.Cryptography.RsaCryptographyProvider.Decrypt(DecryptParameters parameters, CancellationToken cancellationToken)
   at Azure.Security.KeyVault.Keys.Cryptography.CryptographyClient.Decrypt(DecryptParameters decryptParameters, CancellationToken cancellationToken)
   at Azure.Security.KeyVault.Keys.Cryptography.CryptographyClient.Decrypt(EncryptionAlgorithm algorithm, Byte[] ciphertext, CancellationToken cancellationToken)
   at DotNetFiveCrypto.Program.Main(String[] args) in C:\Users\mike\Documents\Visual Studio 2019\Projects\DotNetFiveCrypto\Program.cs:line 32

I'm using .NET 5 on Windows 10, referenced SDK packages:

<PackageReference Include="Azure.Identity" Version="1.4.1" />
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.2.0" />

Upvotes: 1

Views: 885

Answers (1)

allant
allant

Reputation: 166

You are instantiating CryptographyClient using the public part of your key - so the SDK creates a local client, which is only capable of encrypting.

Since the private part is never exposed by Key Vault, you need to instantiate CryptographyClient using the Id of your key instead, so that it creates a remote client that delegates both encryption and decryption to Key Vault REST API.

Here's the fix:

static void Main(string[] args)
{
    var keyVaultKeyIdentifier = new KeyVaultKeyIdentifier(new Uri("key-url"));

    var credential = new DefaultAzureCredential();

    var keyClient = new KeyClient(keyVaultKeyIdentifier.VaultUri, credential);

    var keyVaultKey = keyClient.GetKey(keyVaultKeyIdentifier.Name).Value;

    var cryptoClient = new CryptographyClient(keyVaultKey.Id, credential);

    byte[] plaintext = Encoding.UTF8.GetBytes("A single block of plaintext");

    EncryptResult encryptResult = cryptoClient.Encrypt(EncryptionAlgorithm.RsaOaep, plaintext);

    DecryptResult decryptResult = cryptoClient.Decrypt(EncryptionAlgorithm.RsaOaep, encryptResult.Ciphertext);
}

Here's an additional encryption/decryption sample and here the source code where it switches between local and remote clients.

I don't know the use case in question, but you could build a local crypto client for encryption (faster) and use the remote one for decryption (slower).

Upvotes: 3

Related Questions