< Summary

Class:Microsoft.Azure.KeyVault.RsaKey
Assembly:Microsoft.Azure.KeyVault.Cryptography
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Microsoft.Azure.KeyVault.Cryptography\src\RsaKey.cs
Covered lines:90
Uncovered lines:43
Coverable lines:133
Total lines:362
Line coverage:67.6% (90 of 133)
Covered branches:48
Total branches:86
Branch coverage:55.8% (48 of 86)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
get_Kid()-100%100%
.ctor()-0%100%
.ctor(...)-100%100%
.ctor(...)-85.71%50%
.ctor(...)-0%0%
.ctor(...)-75%50%
Dispose()-100%100%
Dispose(...)-100%100%
get_DefaultEncryptionAlgorithm()-100%100%
get_DefaultKeyWrapAlgorithm()-100%100%
get_DefaultSignatureAlgorithm()-100%100%
DecryptAsync(...)-66.67%57.14%
EncryptAsync(...)-66.67%57.14%
WrapKeyAsync(...)-71.43%60%
UnwrapKeyAsync(...)-71.43%60%
SignAsync(...)-64.29%50%
VerifyAsync(...)-62.5%50%

File(s)

C:\Git\azure-sdk-for-net\sdk\keyvault\Microsoft.Azure.KeyVault.Cryptography\src\RsaKey.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License. See License.txt in the project root for
 3// license information.
 4
 5using System;
 6using System.Security.Cryptography;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using Microsoft.Azure.KeyVault.Core;
 10using Microsoft.Azure.KeyVault.Cryptography;
 11using Microsoft.Azure.KeyVault.Cryptography.Algorithms;
 12
 13#if NETSTANDARD
 14using TaskException = System.Threading.Tasks.Task;
 15#endif
 16
 17namespace Microsoft.Azure.KeyVault
 18{
 19    /// <summary>
 20    /// An RSA key.
 21    /// </summary>
 22    public class RsaKey : IKey, IDisposable
 23    {
 24        public const int KeySize1024 = 1024;
 25        public const int KeySize2048 = 2048;
 26
 227        private static readonly int DefaultKeySize = KeySize2048;
 28
 29        private RSA _csp;
 30
 31        /// <summary>
 32        /// Key Identifier
 33        /// </summary>
 9834        public string Kid { get; private set; }
 35
 36        /// <summary>
 37        /// Constructor, creates a 2048 bit key with a GUID identifier.
 38        /// </summary>
 039        public RsaKey() : this( Guid.NewGuid().ToString( "D" ), DefaultKeySize )
 40        {
 041        }
 42
 43        /// <summary>
 44        /// Constructor, creates a 2048 bit RSA key.
 45        /// </summary>
 46        /// <param name="kid">The key identifier to use</param>
 2647        public RsaKey( string kid ) : this( kid, DefaultKeySize )
 48        {
 2649        }
 50
 51        /// <summary>
 52        /// Constructor.
 53        /// </summary>
 54        /// <param name="kid">The key identifier to use</param>
 55        /// <param name="keySize">The size of the key</param>
 2656        public RsaKey( string kid, int keySize )
 57        {
 2658            if ( string.IsNullOrWhiteSpace( kid ) )
 059                throw new ArgumentNullException( "kid" );
 60
 2661            Kid = kid;
 62
 2663            _csp = RSA.Create();
 64
 2665            _csp.KeySize = keySize;
 2666        }
 67
 68        /// <summary>
 69        /// Constructor
 70        /// </summary>
 71        /// <param name="kid">The key identifier to use</param>
 72        /// <param name="keyParameters">The RSA parameters for the key</param>
 073        public RsaKey( string kid, RSAParameters keyParameters )
 74        {
 075            if ( string.IsNullOrWhiteSpace( kid ) )
 076                throw new ArgumentNullException( "kid" );
 77
 078            Kid = kid;
 79
 080            _csp = RSA.Create();
 081            _csp.ImportParameters( keyParameters );
 082        }
 83
 84        /// <summary>
 85        /// Constructor.
 86        /// </summary>
 87        /// <param name="kid">The key identifier to use</param>
 88        /// <param name="csp">The RSA object for the key</param>
 89        /// <remarks>The RSA object is IDisposable, this class will hold a
 90        /// reference to the RSA object but will not dispose it, the caller
 91        /// of this constructor is responsible for the lifetime of this
 92        /// parameter.</remarks>
 1693        public RsaKey( string kid, RSA csp )
 94        {
 1695            if ( string.IsNullOrWhiteSpace( kid ) )
 096                throw new ArgumentNullException( "kid" );
 97
 1698            if ( csp == null )
 099                throw new ArgumentNullException( "csp" );
 100
 16101            Kid = kid;
 102
 103            // NOTE: RSA is disposable and that may lead to runtime errors later.
 16104            _csp = csp;
 16105        }
 106
 107        // Intentionally excluded.
 108        //~RsaKey()
 109        //{
 110        //    Dispose( false );
 111        //}
 112
 113        public void Dispose()
 114        {
 14115            Dispose( true );
 14116            GC.SuppressFinalize( this );
 14117        }
 118
 119        protected virtual void Dispose( bool disposing )
 120        {
 121            // Clean up managed resources if Dispose was called
 14122            if ( disposing )
 123            {
 14124                if ( _csp != null )
 125                {
 14126                    _csp.Dispose();
 14127                    _csp = null;
 128                }
 129            }
 130
 131            // Clean up native resources always
 14132        }
 133
 134#region IKey implementation
 135
 136        public string DefaultEncryptionAlgorithm
 137        {
 6138            get { return RsaOaep.AlgorithmName; }
 139        }
 140
 141        public string DefaultKeyWrapAlgorithm
 142        {
 6143            get { return RsaOaep.AlgorithmName; }
 144        }
 145
 146        public string DefaultSignatureAlgorithm
 147        {
 2148            get { return Rs256.AlgorithmName; }
 149        }
 150
 151        public Task<byte[]> DecryptAsync( byte[] ciphertext, byte[] iv, byte[] authenticationData = null, byte[] authent
 152        {
 6153            if ( _csp == null )
 0154                throw new ObjectDisposedException( string.Format( "RsaKey {0} is disposed", Kid ) );
 155
 6156            if ( string.IsNullOrWhiteSpace( algorithm ) )
 2157                algorithm = DefaultEncryptionAlgorithm;
 158
 6159            if ( ciphertext == null || ciphertext.Length == 0 )
 0160                throw new ArgumentNullException( "ciphertext" );
 161
 6162            if ( iv != null )
 0163                throw new ArgumentException( "Initialization vector must be null", "iv" );
 164
 6165            if ( authenticationData != null )
 0166                throw new ArgumentException( "Authentication data must be null", "authenticationData" );
 167
 168            // TODO: Not available via the RSA class
 169            //if ( _csp.PublicOnly )
 170            //    throw new NotSupportedException( "Decrypt is not supported because no private key is available" );
 171
 6172            AsymmetricEncryptionAlgorithm algo = AlgorithmResolver.Default[algorithm] as AsymmetricEncryptionAlgorithm;
 173
 6174            if ( algo == null )
 0175                throw new NotSupportedException( "algorithm is not supported" );
 176
 6177            using ( var encryptor = algo.CreateDecryptor( _csp ) )
 178            {
 179                try
 180                {
 6181                    var result = encryptor.TransformFinalBlock( ciphertext, 0, ciphertext.Length );
 182
 6183                    return Task.FromResult( result );
 184                }
 185                catch ( Exception ex )
 186                {
 0187                    return TaskException.FromException<byte[]>( ex );
 188                }
 189            }
 6190        }
 191
 192        public Task<Tuple<byte[], byte[], string>> EncryptAsync( byte[] plaintext, byte[] iv = null, byte[] authenticati
 193        {
 6194            if ( _csp == null )
 0195                throw new ObjectDisposedException( string.Format( "RsaKey {0} is disposed", Kid ) );
 196
 6197            if ( string.IsNullOrWhiteSpace( algorithm ) )
 2198                algorithm = DefaultEncryptionAlgorithm;
 199
 6200            if ( plaintext == null || plaintext.Length == 0 )
 0201                throw new ArgumentNullException( "plaintext" );
 202
 6203            if ( iv != null )
 0204                throw new ArgumentException( "Initialization vector must be null", "iv" );
 205
 6206            if ( authenticationData != null )
 0207                throw new ArgumentException( "Authentication data must be null", "authenticationData" );
 208
 6209            AsymmetricEncryptionAlgorithm algo = AlgorithmResolver.Default[algorithm] as AsymmetricEncryptionAlgorithm;
 210
 6211            if ( algo == null )
 0212                throw new NotSupportedException( "algorithm is not supported" );
 213
 6214            using ( var encryptor = algo.CreateEncryptor( _csp ) )
 215            {
 216                try
 217                {
 6218                    var result = new Tuple<byte[], byte[], string>( encryptor.TransformFinalBlock( plaintext, 0, plainte
 219
 6220                    return Task.FromResult( result );
 221                }
 222                catch ( Exception ex )
 223                {
 0224                    return TaskException.FromException<Tuple<byte[], byte[], string>>( ex );
 225                }
 226            }
 6227        }
 228
 229        public Task<Tuple<byte[], string>> WrapKeyAsync( byte[] key, string algorithm = RsaOaep.AlgorithmName, Cancellat
 230        {
 6231            if ( _csp == null )
 0232                throw new ObjectDisposedException( string.Format( "RsaKey {0} is disposed", Kid ) );
 233
 6234            if ( string.IsNullOrWhiteSpace( algorithm ) )
 2235                algorithm = DefaultKeyWrapAlgorithm;
 236
 6237            if ( key == null || key.Length == 0 )
 0238                throw new ArgumentNullException( "key" );
 239
 6240            AsymmetricEncryptionAlgorithm algo = AlgorithmResolver.Default[algorithm] as AsymmetricEncryptionAlgorithm;
 241
 6242            if ( algo == null )
 0243                throw new NotSupportedException( "algorithm is not supported" );
 244
 6245            using ( var encryptor = algo.CreateEncryptor( _csp ) )
 246            {
 247                try
 248                {
 6249                    var result = new Tuple<byte[], string>( encryptor.TransformFinalBlock( key, 0, key.Length ), algorit
 250
 6251                    return Task.FromResult( result );
 252                }
 253                catch ( Exception ex )
 254                {
 0255                    return TaskException.FromException<Tuple<byte[], string>>( ex );
 256                }
 257            }
 6258        }
 259
 260        public Task<byte[]> UnwrapKeyAsync( byte[] encryptedKey, string algorithm = RsaOaep.AlgorithmName, CancellationT
 261        {
 6262            if ( _csp == null )
 0263                throw new ObjectDisposedException( string.Format( "RsaKey {0} is disposed", Kid ) );
 264
 6265            if ( string.IsNullOrWhiteSpace( algorithm ) )
 2266                algorithm = DefaultKeyWrapAlgorithm;
 267
 6268            if ( encryptedKey == null || encryptedKey.Length == 0 )
 0269                throw new ArgumentNullException( "encryptedKey" );
 270
 271            // TODO: Not available via the RSA class
 272            //if ( _csp.PublicOnly )
 273            //    throw new NotSupportedException( "UnwrapKey is not supported because no private key is available" );
 274
 6275            AsymmetricEncryptionAlgorithm algo = AlgorithmResolver.Default[algorithm] as AsymmetricEncryptionAlgorithm;
 276
 6277            if ( algo == null )
 0278                throw new NotSupportedException( "algorithm is not supported" );
 279
 6280            using ( var encryptor = algo.CreateDecryptor( _csp ) )
 281            {
 282                try
 283                {
 6284                    var result =  encryptor.TransformFinalBlock( encryptedKey, 0, encryptedKey.Length );
 285
 6286                    return Task.FromResult( result );
 287                }
 288                catch ( Exception ex )
 289                {
 0290                    return TaskException.FromException<byte[]>( ex );
 291                }
 292            }
 6293        }
 294
 295        public Task<Tuple<byte[], string>> SignAsync( byte[] digest, string algorithm, CancellationToken token = default
 296        {
 2297            if ( _csp == null )
 0298                throw new ObjectDisposedException( string.Format( "RsaKey {0} is disposed", Kid ) );
 299
 2300            if ( algorithm == null )
 0301                algorithm = DefaultSignatureAlgorithm;
 302
 2303            if ( digest == null )
 0304                throw new ArgumentNullException( "digest" );
 305
 306            // TODO: Not available via the RSA class
 307            //if ( _csp.PublicOnly )
 308            //    throw new NotSupportedException( "Sign is not supported because no private key is available" );
 309
 2310            AsymmetricSignatureAlgorithm algo      = AlgorithmResolver.Default[algorithm] as AsymmetricSignatureAlgorith
 2311            ISignatureTransform          transform = algo != null ? algo.CreateSignatureTransform( _csp ) : null;
 312
 2313            if ( algo == null || transform == null )
 0314                throw new NotSupportedException( "algorithm is not supported" );
 315
 316            try
 317            {
 2318                var result = new Tuple<byte[], string>( transform.Sign( digest ), algorithm );
 319
 2320                return Task.FromResult( result );
 321            }
 322            catch ( Exception ex )
 323            {
 0324                return TaskException.FromException<Tuple<byte[], string>>( ex );
 325            }
 2326        }
 327
 328        public Task<bool> VerifyAsync( byte[] digest, byte[] signature, string algorithm, CancellationToken token = defa
 329        {
 4330            if ( _csp == null )
 0331                throw new ObjectDisposedException( string.Format( "RsaKey {0} is disposed", Kid ) );
 332
 4333            if ( digest == null )
 0334                throw new ArgumentNullException( "digest" );
 335
 4336            if ( signature == null )
 0337                throw new ArgumentNullException( "signature" );
 338
 4339            if ( algorithm == null )
 0340                algorithm = DefaultSignatureAlgorithm;
 341
 4342            AsymmetricSignatureAlgorithm algo = AlgorithmResolver.Default[algorithm] as AsymmetricSignatureAlgorithm;
 4343            ISignatureTransform          transform = algo != null ? algo.CreateSignatureTransform( _csp ) : null;
 344
 4345            if ( algo == null || transform == null )
 0346                throw new NotSupportedException( "algorithm is not supported" );
 347
 348            try
 349            {
 4350                var result = transform.Verify( digest, signature );
 351
 4352                return Task.FromResult( result );
 353            }
 354            catch ( Exception ex )
 355            {
 0356                return TaskException.FromException<bool>( ex );
 357            }
 4358        }
 359
 360#endregion
 361    }
 362}