< Summary

Class:Azure.Security.KeyVault.Keys.Cryptography.CryptographyClient
Assembly:Azure.Security.KeyVault.Keys
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\Cryptography\CryptographyClient.cs
Covered lines:376
Uncovered lines:128
Coverable lines:504
Total lines:1364
Line coverage:74.6% (376 of 504)
Covered branches:121
Total branches:148
Branch coverage:81.7% (121 of 148)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor()-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-92.31%62.5%
.ctor(...)-90.91%50%
.ctor(...)-100%100%
get_RemoteClient()-100%100%
get_KeyId()-0%100%
EncryptAsync()-84.21%100%
Encrypt(...)-84.21%100%
DecryptAsync()-84.21%100%
Decrypt(...)-84.21%100%
WrapKeyAsync()-84.21%100%
WrapKey(...)-84.21%100%
UnwrapKeyAsync()-100%100%
UnwrapKey(...)-84.21%100%
SignAsync()-84.21%100%
Sign(...)-84.21%100%
VerifyAsync()-84.21%100%
Verify(...)-84.21%100%
SignDataAsync()-61.9%66.67%
SignData(...)-61.9%66.67%
SignDataAsync()-61.9%66.67%
SignData(...)-61.9%66.67%
VerifyDataAsync()-61.9%66.67%
VerifyData(...)-61.9%66.67%
VerifyDataAsync()-61.9%66.67%
VerifyData(...)-61.9%66.67%
Azure.Core.Cryptography.IKeyEncryptionKey.WrapKey(...)-0%100%
Azure-Core-Cryptography-IKeyEncryptionKey-WrapKeyAsync()-0%100%
Azure.Core.Cryptography.IKeyEncryptionKey.UnwrapKey(...)-0%0%
Azure-Core-Cryptography-IKeyEncryptionKey-UnwrapKeyAsync()-0%0%
CreateDigest(...)-100%100%
CreateDigest(...)-100%100%
InitializeAsync()-60%75%
Initialize(...)-57.89%75%

File(s)

C:\Git\azure-sdk-for-net\sdk\keyvault\Azure.Security.KeyVault.Keys\src\Cryptography\CryptographyClient.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using Azure.Core;
 5using Azure.Core.Cryptography;
 6using Azure.Core.Pipeline;
 7using System;
 8using System.IO;
 9using System.Runtime.InteropServices;
 10using System.Security.Cryptography;
 11using System.Threading;
 12using System.Threading.Tasks;
 13
 14namespace Azure.Security.KeyVault.Keys.Cryptography
 15{
 16    /// <summary>
 17    /// A client used to perform cryptographic operations with Azure Key Vault keys.
 18    /// </summary>
 19    public class CryptographyClient : IKeyEncryptionKey
 20    {
 21        private readonly Uri _keyId;
 22        private readonly KeyVaultPipeline _pipeline;
 23        private readonly RemoteCryptographyClient _remoteProvider;
 24        private ICryptographyProvider _provider;
 25
 26        /// <summary>
 27        /// Initializes a new instance of the <see cref="CryptographyClient"/> class for mocking.
 28        /// </summary>
 29229        protected CryptographyClient()
 30        {
 29231        }
 32
 33        /// <summary>
 34        /// Initializes a new instance of the <see cref="CryptographyClient"/> class.
 35        /// </summary>
 36        /// <param name="keyId">The <see cref="KeyProperties.Id"/> of the <see cref="KeyVaultKey"/> which will be used f
 37        /// <param name="credential">A <see cref="TokenCredential"/> used to authenticate requests to the vault, like De
 38        /// <exception cref="ArgumentNullException"><paramref name="keyId"/> or <paramref name="credential"/> is null.</
 39        public CryptographyClient(Uri keyId, TokenCredential credential)
 1240            : this(keyId, credential, null)
 41        {
 442        }
 43
 44        /// <summary>
 45        /// Initializes a new instance of the <see cref="CryptographyClient"/> class.
 46        /// </summary>
 47        /// <param name="keyId">The <see cref="KeyProperties.Id"/> of the <see cref="KeyVaultKey"/> which will be used f
 48        /// <param name="credential">A <see cref="TokenCredential"/> used to authenticate requests to the vault, like De
 49        /// <param name="options"><see cref="CryptographyClientOptions"/> that allow to configure the management of the 
 50        /// <exception cref="ArgumentNullException"><paramref name="keyId"/> or <paramref name="credential"/> is null.</
 51        /// <exception cref="NotSupportedException">The <see cref="CryptographyClientOptions.Version"/> is not supported
 1252        public CryptographyClient(Uri keyId, TokenCredential credential, CryptographyClientOptions options) : this(keyId
 53        {
 454        }
 55
 15256        internal CryptographyClient(Uri keyId, TokenCredential credential, CryptographyClientOptions options, bool force
 57        {
 15258            Argument.AssertNotNull(keyId, nameof(keyId));
 14859            Argument.AssertNotNull(credential, nameof(credential));
 60
 14461            _keyId = keyId;
 14462            options ??= new CryptographyClientOptions();
 63
 14464            RemoteCryptographyClient remoteClient = new RemoteCryptographyClient(_keyId, credential, options);
 65
 14466            _pipeline = remoteClient.Pipeline;
 14467            _remoteProvider = remoteClient;
 68
 14469            if (forceRemote)
 70            {
 10471                _provider = remoteClient;
 72            }
 14473        }
 74
 14075        internal CryptographyClient(KeyVaultKey key, TokenCredential credential, CryptographyClientOptions options, ICry
 76        {
 14077            Argument.AssertNotNull(key, nameof(key));
 14078            Argument.AssertNotNull(credential, nameof(credential));
 79
 14080            JsonWebKey keyMaterial = key.Key;
 14081            if (string.IsNullOrEmpty(keyMaterial?.Id))
 82            {
 083                throw new ArgumentException($"{nameof(key.Id)} is required", nameof(key));
 84            }
 85
 14086            _keyId = new Uri(keyMaterial.Id);
 14087            options ??= new CryptographyClientOptions();
 88
 14089            RemoteCryptographyClient remoteClient = new RemoteCryptographyClient(_keyId, credential, options);
 90
 14091            _pipeline = remoteClient.Pipeline;
 14092            _remoteProvider = remoteClient;
 14093            _provider = provider ?? LocalCryptographyProviderFactory.Create(key);
 14094        }
 95
 1296        internal CryptographyClient(KeyVaultKey key, KeyVaultPipeline pipeline)
 97        {
 1298            Argument.AssertNotNull(key, nameof(key));
 99
 12100            JsonWebKey keyMaterial = key.Key;
 12101            if (string.IsNullOrEmpty(keyMaterial?.Id))
 102            {
 0103                throw new ArgumentException($"{nameof(key.Id)} is required", nameof(key));
 104            }
 105
 12106            _keyId = new Uri(keyMaterial.Id);
 107
 12108            RemoteCryptographyClient remoteClient = new RemoteCryptographyClient(pipeline);
 109
 12110            _pipeline = pipeline;
 12111            _remoteProvider = remoteClient;
 12112            _provider = LocalCryptographyProviderFactory.Create(key);
 12113        }
 114
 4115        internal CryptographyClient(Uri keyId, KeyVaultPipeline pipeline)
 116        {
 4117            Argument.AssertNotNull(keyId, nameof(keyId));
 118
 4119            _keyId = keyId;
 120
 4121            RemoteCryptographyClient remoteClient = new RemoteCryptographyClient(pipeline);
 122
 4123            _pipeline = pipeline;
 4124            _remoteProvider = remoteClient;
 4125            _provider = remoteClient;
 4126        }
 127
 36128        internal ICryptographyProvider RemoteClient => _remoteProvider;
 129
 130        /// <summary>
 131        /// Gets the <see cref="KeyVaultKey.Id"/> of the key used to perform cryptographic operations for the client.
 132        /// </summary>
 0133        public virtual string KeyId => _keyId.ToString();
 134
 135        /// <summary>
 136        /// Encrypts the specified plain text.
 137        /// </summary>
 138        /// <param name="algorithm">The <see cref="EncryptionAlgorithm"/> to use.</param>
 139        /// <param name="plaintext">The data to encrypt.</param>
 140        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 141        /// <returns>
 142        /// The result of the encrypt operation. The returned <see cref="EncryptResult"/> contains the encrypted data
 143        /// along with all other information needed to decrypt it. This information should be stored with the encrypted 
 144        /// </returns>
 145        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 146        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 147        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 148        public virtual async Task<EncryptResult> EncryptAsync(EncryptionAlgorithm algorithm, byte[] plaintext, Cancellat
 149        {
 12150            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Encrypt)}");
 12151            scope.AddAttribute("key", _keyId);
 12152            scope.Start();
 153
 154            try
 155            {
 12156                if (_provider is null)
 157                {
 2158                    await InitializeAsync(nameof(Encrypt), cancellationToken).ConfigureAwait(false);
 159                }
 160
 12161                EncryptResult result = null;
 12162                if (_provider.SupportsOperation(KeyOperation.Encrypt))
 163                {
 164                    try
 165                    {
 12166                        result = await _provider.EncryptAsync(algorithm, plaintext, cancellationToken).ConfigureAwait(fa
 10167                    }
 2168                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 169                    {
 170                        // Use the non-async name as we do for scope.
 2171                        KeysEventSource.Singleton.CryptographicException(nameof(Encrypt), ex);
 2172                    }
 173                }
 174
 12175                if (result is null)
 176                {
 4177                    result = await _remoteProvider.EncryptAsync(algorithm, plaintext, cancellationToken).ConfigureAwait(
 178                }
 179
 12180                return result;
 181            }
 0182            catch (Exception e)
 183            {
 0184                scope.Failed(e);
 0185                throw;
 186            }
 12187        }
 188
 189        /// <summary>
 190        /// Encrypts the specified plain text.
 191        /// </summary>
 192        /// <param name="algorithm">The <see cref="EncryptionAlgorithm"/> to use.</param>
 193        /// <param name="plaintext">The data to encrypt.</param>
 194        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 195        /// <returns>
 196        /// The result of the encrypt operation. The returned <see cref="EncryptResult"/> contains the encrypted data
 197        /// along with all other information needed to decrypt it. This information should be stored with the encrypted 
 198        /// </returns>
 199        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 200        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 201        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 202        public virtual EncryptResult Encrypt(EncryptionAlgorithm algorithm, byte[] plaintext, CancellationToken cancella
 203        {
 12204            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Encrypt)}");
 12205            scope.AddAttribute("key", _keyId);
 12206            scope.Start();
 207
 208            try
 209            {
 12210                if (_provider is null)
 211                {
 2212                    Initialize(nameof(Encrypt), cancellationToken);
 213                }
 214
 12215                EncryptResult result = null;
 12216                if (_provider.SupportsOperation(KeyOperation.Encrypt))
 217                {
 218                    try
 219                    {
 12220                        result = _provider.Encrypt(algorithm, plaintext, cancellationToken);
 10221                    }
 2222                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 223                    {
 2224                        KeysEventSource.Singleton.CryptographicException(nameof(Encrypt), ex);
 2225                    }
 226                }
 227
 12228                if (result is null)
 229                {
 4230                    result = _remoteProvider.Encrypt(algorithm, plaintext, cancellationToken);
 231                }
 232
 12233                return result;
 234            }
 0235            catch (Exception e)
 236            {
 0237                scope.Failed(e);
 0238                throw;
 239            }
 12240        }
 241
 242        /// <summary>
 243        /// Decrypts the specified cipher text.
 244        /// </summary>
 245        /// <param name="algorithm">The <see cref="EncryptionAlgorithm"/> to use.</param>
 246        /// <param name="ciphertext">The encrypted data to decrypt.</param>
 247        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 248        /// <returns>
 249        /// The result of the decrypt operation. The returned <see cref="DecryptResult"/> contains the encrypted data
 250        /// along with information regarding the algorithm and key used to decrypt it.
 251        /// </returns>
 252        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 253        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 254        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 255        public virtual async Task<DecryptResult> DecryptAsync(EncryptionAlgorithm algorithm, byte[] ciphertext, Cancella
 256        {
 14257            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Decrypt)}");
 14258            scope.AddAttribute("key", _keyId);
 14259            scope.Start();
 260
 261            try
 262            {
 14263                if (_provider is null)
 264                {
 2265                    await InitializeAsync(nameof(Decrypt), cancellationToken).ConfigureAwait(false);
 266                }
 267
 14268                DecryptResult result = null;
 14269                if (_provider.SupportsOperation(KeyOperation.Decrypt))
 270                {
 271                    try
 272                    {
 14273                        result = await _provider.DecryptAsync(algorithm, ciphertext, cancellationToken).ConfigureAwait(f
 12274                    }
 2275                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 276                    {
 277                        // Use the non-async name as we do for scope.
 2278                        KeysEventSource.Singleton.CryptographicException(nameof(Decrypt), ex);
 2279                    }
 280                }
 281
 14282                if (result is null)
 283                {
 6284                    result = await _remoteProvider.DecryptAsync(algorithm, ciphertext, cancellationToken).ConfigureAwait
 285                }
 286
 14287                return result;
 288            }
 0289            catch (Exception e)
 290            {
 0291                scope.Failed(e);
 0292                throw;
 293            }
 14294        }
 295
 296        /// <summary>
 297        /// Decrypts the specified cipher text.
 298        /// </summary>
 299        /// <param name="algorithm">The <see cref="EncryptionAlgorithm"/> to use.</param>
 300        /// <param name="ciphertext">The encrypted data to decrypt.</param>
 301        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 302        /// <returns>
 303        /// The result of the decrypt operation. The returned <see cref="DecryptResult"/> contains the encrypted data
 304        /// along with information regarding the algorithm and key used to decrypt it.
 305        /// </returns>
 306        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 307        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 308        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 309        public virtual DecryptResult Decrypt(EncryptionAlgorithm algorithm, byte[] ciphertext, CancellationToken cancell
 310        {
 14311            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Decrypt)}");
 14312            scope.AddAttribute("key", _keyId);
 14313            scope.Start();
 314
 315            try
 316            {
 14317                if (_provider is null)
 318                {
 2319                    Initialize(nameof(Decrypt), cancellationToken);
 320                }
 321
 14322                DecryptResult result = null;
 14323                if (_provider.SupportsOperation(KeyOperation.Decrypt))
 324                {
 325                    try
 326                    {
 14327                        result = _provider.Decrypt(algorithm, ciphertext, cancellationToken);
 12328                    }
 2329                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 330                    {
 2331                        KeysEventSource.Singleton.CryptographicException(nameof(Decrypt), ex);
 2332                    }
 333                }
 334
 14335                if (result is null)
 336                {
 6337                    result = _remoteProvider.Decrypt(algorithm, ciphertext, cancellationToken);
 338                }
 339
 14340                return result;
 341            }
 0342            catch (Exception e)
 343            {
 0344                scope.Failed(e);
 0345                throw;
 346            }
 14347        }
 348
 349        /// <summary>
 350        /// Encrypts the specified key.
 351        /// </summary>
 352        /// <param name="algorithm">The <see cref="KeyWrapAlgorithm"/> to use.</param>
 353        /// <param name="key">The key to encrypt.</param>
 354        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 355        /// <returns>
 356        /// The result of the wrap operation. The returned <see cref="WrapResult"/> contains the wrapped key
 357        /// along with all other information needed to unwrap it. This information should be stored with the wrapped key
 358        /// </returns>
 359        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 360        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 361        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 362        public virtual async Task<WrapResult> WrapKeyAsync(KeyWrapAlgorithm algorithm, byte[] key, CancellationToken can
 363        {
 18364            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(WrapKey)}");
 18365            scope.AddAttribute("key", _keyId);
 18366            scope.Start();
 367
 368            try
 369            {
 18370                if (_provider is null)
 371                {
 2372                    await InitializeAsync(nameof(WrapKey), cancellationToken).ConfigureAwait(false);
 373                }
 374
 18375                WrapResult result = null;
 18376                if (_provider.SupportsOperation(KeyOperation.WrapKey))
 377                {
 378                    try
 379                    {
 18380                        result = await _provider.WrapKeyAsync(algorithm, key, cancellationToken).ConfigureAwait(false);
 16381                    }
 2382                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 383                    {
 384                        // Use the non-async name as we do for scope.
 2385                        KeysEventSource.Singleton.CryptographicException(nameof(WrapKey), ex);
 2386                    }
 387                }
 388
 18389                if (result is null)
 390                {
 6391                    result = await _remoteProvider.WrapKeyAsync(algorithm, key, cancellationToken).ConfigureAwait(false)
 392                }
 393
 18394                return result;
 395            }
 0396            catch (Exception e)
 397            {
 0398                scope.Failed(e);
 0399                throw;
 400            }
 18401        }
 402
 403        /// <summary>
 404        /// Encrypts the specified key.
 405        /// </summary>
 406        /// <param name="algorithm">The <see cref="KeyWrapAlgorithm"/> to use.</param>
 407        /// <param name="key">The key to encrypt.</param>
 408        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 409        /// <returns>
 410        /// The result of the wrap operation. The returned <see cref="WrapResult"/> contains the wrapped key
 411        /// along with all other information needed to unwrap it. This information should be stored with the wrapped key
 412        /// </returns>
 413        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 414        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 415        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 416        public virtual WrapResult WrapKey(KeyWrapAlgorithm algorithm, byte[] key, CancellationToken cancellationToken = 
 417        {
 18418            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(WrapKey)}");
 18419            scope.AddAttribute("key", _keyId);
 18420            scope.Start();
 421
 422            try
 423            {
 18424                if (_provider is null)
 425                {
 2426                    Initialize(nameof(WrapKey), cancellationToken);
 427                }
 428
 18429                WrapResult result = null;
 18430                if (_provider.SupportsOperation(KeyOperation.WrapKey))
 431                {
 432                    try
 433                    {
 18434                        result = _provider.WrapKey(algorithm, key, cancellationToken);
 16435                    }
 2436                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 437                    {
 2438                        KeysEventSource.Singleton.CryptographicException(nameof(WrapKey), ex);
 2439                    }
 440                }
 441
 18442                if (result is null)
 443                {
 6444                    result = _remoteProvider.WrapKey(algorithm, key, cancellationToken);
 445                }
 446
 18447                return result;
 448            }
 0449            catch (Exception e)
 450            {
 0451                scope.Failed(e);
 0452                throw;
 453            }
 18454        }
 455
 456        /// <summary>
 457        /// Decrypts the specified encrypted key.
 458        /// </summary>
 459        /// <param name="algorithm">The <see cref="KeyWrapAlgorithm"/> to use.</param>
 460        /// <param name="encryptedKey">The encrypted key.</param>
 461        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 462        /// <returns>
 463        /// The result of the unwrap operation. The returned <see cref="UnwrapResult"/> contains the key
 464        /// along with information regarding the algorithm and key used to unwrap it.
 465        /// </returns>
 466        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 467        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 468        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 469        public virtual async Task<UnwrapResult> UnwrapKeyAsync(KeyWrapAlgorithm algorithm, byte[] encryptedKey, Cancella
 470        {
 24471            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(UnwrapKey)}");
 24472            scope.AddAttribute("key", _keyId);
 24473            scope.Start();
 474
 475            try
 476            {
 24477                if (_provider is null)
 478                {
 2479                    await InitializeAsync(nameof(UnwrapKey), cancellationToken).ConfigureAwait(false);
 480                }
 481
 24482                UnwrapResult result = null;
 24483                if (_provider.SupportsOperation(KeyOperation.UnwrapKey))
 484                {
 485                    try
 486                    {
 24487                        result = await _provider.UnwrapKeyAsync(algorithm, encryptedKey, cancellationToken).ConfigureAwa
 18488                    }
 2489                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 490                    {
 491                        // Use the non-async name as we do for scope.
 2492                        KeysEventSource.Singleton.CryptographicException(nameof(UnwrapKey), ex);
 2493                    }
 494                }
 495
 20496                if (result is null)
 497                {
 10498                    result = await _remoteProvider.UnwrapKeyAsync(algorithm, encryptedKey, cancellationToken).ConfigureA
 499                }
 500
 20501                return result;
 502            }
 4503            catch (Exception e)
 504            {
 4505                scope.Failed(e);
 4506                throw;
 507            }
 20508        }
 509
 510        /// <summary>
 511        /// Decrypts the specified encrypted key.
 512        /// </summary>
 513        /// <param name="algorithm">The <see cref="KeyWrapAlgorithm"/> to use.</param>
 514        /// <param name="encryptedKey">The encrypted key.</param>
 515        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 516        /// <returns>
 517        /// The result of the unwrap operation. The returned <see cref="UnwrapResult"/> contains the key
 518        /// along with information regarding the algorithm and key used to unwrap it.
 519        /// </returns>
 520        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 521        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 522        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 523        public virtual UnwrapResult UnwrapKey(KeyWrapAlgorithm algorithm, byte[] encryptedKey, CancellationToken cancell
 524        {
 20525            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(UnwrapKey)}");
 20526            scope.AddAttribute("key", _keyId);
 20527            scope.Start();
 528
 529            try
 530            {
 20531                if (_provider is null)
 532                {
 2533                    Initialize(nameof(UnwrapKey), cancellationToken);
 534                }
 535
 20536                UnwrapResult result = null;
 20537                if (_provider.SupportsOperation(KeyOperation.UnwrapKey))
 538                {
 539                    try
 540                    {
 20541                        result = _provider.UnwrapKey(algorithm, encryptedKey, cancellationToken);
 18542                    }
 2543                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 544                    {
 2545                        KeysEventSource.Singleton.CryptographicException(nameof(UnwrapKey), ex);
 2546                    }
 547                }
 548
 20549                if (result is null)
 550                {
 10551                    result = _remoteProvider.UnwrapKey(algorithm, encryptedKey, cancellationToken);
 552                }
 553
 20554                return result;
 555            }
 0556            catch (Exception e)
 557            {
 0558                scope.Failed(e);
 0559                throw;
 560            }
 20561        }
 562
 563        /// <summary>
 564        /// Signs the specified digest.
 565        /// </summary>
 566        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use.</param>
 567        /// <param name="digest">The pre-hashed digest to sign. The hash algorithm used to compute the digest must be co
 568        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 569        /// <returns>
 570        /// The result of the sign operation. The returned <see cref="SignResult"/> contains the signature
 571        /// along with all other information needed to verify it. This information should be stored with the signature.
 572        /// </returns>
 573        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 574        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 575        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 576        public virtual async Task<SignResult> SignAsync(SignatureAlgorithm algorithm, byte[] digest, CancellationToken c
 577        {
 88578            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Sign)}");
 88579            scope.AddAttribute("key", _keyId);
 88580            scope.Start();
 581
 582            try
 583            {
 88584                if (_provider is null)
 585                {
 20586                    await InitializeAsync(nameof(Sign), cancellationToken).ConfigureAwait(false);
 587                }
 588
 88589                SignResult result = null;
 88590                if (_provider.SupportsOperation(KeyOperation.Sign))
 591                {
 592                    try
 593                    {
 88594                        result = await _provider.SignAsync(algorithm, digest, cancellationToken).ConfigureAwait(false);
 86595                    }
 2596                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 597                    {
 598                        // Use the non-async name as we do for scope.
 2599                        KeysEventSource.Singleton.CryptographicException(nameof(Sign), ex);
 2600                    }
 601                }
 602
 88603                if (result is null)
 604                {
 28605                    result = await _remoteProvider.SignAsync(algorithm, digest, cancellationToken).ConfigureAwait(false)
 606                }
 607
 88608                return result;
 609            }
 0610            catch (Exception e)
 611            {
 0612                scope.Failed(e);
 0613                throw;
 614            }
 88615        }
 616
 617        /// <summary>
 618        /// Signs the specified digest.
 619        /// </summary>
 620        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use.</param>
 621        /// <param name="digest">The pre-hashed digest to sign. The hash algorithm used to compute the digest must be co
 622        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 623        /// <returns>
 624        /// The result of the sign operation. The returned <see cref="SignResult"/> contains the signature
 625        /// along with all other information needed to verify it. This information should be stored with the signature.
 626        /// </returns>
 627        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 628        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 629        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 630        public virtual SignResult Sign(SignatureAlgorithm algorithm, byte[] digest, CancellationToken cancellationToken 
 631        {
 88632            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Sign)}");
 88633            scope.AddAttribute("key", _keyId);
 88634            scope.Start();
 635
 636            try
 637            {
 88638                if (_provider is null)
 639                {
 20640                    Initialize(nameof(Sign), cancellationToken);
 641                }
 642
 88643                SignResult result = null;
 88644                if (_provider.SupportsOperation(KeyOperation.Sign))
 645                {
 646                    try
 647                    {
 88648                        result = _provider.Sign(algorithm, digest, cancellationToken);
 86649                    }
 2650                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 651                    {
 2652                        KeysEventSource.Singleton.CryptographicException(nameof(Sign), ex);
 2653                    }
 654                }
 655
 88656                if (result is null)
 657                {
 28658                    result = _remoteProvider.Sign(algorithm, digest, cancellationToken);
 659                }
 660
 88661                return result;
 662            }
 0663            catch (Exception e)
 664            {
 0665                scope.Failed(e);
 0666                throw;
 667            }
 88668        }
 669
 670        /// <summary>
 671        /// Verifies the specified signature.
 672        /// </summary>
 673        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use. This must be the same algorithm used to
 674        /// <param name="digest">The pre-hashed digest corresponding to the signature. The hash algorithm used to comput
 675        /// <param name="signature">The signature to verify.</param>
 676        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 677        /// <returns>
 678        /// The result of the verify operation. If the signature is valid the <see cref="VerifyResult.IsValid"/> propert
 679        /// </returns>
 680        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 681        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 682        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 683        public virtual async Task<VerifyResult> VerifyAsync(SignatureAlgorithm algorithm, byte[] digest, byte[] signatur
 684        {
 66685            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Verify)}");
 66686            scope.AddAttribute("key", _keyId);
 66687            scope.Start();
 688
 689            try
 690            {
 66691                if (_provider is null)
 692                {
 2693                    await InitializeAsync(nameof(Verify), cancellationToken).ConfigureAwait(false);
 694                }
 695
 66696                VerifyResult result = null;
 66697                if (_provider.SupportsOperation(KeyOperation.Verify))
 698                {
 699                    try
 700                    {
 66701                        result = await _provider.VerifyAsync(algorithm, digest, signature, cancellationToken).ConfigureA
 64702                    }
 2703                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 704                    {
 705                        // Use the non-async name as we do for scope.
 2706                        KeysEventSource.Singleton.CryptographicException(nameof(Verify), ex);
 2707                    }
 708                }
 709
 66710                if (result is null)
 711                {
 6712                    result = await _remoteProvider.VerifyAsync(algorithm, digest, signature, cancellationToken).Configur
 713                }
 714
 66715                return result;
 716            }
 0717            catch (Exception e)
 718            {
 0719                scope.Failed(e);
 0720                throw;
 721            }
 66722        }
 723
 724        /// <summary>
 725        /// Verifies the specified signature.
 726        /// </summary>
 727        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use. This must be the same algorithm used to
 728        /// <param name="digest">The pre-hashed digest corresponding to the signature. The hash algorithm used to comput
 729        /// <param name="signature">The signature to verify.</param>
 730        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 731        /// <returns>
 732        /// The result of the verify operation. If the signature is valid the <see cref="VerifyResult.IsValid"/> propert
 733        /// </returns>
 734        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 735        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 736        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 737        public virtual VerifyResult Verify(SignatureAlgorithm algorithm, byte[] digest, byte[] signature, CancellationTo
 738        {
 66739            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Verify)}");
 66740            scope.AddAttribute("key", _keyId);
 66741            scope.Start();
 742
 743            try
 744            {
 66745                if (_provider is null)
 746                {
 2747                    Initialize(nameof(Verify), cancellationToken);
 748                }
 749
 66750                VerifyResult result = null;
 66751                if (_provider.SupportsOperation(KeyOperation.Verify))
 752                {
 753                    try
 754                    {
 66755                        result = _provider.Verify(algorithm, digest, signature, cancellationToken);
 64756                    }
 2757                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 758                    {
 2759                        KeysEventSource.Singleton.CryptographicException(nameof(Verify), ex);
 2760                    }
 761                }
 762
 66763                if (result is null)
 764                {
 6765                    result = _remoteProvider.Verify(algorithm, digest, signature, cancellationToken);
 766                }
 767
 66768                return result;
 769            }
 0770            catch (Exception e)
 771            {
 0772                scope.Failed(e);
 0773                throw;
 774            }
 66775        }
 776
 777        /// <summary>
 778        /// Signs the specified data.
 779        /// </summary>
 780        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use.</param>
 781        /// <param name="data">The data to sign.</param>
 782        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 783        /// <returns>
 784        /// The result of the sign operation. The returned <see cref="SignResult"/> contains the signature
 785        /// along with all other information needed to verify it. This information should be stored with the signature.
 786        /// </returns>
 787        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 788        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 789        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 790        public virtual async Task<SignResult> SignDataAsync(SignatureAlgorithm algorithm, byte[] data, CancellationToken
 791        {
 22792            Argument.AssertNotNull(data, nameof(data));
 793
 20794            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(SignData)}");
 20795            scope.AddAttribute("key", _keyId);
 20796            scope.Start();
 797
 798            try
 799            {
 20800                byte[] digest = CreateDigest(algorithm, data);
 801
 20802                if (_provider is null)
 803                {
 0804                    await InitializeAsync(nameof(SignData), cancellationToken).ConfigureAwait(false);
 805                }
 806
 20807                SignResult result = null;
 20808                if (_provider.SupportsOperation(KeyOperation.Sign))
 809                {
 810                    try
 811                    {
 20812                        result = await _provider.SignAsync(algorithm, digest, cancellationToken).ConfigureAwait(false);
 20813                    }
 0814                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 815                    {
 816                        // Use the non-async name as we do for scope.
 0817                        KeysEventSource.Singleton.CryptographicException(nameof(SignData), ex);
 0818                    }
 819                }
 820
 20821                if (result is null)
 822                {
 0823                    result = await _remoteProvider.SignAsync(algorithm, digest, cancellationToken).ConfigureAwait(false)
 824                }
 825
 20826                return result;
 827            }
 0828            catch (Exception e)
 829            {
 0830                scope.Failed(e);
 0831                throw;
 832            }
 20833        }
 834
 835        /// <summary>
 836        /// Signs the specified data.
 837        /// </summary>
 838        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use.</param>
 839        /// <param name="data">The data to sign.</param>
 840        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 841        /// <returns>
 842        /// The result of the sign operation. The returned <see cref="SignResult"/> contains the signature
 843        /// along with all other information needed to verify it. This information should be stored with the signature.
 844        /// </returns>
 845        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 846        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 847        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 848        public virtual SignResult SignData(SignatureAlgorithm algorithm, byte[] data, CancellationToken cancellationToke
 849        {
 22850            Argument.AssertNotNull(data, nameof(data));
 851
 20852            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(SignData)}");
 20853            scope.AddAttribute("key", _keyId);
 20854            scope.Start();
 855
 856            try
 857            {
 20858                byte[] digest = CreateDigest(algorithm, data);
 859
 20860                if (_provider is null)
 861                {
 0862                    Initialize(nameof(SignData), cancellationToken);
 863                }
 864
 20865                SignResult result = null;
 20866                if (_provider.SupportsOperation(KeyOperation.Sign))
 867                {
 868                    try
 869                    {
 20870                        result = _provider.Sign(algorithm, digest, cancellationToken);
 20871                    }
 0872                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 873                    {
 874                        // Use the non-async name as we do for scope.
 0875                        KeysEventSource.Singleton.CryptographicException(nameof(SignData), ex);
 0876                    }
 877                }
 878
 20879                if (result is null)
 880                {
 0881                    result = _remoteProvider.Sign(algorithm, digest, cancellationToken);
 882                }
 883
 20884                return result;
 885            }
 0886            catch (Exception e)
 887            {
 0888                scope.Failed(e);
 0889                throw;
 890            }
 20891        }
 892
 893        /// <summary>
 894        /// Signs the specified data.
 895        /// </summary>
 896        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use.</param>
 897        /// <param name="data">The data to sign.</param>
 898        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 899        /// <returns>
 900        /// The result of the sign operation. The returned <see cref="SignResult"/> contains the signature
 901        /// along with all other information needed to verify it. This information should be stored with the signature.
 902        /// </returns>
 903        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 904        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
 905        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 906        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 907        public virtual async Task<SignResult> SignDataAsync(SignatureAlgorithm algorithm, Stream data, CancellationToken
 908        {
 22909            Argument.AssertNotNull(data, nameof(data));
 910
 20911            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(SignData)}");
 20912            scope.AddAttribute("key", _keyId);
 20913            scope.Start();
 914
 915            try
 916            {
 20917                byte[] digest = CreateDigest(algorithm, data);
 918
 20919                if (_provider is null)
 920                {
 0921                    await InitializeAsync(nameof(SignData), cancellationToken).ConfigureAwait(false);
 922                }
 923
 20924                SignResult result = null;
 20925                if (_provider.SupportsOperation(KeyOperation.Sign))
 926                {
 927                    try
 928                    {
 20929                        result = await _provider.SignAsync(algorithm, digest, cancellationToken).ConfigureAwait(false);
 20930                    }
 0931                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 932                    {
 933                        // Use the non-async name as we do for scope.
 0934                        KeysEventSource.Singleton.CryptographicException(nameof(SignData), ex);
 0935                    }
 936                }
 937
 20938                if (result is null)
 939                {
 0940                    result = await _remoteProvider.SignAsync(algorithm, digest, cancellationToken).ConfigureAwait(false)
 941                }
 942
 20943                return result;
 944            }
 0945            catch (Exception e)
 946            {
 0947                scope.Failed(e);
 0948                throw;
 949            }
 20950        }
 951
 952        /// <summary>
 953        /// Signs the specified data.
 954        /// </summary>
 955        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use.</param>
 956        /// <param name="data">The data to sign.</param>
 957        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 958        /// <returns>
 959        /// The result of the sign operation. The returned <see cref="SignResult"/> contains the signature
 960        /// along with all other information needed to verify it. This information should be stored with the signature.
 961        /// </returns>
 962        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 963        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
 964        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 965        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 966        public virtual SignResult SignData(SignatureAlgorithm algorithm, Stream data, CancellationToken cancellationToke
 967        {
 22968            Argument.AssertNotNull(data, nameof(data));
 969
 20970            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(SignData)}");
 20971            scope.AddAttribute("key", _keyId);
 20972            scope.Start();
 973
 974            try
 975            {
 20976                byte[] digest = CreateDigest(algorithm, data);
 977
 20978                if (_provider is null)
 979                {
 0980                    Initialize(nameof(SignData), cancellationToken);
 981                }
 982
 20983                SignResult result = null;
 20984                if (_provider.SupportsOperation(KeyOperation.Sign))
 985                {
 986                    try
 987                    {
 20988                        result = _provider.Sign(algorithm, digest, cancellationToken);
 20989                    }
 0990                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 991                    {
 0992                        KeysEventSource.Singleton.CryptographicException(nameof(SignData), ex);
 0993                    }
 994                }
 995
 20996                if (result is null)
 997                {
 0998                    result = _remoteProvider.Sign(algorithm, digest, cancellationToken);
 999                }
 1000
 201001                return result;
 1002            }
 01003            catch (Exception e)
 1004            {
 01005                scope.Failed(e);
 01006                throw;
 1007            }
 201008        }
 1009
 1010        /// <summary>
 1011        /// Verifies the specified signature.
 1012        /// </summary>
 1013        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use. This must be the same algorithm used to
 1014        /// <param name="data">The data corresponding to the signature.</param>
 1015        /// <param name="signature">The signature to verify.</param>
 1016        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 1017        /// <returns>
 1018        /// The result of the verify operation. If the signature is valid the <see cref="VerifyResult.IsValid"/> propert
 1019        /// </returns>
 1020        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 1021        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
 1022        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 1023        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 1024        public virtual async Task<VerifyResult> VerifyDataAsync(SignatureAlgorithm algorithm, byte[] data, byte[] signat
 1025        {
 221026            Argument.AssertNotNull(data, nameof(data));
 1027
 201028            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(VerifyData)}");
 201029            scope.AddAttribute("key", _keyId);
 201030            scope.Start();
 1031
 1032            try
 1033            {
 201034                byte[] digest = CreateDigest(algorithm, data);
 1035
 201036                if (_provider is null)
 1037                {
 01038                    await InitializeAsync(nameof(VerifyData), cancellationToken).ConfigureAwait(false);
 1039                }
 1040
 201041                VerifyResult result = null;
 201042                if (_provider.SupportsOperation(KeyOperation.Verify))
 1043                {
 1044                    try
 1045                    {
 201046                        result = await _provider.VerifyAsync(algorithm, digest, signature, cancellationToken).ConfigureA
 201047                    }
 01048                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 1049                    {
 1050                        // Use the non-async name as we do for scope.
 01051                        KeysEventSource.Singleton.CryptographicException(nameof(VerifyData), ex);
 01052                    }
 1053                }
 1054
 201055                if (result is null)
 1056                {
 01057                    result = await _remoteProvider.VerifyAsync(algorithm, digest, signature, cancellationToken).Configur
 1058                }
 1059
 201060                return result;
 1061            }
 01062            catch (Exception e)
 1063            {
 01064                scope.Failed(e);
 01065                throw;
 1066            }
 201067        }
 1068
 1069        /// <summary>
 1070        /// Verifies the specified signature.
 1071        /// </summary>
 1072        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use. This must be the same algorithm used to
 1073        /// <param name="data">The data corresponding to the signature.</param>
 1074        /// <param name="signature">The signature to verify.</param>
 1075        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 1076        /// <returns>
 1077        /// The result of the verify operation. If the signature is valid the <see cref="VerifyResult.IsValid"/> propert
 1078        /// </returns>
 1079        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 1080        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
 1081        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 1082        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 1083        public virtual VerifyResult VerifyData(SignatureAlgorithm algorithm, byte[] data, byte[] signature, Cancellation
 1084        {
 221085            Argument.AssertNotNull(data, nameof(data));
 1086
 201087            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(VerifyData)}");
 201088            scope.AddAttribute("key", _keyId);
 201089            scope.Start();
 1090
 1091            try
 1092            {
 201093                byte[] digest = CreateDigest(algorithm, data);
 1094
 201095                if (_provider is null)
 1096                {
 01097                    Initialize(nameof(VerifyData), cancellationToken);
 1098                }
 1099
 201100                VerifyResult result = null;
 201101                if (_provider.SupportsOperation(KeyOperation.Verify))
 1102                {
 1103                    try
 1104                    {
 201105                        result = _provider.Verify(algorithm, digest, signature, cancellationToken);
 201106                    }
 01107                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 1108                    {
 01109                        KeysEventSource.Singleton.CryptographicException(nameof(VerifyData), ex);
 01110                    }
 1111                }
 1112
 201113                if (result is null)
 1114                {
 01115                    result = _remoteProvider.Verify(algorithm, digest, signature, cancellationToken);
 1116                }
 1117
 201118                return result;
 1119            }
 01120            catch (Exception e)
 1121            {
 01122                scope.Failed(e);
 01123                throw;
 1124            }
 201125        }
 1126
 1127        /// <summary>
 1128        /// Verifies the specified signature.
 1129        /// </summary>
 1130        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use. This must be the same algorithm used to
 1131        /// <param name="data">The data corresponding to the signature.</param>
 1132        /// <param name="signature">The signature to verify.</param>
 1133        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 1134        /// <returns>
 1135        /// The result of the verify operation. If the signature is valid the <see cref="VerifyResult.IsValid"/> propert
 1136        /// </returns>
 1137        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 1138        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
 1139        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 1140        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 1141        public virtual async Task<VerifyResult> VerifyDataAsync(SignatureAlgorithm algorithm, Stream data, byte[] signat
 1142        {
 221143            Argument.AssertNotNull(data, nameof(data));
 1144
 201145            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(VerifyData)}");
 201146            scope.AddAttribute("key", _keyId);
 201147            scope.Start();
 1148
 1149            try
 1150            {
 201151                byte[] digest = CreateDigest(algorithm, data);
 1152
 201153                if (_provider is null)
 1154                {
 01155                    await InitializeAsync(nameof(VerifyData), cancellationToken).ConfigureAwait(false);
 1156                }
 1157
 201158                VerifyResult result = null;
 201159                if (_provider.SupportsOperation(KeyOperation.Verify))
 1160                {
 1161                    try
 1162                    {
 201163                        result = await _provider.VerifyAsync(algorithm, digest, signature, cancellationToken).ConfigureA
 201164                    }
 01165                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 1166                    {
 1167                        // Use the non-async name as we do for scope.
 01168                        KeysEventSource.Singleton.CryptographicException(nameof(VerifyData), ex);
 01169                    }
 1170                }
 1171
 201172                if (result is null)
 1173                {
 01174                    result = await _remoteProvider.VerifyAsync(algorithm, digest, signature, cancellationToken).Configur
 1175                }
 1176
 201177                return result;
 1178            }
 01179            catch (Exception e)
 1180            {
 01181                scope.Failed(e);
 01182                throw;
 1183            }
 201184        }
 1185
 1186        /// <summary>
 1187        /// Verifies the specified signature.
 1188        /// </summary>
 1189        /// <param name="algorithm">The <see cref="SignatureAlgorithm"/> to use. This must be the same algorithm used to
 1190        /// <param name="data">The data corresponding to the signature.</param>
 1191        /// <param name="signature">The signature to verify.</param>
 1192        /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation.</param>
 1193        /// <returns>
 1194        /// The result of the verify operation. If the signature is valid the <see cref="VerifyResult.IsValid"/> propert
 1195        /// </returns>
 1196        /// <exception cref="ArgumentException">The specified <paramref name="algorithm"/> does not match the key corres
 1197        /// <exception cref="ArgumentNullException"><paramref name="data"/> is null.</exception>
 1198        /// <exception cref="NotSupportedException">The operation is not supported with the specified key.</exception>
 1199        /// <exception cref="RequestFailedException">The server returned an error. See <see cref="Exception.Message"/> f
 1200        public virtual VerifyResult VerifyData(SignatureAlgorithm algorithm, Stream data, byte[] signature, Cancellation
 1201        {
 221202            Argument.AssertNotNull(data, nameof(data));
 1203
 201204            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(VerifyData)}");
 201205            scope.AddAttribute("key", _keyId);
 201206            scope.Start();
 1207
 1208            try
 1209            {
 201210                byte[] digest = CreateDigest(algorithm, data);
 1211
 201212                if (_provider is null)
 1213                {
 01214                    Initialize(nameof(VerifyData), cancellationToken);
 1215                }
 1216
 201217                VerifyResult result = null;
 201218                if (_provider.SupportsOperation(KeyOperation.Verify))
 1219                {
 1220                    try
 1221                    {
 201222                        result = _provider.Verify(algorithm, digest, signature, cancellationToken);
 201223                    }
 01224                    catch (CryptographicException ex) when (_provider.ShouldRemote)
 1225                    {
 01226                        KeysEventSource.Singleton.CryptographicException(nameof(VerifyData), ex);
 01227                    }
 1228                }
 1229
 201230                if (result is null)
 1231                {
 01232                    result = _remoteProvider.Verify(algorithm, digest, signature, cancellationToken);
 1233                }
 1234
 201235                return result;
 1236            }
 01237            catch (Exception e)
 1238            {
 01239                scope.Failed(e);
 01240                throw;
 1241            }
 201242        }
 1243
 1244        /// <inheritdoc/>
 1245        byte[] IKeyEncryptionKey.WrapKey(string algorithm, ReadOnlyMemory<byte> key, CancellationToken cancellationToken
 1246        {
 01247            WrapResult result = WrapKey(new KeyWrapAlgorithm(algorithm), key.ToArray(), cancellationToken);
 1248
 01249            return result.EncryptedKey;
 1250        }
 1251
 1252        /// <inheritdoc/>
 1253        async Task<byte[]> IKeyEncryptionKey.WrapKeyAsync(string algorithm, ReadOnlyMemory<byte> key, CancellationToken 
 1254        {
 01255            WrapResult result = await WrapKeyAsync(new KeyWrapAlgorithm(algorithm), key.ToArray(), cancellationToken).Co
 1256
 01257            return result.EncryptedKey;
 01258        }
 1259
 1260        /// <inheritdoc/>
 1261        byte[] IKeyEncryptionKey.UnwrapKey(string algorithm, ReadOnlyMemory<byte> encryptedKey, CancellationToken cancel
 1262        {
 01263            byte[] buffer = MemoryMarshal.TryGetArray(encryptedKey, out ArraySegment<byte> segment) ? segment.Array : en
 01264            UnwrapResult result = UnwrapKey(new KeyWrapAlgorithm(algorithm), buffer, cancellationToken);
 1265
 01266            return result.Key;
 1267        }
 1268
 1269        /// <inheritdoc/>
 1270        async Task<byte[]> IKeyEncryptionKey.UnwrapKeyAsync(string algorithm, ReadOnlyMemory<byte> encryptedKey, Cancell
 1271        {
 01272            byte[] buffer = MemoryMarshal.TryGetArray(encryptedKey, out ArraySegment<byte> segment) ? segment.Array : en
 01273            UnwrapResult result = await UnwrapKeyAsync(new KeyWrapAlgorithm(algorithm), buffer, cancellationToken).Confi
 1274
 01275            return result.Key;
 01276        }
 1277
 1278        private static byte[] CreateDigest(SignatureAlgorithm algorithm, byte[] data)
 1279        {
 801280            using HashAlgorithm hashAlgo = algorithm.GetHashAlgorithm();
 801281            return hashAlgo.ComputeHash(data);
 801282        }
 1283
 1284        private static byte[] CreateDigest(SignatureAlgorithm algorithm, Stream data)
 1285        {
 801286            using HashAlgorithm hashAlgo = algorithm.GetHashAlgorithm();
 801287            return hashAlgo.ComputeHash(data);
 801288        }
 1289
 1290        private async Task InitializeAsync(string operation, CancellationToken cancellationToken)
 1291        {
 301292            if (_provider != null)
 1293            {
 01294                return;
 1295            }
 1296
 301297            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Initialize)}");
 301298            scope.AddAttribute("key", _keyId);
 301299            scope.Start();
 1300
 1301            try
 1302            {
 301303                Response<KeyVaultKey> key = await _remoteProvider.GetKeyAsync(cancellationToken).ConfigureAwait(false);
 1304
 301305                _provider = LocalCryptographyProviderFactory.Create(key.Value);
 301306                if (_provider is null)
 1307                {
 121308                    KeysEventSource.Singleton.KeyTypeNotSupported(operation, key.Value);
 1309
 121310                    _provider = _remoteProvider;
 121311                    return;
 1312                }
 181313            }
 01314            catch (RequestFailedException e) when (e.Status == 403)
 1315            {
 01316                scope.AddAttribute("status", e.Status);
 1317
 01318                _provider = _remoteProvider;
 01319            }
 01320            catch (Exception e)
 1321            {
 01322                scope.Failed(e);
 01323                throw;
 1324            }
 301325        }
 1326
 1327        private void Initialize(string operation, CancellationToken cancellationToken)
 1328        {
 301329            if (_provider != null)
 1330            {
 01331                return;
 1332            }
 1333
 301334            using DiagnosticScope scope = _pipeline.CreateScope($"{nameof(CryptographyClient)}.{nameof(Initialize)}");
 301335            scope.AddAttribute("key", _keyId);
 301336            scope.Start();
 1337
 1338            try
 1339            {
 301340                Response<KeyVaultKey> key = _remoteProvider.GetKey(cancellationToken);
 1341
 301342                _provider = LocalCryptographyProviderFactory.Create(key.Value);
 301343                if (_provider is null)
 1344                {
 121345                    KeysEventSource.Singleton.KeyTypeNotSupported(operation, key.Value);
 1346
 121347                    _provider = _remoteProvider;
 1348                    return;
 1349                }
 301350            }
 01351            catch (RequestFailedException e) when (e.Status == 403)
 1352            {
 01353                scope.AddAttribute("status", e.Status);
 1354
 01355                _provider = _remoteProvider;
 01356            }
 01357            catch (Exception e)
 1358            {
 01359                scope.Failed(e);
 01360                throw;
 1361            }
 301362        }
 1363    }
 1364}