Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / rsacryptoserviceprovider.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>[....]</OWNER>
7 // 
8
9 //
10 // RSACryptoServiceProvider.cs
11 //
12 // CSP-based implementation of RSA
13 //
14
15 namespace System.Security.Cryptography {
16     using System;
17     using System.Globalization;
18     using System.IO;
19     using System.Security;
20     using System.Runtime.InteropServices;
21     using System.Runtime.CompilerServices;
22     using System.Runtime.Versioning;
23     using System.Security.Cryptography.X509Certificates;
24     using System.Security.Permissions;
25     using System.Diagnostics.Contracts;
26
27     // Object layout of the RSAParameters structure
28     internal class RSACspObject {
29         internal byte[] Exponent;
30         internal byte[] Modulus;
31         internal byte[] P;
32         internal byte[] Q;
33         internal byte[] DP;
34         internal byte[] DQ;
35         internal byte[] InverseQ;
36         internal byte[] D;
37     }
38
39     [System.Runtime.InteropServices.ComVisible(true)]
40     public sealed class RSACryptoServiceProvider : RSA
41         , ICspAsymmetricAlgorithm
42     {
43         private int _dwKeySize;
44         private CspParameters  _parameters;
45         private bool _randomKeyContainer;
46         [System.Security.SecurityCritical] // auto-generated
47         private SafeProvHandle _safeProvHandle;
48         [System.Security.SecurityCritical] // auto-generated
49         private SafeKeyHandle _safeKeyHandle;
50
51         private static volatile CspProviderFlags s_UseMachineKeyStore = 0;
52
53         //
54         // QCalls
55         //
56
57         [System.Security.SecurityCritical]  // auto-generated
58         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
59         [ResourceExposure(ResourceScope.None)]
60         [SuppressUnmanagedCodeSecurity]
61         private static extern void DecryptKey(SafeKeyHandle pKeyContext,
62                                               [MarshalAs(UnmanagedType.LPArray)] byte[] pbEncryptedKey,
63                                               int cbEncryptedKey,
64                                               [MarshalAs(UnmanagedType.Bool)] bool fOAEP,
65                                               ObjectHandleOnStack ohRetDecryptedKey);
66
67         [System.Security.SecurityCritical]  // auto-generated
68         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
69         [ResourceExposure(ResourceScope.None)]
70         [SuppressUnmanagedCodeSecurity]
71         private static extern void EncryptKey(SafeKeyHandle pKeyContext,
72                                               [MarshalAs(UnmanagedType.LPArray)] byte[] pbKey,
73                                               int cbKey,
74                                               [MarshalAs(UnmanagedType.Bool)] bool fOAEP,
75                                               ObjectHandleOnStack ohRetEncryptedKey);
76         
77         //
78         // public constructors
79         //
80
81         [System.Security.SecuritySafeCritical]  // auto-generated
82         [ResourceExposure(ResourceScope.None)]
83         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
84         public RSACryptoServiceProvider() 
85             : this(0, new CspParameters(Utils.DefaultRsaProviderType, null, null, s_UseMachineKeyStore), true) {
86         }
87
88         [System.Security.SecuritySafeCritical]  // auto-generated
89         [ResourceExposure(ResourceScope.None)]
90         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
91         public RSACryptoServiceProvider(int dwKeySize) 
92             : this(dwKeySize, new CspParameters(Utils.DefaultRsaProviderType, null, null, s_UseMachineKeyStore), false) {
93         }
94
95         [System.Security.SecuritySafeCritical]  // auto-generated
96         public RSACryptoServiceProvider(CspParameters parameters) 
97             : this(0, parameters, true) {
98         }
99
100         [System.Security.SecuritySafeCritical]  // auto-generated
101         public RSACryptoServiceProvider(int dwKeySize, CspParameters parameters)
102             : this(dwKeySize, parameters, false) {
103         }
104
105         //
106         // private methods
107         //
108
109         [System.Security.SecurityCritical]  // auto-generated
110         private RSACryptoServiceProvider(int dwKeySize, CspParameters parameters, bool useDefaultKeySize) {
111             if (dwKeySize < 0)
112                 throw new ArgumentOutOfRangeException("dwKeySize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
113             Contract.EndContractBlock();
114
115             _parameters = Utils.SaveCspParameters(CspAlgorithmType.Rsa, parameters, s_UseMachineKeyStore, ref _randomKeyContainer);
116
117                 LegalKeySizesValue = new KeySizes[] { new KeySizes(384, 16384, 8) };
118             _dwKeySize = useDefaultKeySize ? 1024 : dwKeySize;
119
120             // If this is not a random container we generate, create it eagerly 
121             // in the constructor so we can report any errors now.
122             if (!_randomKeyContainer 
123 #if !FEATURE_CORECLR                
124                 || Environment.GetCompatibilityFlag(CompatibilityFlag.EagerlyGenerateRandomAsymmKeys)
125 #endif //!FEATURE_CORECLR
126                 )
127                 GetKeyPair();
128         }
129
130         [System.Security.SecurityCritical]  // auto-generated
131         private void GetKeyPair () {
132             if (_safeKeyHandle == null) {
133                 lock (this) {
134                     if (_safeKeyHandle == null) {
135                         // We only attempt to generate a random key on desktop runtimes because the CoreCLR
136                         // RSA surface area is limited to simply verifying signatures.  Since generating a
137                         // random key to verify signatures will always lead to failure (unless we happend to
138                         // win the lottery and randomly generate the signing key ...), there is no need
139                         // to add this functionality to CoreCLR at this point.
140                         Utils.GetKeyPairHelper(CspAlgorithmType.Rsa, _parameters, _randomKeyContainer, _dwKeySize, ref _safeProvHandle, ref _safeKeyHandle);
141                     }
142                 }
143             }
144         }
145
146         [System.Security.SecuritySafeCritical] // overrides public transparent member
147         protected override void Dispose(bool disposing)
148         {
149             base.Dispose(disposing);
150
151             if (_safeKeyHandle != null && !_safeKeyHandle.IsClosed)
152                 _safeKeyHandle.Dispose();
153             if (_safeProvHandle != null && !_safeProvHandle.IsClosed)
154                 _safeProvHandle.Dispose();
155         }
156
157         //
158         // public properties
159         //
160
161         [System.Runtime.InteropServices.ComVisible(false)]
162         public bool PublicOnly {
163             [System.Security.SecuritySafeCritical]  // auto-generated
164             get {
165                 GetKeyPair();
166                 byte[] publicKey = (byte[]) Utils._GetKeyParameter(_safeKeyHandle, Constants.CLR_PUBLICKEYONLY);
167                 return (publicKey[0] == 1);
168             }
169         }
170
171         [System.Runtime.InteropServices.ComVisible(false)]
172         public CspKeyContainerInfo CspKeyContainerInfo {
173             [System.Security.SecuritySafeCritical]  // auto-generated
174             get {
175                 GetKeyPair();
176                 return new CspKeyContainerInfo(_parameters, _randomKeyContainer);
177             }
178         }
179
180         public override int KeySize {
181             [System.Security.SecuritySafeCritical]  // auto-generated
182             get {
183                 GetKeyPair();
184                 byte[] keySize = (byte[]) Utils._GetKeyParameter(_safeKeyHandle, Constants.CLR_KEYLEN);
185                 _dwKeySize = (keySize[0] | (keySize[1] << 8) | (keySize[2] << 16) | (keySize[3] << 24));
186                 return _dwKeySize;
187             }
188         }
189
190         public override string KeyExchangeAlgorithm {
191             get {
192                 if (_parameters.KeyNumber == Constants.AT_KEYEXCHANGE)
193                     return "RSA-PKCS1-KeyEx";
194                 return null;
195             }
196         }
197
198         public override string SignatureAlgorithm {
199             get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }
200         }
201
202         public static bool UseMachineKeyStore {
203             get { return (s_UseMachineKeyStore == CspProviderFlags.UseMachineKeyStore); }
204             set { s_UseMachineKeyStore = (value ? CspProviderFlags.UseMachineKeyStore : 0); }
205         }
206
207         public bool PersistKeyInCsp {
208             [System.Security.SecuritySafeCritical]  // auto-generated
209             get {
210                 if (_safeProvHandle == null) {
211                     lock (this) {
212                         if (_safeProvHandle == null)
213                             _safeProvHandle = Utils.CreateProvHandle(_parameters, _randomKeyContainer);
214                     }
215                 }
216                 return Utils.GetPersistKeyInCsp(_safeProvHandle); 
217             }
218             [System.Security.SecuritySafeCritical]  // auto-generated
219             set {
220                 bool oldPersistKeyInCsp = this.PersistKeyInCsp;
221                 if (value == oldPersistKeyInCsp)
222                     return;
223
224                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
225                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
226                     if (!value) {
227                         KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Delete);
228                         kp.AccessEntries.Add(entry);
229                     } else {
230                         KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Create);
231                         kp.AccessEntries.Add(entry);
232                     }
233                     kp.Demand();
234                 }
235
236                 Utils.SetPersistKeyInCsp(_safeProvHandle, value);
237             }
238         }
239
240         //
241         // public methods
242         //
243
244         [System.Security.SecuritySafeCritical]  // auto-generated
245         public override RSAParameters ExportParameters (bool includePrivateParameters) {
246             GetKeyPair();
247             if (includePrivateParameters) {
248                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
249                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
250                     KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Export);
251                     kp.AccessEntries.Add(entry);
252                     kp.Demand();
253                 }
254             }
255             RSACspObject rsaCspObject = new RSACspObject();
256             int blobType = includePrivateParameters ? Constants.PRIVATEKEYBLOB : Constants.PUBLICKEYBLOB;
257             // _ExportKey will check for failures and throw an exception
258             Utils._ExportKey(_safeKeyHandle, blobType, rsaCspObject);
259             return RSAObjectToStruct(rsaCspObject);
260         }
261
262 #if FEATURE_LEGACYNETCFCRYPTO
263         [System.Security.SecurityCritical]  
264 #else
265         [System.Security.SecuritySafeCritical]  // auto-generated
266 #endif
267         [System.Runtime.InteropServices.ComVisible(false)]
268         public byte[] ExportCspBlob (bool includePrivateParameters) {
269             GetKeyPair();
270             return Utils.ExportCspBlobHelper(includePrivateParameters, _parameters, _safeKeyHandle);
271         }
272
273         [System.Security.SecuritySafeCritical]  // auto-generated
274         public override void ImportParameters(RSAParameters parameters) {
275             // Free the current key handle
276             if (_safeKeyHandle != null && !_safeKeyHandle.IsClosed) {
277                 _safeKeyHandle.Dispose();
278                 _safeKeyHandle = null;
279             }
280
281             RSACspObject rsaCspObject = RSAStructToObject(parameters);
282             _safeKeyHandle = SafeKeyHandle.InvalidHandle;
283
284             if (IsPublic(parameters)) {
285                 // Use our CRYPT_VERIFYCONTEXT handle, CRYPT_EXPORTABLE is not applicable to public only keys, so pass false
286                 Utils._ImportKey(Utils.StaticProvHandle, Constants.CALG_RSA_KEYX, (CspProviderFlags) 0, rsaCspObject, ref _safeKeyHandle);
287             } else {
288                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
289                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
290                     KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Import);
291                     kp.AccessEntries.Add(entry);
292                     kp.Demand();
293                 }
294                 if (_safeProvHandle == null)
295                     _safeProvHandle = Utils.CreateProvHandle(_parameters, _randomKeyContainer);
296                 // Now, import the key into the CSP; _ImportKey will check for failures.
297                 Utils._ImportKey(_safeProvHandle, Constants.CALG_RSA_KEYX, _parameters.Flags, rsaCspObject, ref _safeKeyHandle);
298             }
299         }
300
301 #if FEATURE_LEGACYNETCFCRYPTO
302         [System.Security.SecurityCritical]  
303 #else
304         [System.Security.SecuritySafeCritical]  // auto-generated
305 #endif
306         [System.Runtime.InteropServices.ComVisible(false)]
307         public void ImportCspBlob (byte[] keyBlob) {
308             Utils.ImportCspBlobHelper(CspAlgorithmType.Rsa, keyBlob, IsPublic(keyBlob), ref _parameters, _randomKeyContainer, ref _safeProvHandle, ref _safeKeyHandle);
309         }
310
311         public byte[] SignData(Stream inputStream, Object halg) {
312             int calgHash = Utils.ObjToAlgId(halg, OidGroup.HashAlgorithm);
313             HashAlgorithm hash = Utils.ObjToHashAlgorithm(halg);
314             byte[] hashVal = hash.ComputeHash(inputStream);
315             return SignHash(hashVal, calgHash);
316         }
317
318         public byte[] SignData(byte[] buffer, Object halg) {
319             int calgHash = Utils.ObjToAlgId(halg, OidGroup.HashAlgorithm);
320             HashAlgorithm hash = Utils.ObjToHashAlgorithm(halg);
321             byte[] hashVal = hash.ComputeHash(buffer);
322             return SignHash(hashVal, calgHash);
323         }
324
325         public byte[] SignData(byte[] buffer, int offset, int count, Object halg) {
326             int calgHash = Utils.ObjToAlgId(halg, OidGroup.HashAlgorithm);
327             HashAlgorithm hash = Utils.ObjToHashAlgorithm(halg);
328             byte[] hashVal = hash.ComputeHash(buffer, offset, count);
329             return SignHash(hashVal, calgHash);
330         }
331
332         public bool VerifyData(byte[] buffer, Object halg, byte[] signature) {
333             int calgHash = Utils.ObjToAlgId(halg, OidGroup.HashAlgorithm);
334             HashAlgorithm hash = Utils.ObjToHashAlgorithm(halg);
335             byte[] hashVal = hash.ComputeHash(buffer);
336             return VerifyHash(hashVal, calgHash, signature);
337         }
338
339         public byte[] SignHash(byte[] rgbHash, string str) {
340             if (rgbHash == null)
341                 throw new ArgumentNullException("rgbHash");
342             Contract.EndContractBlock();
343             if (PublicOnly)
344                 throw new CryptographicException(Environment.GetResourceString("Cryptography_CSP_NoPrivateKey"));
345
346             int calgHash = X509Utils.NameOrOidToAlgId(str, OidGroup.HashAlgorithm);
347             return SignHash(rgbHash, calgHash);
348         }
349
350         [SecuritySafeCritical]
351         internal byte[] SignHash(byte[] rgbHash, int calgHash) {
352             Contract.Requires(rgbHash != null);
353
354             GetKeyPair();
355             if (!CspKeyContainerInfo.RandomlyGenerated) {
356                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
357                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
358                     KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Sign);
359                     kp.AccessEntries.Add(entry);
360                     kp.Demand();
361                 }
362             }
363             return Utils.SignValue(_safeKeyHandle, _parameters.KeyNumber, Constants.CALG_RSA_SIGN, calgHash, rgbHash);
364         }
365
366         public bool VerifyHash(byte[] rgbHash, string str, byte[] rgbSignature) {
367             if (rgbHash == null)
368                 throw new ArgumentNullException("rgbHash");
369             if (rgbSignature == null)
370                 throw new ArgumentNullException("rgbSignature");
371             Contract.EndContractBlock();
372
373             int calgHash = X509Utils.NameOrOidToAlgId(str, OidGroup.HashAlgorithm);
374             return VerifyHash(rgbHash, calgHash, rgbSignature);
375         }
376
377         [SecuritySafeCritical]
378         internal bool VerifyHash(byte[] rgbHash, int calgHash, byte[] rgbSignature) {
379             Contract.Requires(rgbHash != null);
380             Contract.Requires(rgbSignature != null);
381
382             GetKeyPair();
383
384             return Utils.VerifySign(_safeKeyHandle, Constants.CALG_RSA_SIGN, calgHash, rgbHash, rgbSignature);
385         }
386
387         /// <summary>
388         ///     Encrypt raw data, generally used for encrypting symmetric key material.
389         /// </summary>
390         /// <remarks>
391         ///     This method can only encrypt (keySize - 88 bits) of data, so should not be used for encrypting
392         ///     arbitrary byte arrays. Instead, encrypt a symmetric key with this method, and use the symmetric
393         ///     key to encrypt the sensitive data.
394         /// </remarks>
395         /// <param name="rgb">raw data to encryt</param>
396         /// <param name="fOAEP">true to use OAEP padding (PKCS #1 v2), false to use PKCS #1 type 2 padding</param>
397         /// <returns>Encrypted key</returns>
398         [System.Security.SecuritySafeCritical]  // auto-generated
399         public byte[] Encrypt(byte[] rgb, bool fOAEP) {
400             if (rgb == null)
401                 throw new ArgumentNullException("rgb");
402             Contract.EndContractBlock();
403
404             GetKeyPair();
405
406             byte[] encryptedKey = null;
407             EncryptKey(_safeKeyHandle, rgb, rgb.Length, fOAEP, JitHelpers.GetObjectHandleOnStack(ref encryptedKey));
408             return encryptedKey;
409         }
410
411         /// <summary>
412         ///     Decrypt raw data, generally used for decrypting symmetric key material
413         /// </summary>
414         /// <param name="rgb">encrypted data</param>
415         /// <param name="fOAEP">true to use OAEP padding (PKCS #1 v2), false to use PKCS #1 type 2 padding</param>
416         /// <returns>decrypted data</returns>
417         [System.Security.SecuritySafeCritical]  // auto-generated
418         public byte [] Decrypt(byte[] rgb, bool fOAEP) {
419             if (rgb == null)
420                 throw new ArgumentNullException("rgb");
421             Contract.EndContractBlock();
422
423             GetKeyPair();
424
425             // size check -- must be at most the modulus size
426             if (rgb.Length > (KeySize / 8))
427                 throw new CryptographicException(Environment.GetResourceString("Cryptography_Padding_DecDataTooBig", KeySize / 8));
428
429             if (!CspKeyContainerInfo.RandomlyGenerated) {
430                 if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
431                     KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
432                     KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Decrypt);
433                     kp.AccessEntries.Add(entry);
434                     kp.Demand();
435                 }
436             }
437
438             byte[] decryptedKey = null;
439             DecryptKey(_safeKeyHandle, rgb, rgb.Length, fOAEP, JitHelpers.GetObjectHandleOnStack(ref decryptedKey));
440             return decryptedKey;
441         }
442
443         public override byte[] DecryptValue(byte[] rgb) {
444             throw new NotSupportedException(Environment.GetResourceString("NotSupported_Method"));
445         }
446
447         public override byte[] EncryptValue(byte[] rgb) {
448             throw new NotSupportedException(Environment.GetResourceString("NotSupported_Method"));
449         }
450
451         // 
452         // private static methods
453         //
454         
455         private static RSAParameters RSAObjectToStruct (RSACspObject rsaCspObject) {
456             RSAParameters rsaParams = new RSAParameters();
457             rsaParams.Exponent = rsaCspObject.Exponent;
458             rsaParams.Modulus = rsaCspObject.Modulus;
459             rsaParams.P = rsaCspObject.P;
460             rsaParams.Q = rsaCspObject.Q;
461             rsaParams.DP = rsaCspObject.DP;
462             rsaParams.DQ = rsaCspObject.DQ;
463             rsaParams.InverseQ = rsaCspObject.InverseQ;
464             rsaParams.D = rsaCspObject.D;
465             return rsaParams;
466         }
467
468         private static RSACspObject RSAStructToObject (RSAParameters rsaParams) {
469             RSACspObject rsaCspObject = new RSACspObject();
470             rsaCspObject.Exponent = rsaParams.Exponent;
471             rsaCspObject.Modulus = rsaParams.Modulus;
472             rsaCspObject.P = rsaParams.P;
473             rsaCspObject.Q = rsaParams.Q;
474             rsaCspObject.DP = rsaParams.DP;
475             rsaCspObject.DQ = rsaParams.DQ;
476             rsaCspObject.InverseQ = rsaParams.InverseQ;
477             rsaCspObject.D = rsaParams.D;
478             return rsaCspObject;
479         }
480
481         // find whether an RSA key blob is public.
482         private static bool IsPublic (byte[] keyBlob) {
483             if (keyBlob == null)
484                 throw new ArgumentNullException("keyBlob");
485             Contract.EndContractBlock();
486
487             // The CAPI RSA public key representation consists of the following sequence:
488             //  - BLOBHEADER
489             //  - RSAPUBKEY
490
491             // The first should be PUBLICKEYBLOB and magic should be RSA_PUB_MAGIC "RSA1"
492             if (keyBlob[0] != Constants.PUBLICKEYBLOB)
493                 return false;
494
495             if (keyBlob[11] != 0x31 || keyBlob[10] != 0x41 || keyBlob[9] != 0x53 || keyBlob[8] != 0x52)
496                 return false;
497
498             return true;
499         }
500
501         // Since P is required, we will assume its presence is synonymous to a private key.
502         private static bool IsPublic(RSAParameters rsaParams) {
503             return (rsaParams.P == null);
504         }
505         
506         //
507         // Adapt new RSA abstraction to legacy RSACryptoServiceProvider surface area.
508         //
509
510         // NOTE: For the new API, we go straight to CAPI for fixed set of hash algorithms and don't use crypto config here.
511         //
512         // Reasons:
513         //       1. We're moving away from crypto config and we won't have it when porting to .NET Core
514         //
515         //       2. It's slow to lookup and slow to use as the base HashAlgorithm adds considerable overhead 
516         //          (redundant defensive copy + double-initialization for the single-use case).
517         //      
518
519         [SecuritySafeCritical]
520         protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) {
521             // we're sealed and the base should have checked this already
522             Contract.Assert(data != null);
523             Contract.Assert(offset >= 0 && offset <= data.Length);
524             Contract.Assert(count >= 0 && count <= data.Length);
525             Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
526
527             using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) {
528                 Utils.HashData(hashHandle, data, offset, count);
529                 return Utils.EndHash(hashHandle);
530             }
531         }
532
533         [SecuritySafeCritical]
534         protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) {
535             // we're sealed and the base should have checked this already
536             Contract.Assert(data != null);
537             Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
538
539             using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) {
540                 // Read the data 4KB at a time, providing similar read characteristics to a standard HashAlgorithm
541                 byte[] buffer = new byte[4096];
542                 int bytesRead = 0;
543                 do {
544                     bytesRead = data.Read(buffer, 0, buffer.Length);
545                     if (bytesRead > 0) {   
546                         Utils.HashData(hashHandle, buffer, 0, bytesRead);
547                     }
548                 } while (bytesRead > 0);
549
550                 return Utils.EndHash(hashHandle);
551             }
552         }
553         
554         private static int GetAlgorithmId(HashAlgorithmName hashAlgorithm) {
555             switch (hashAlgorithm.Name) {
556                 case "MD5":
557                     return Constants.CALG_MD5;
558                 case "SHA1":
559                     return Constants.CALG_SHA1;
560                 case "SHA256":
561                     return Constants.CALG_SHA_256;
562                 case "SHA384":
563                     return Constants.CALG_SHA_384;
564                 case "SHA512":
565                     return Constants.CALG_SHA_512;
566                 default:
567                     throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name));
568             }
569         }
570
571         public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) {
572             if (data == null) {
573                 throw new ArgumentNullException("data");
574             }
575             if (padding == null) {
576                 throw new ArgumentNullException("padding");
577             }
578
579             if (padding == RSAEncryptionPadding.Pkcs1) {
580                 return Encrypt(data, fOAEP: false);
581             } else if (padding == RSAEncryptionPadding.OaepSHA1) {
582                 return Encrypt(data, fOAEP: true);
583             } else {
584                 throw PaddingModeNotSupported();
585             }
586         }
587
588         public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) {
589             if (data == null) {
590                 throw new ArgumentNullException("data");
591             }
592             if (padding == null) {
593                 throw new ArgumentNullException("padding");
594             }
595
596             if (padding == RSAEncryptionPadding.Pkcs1) {
597                 return Decrypt(data, fOAEP: false);
598             } else if (padding == RSAEncryptionPadding.OaepSHA1) {
599                 return Decrypt(data, fOAEP: true);
600             } else {
601                 throw PaddingModeNotSupported();
602             }
603         }
604
605         public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) {
606             if (hash == null) {
607                 throw new ArgumentNullException("hash");
608             }
609             if (String.IsNullOrEmpty(hashAlgorithm.Name)) {
610                 throw HashAlgorithmNameNullOrEmpty();
611             }
612             if (padding == null) {
613                 throw new ArgumentNullException("padding");
614             }
615             if (padding != RSASignaturePadding.Pkcs1) {
616                 throw PaddingModeNotSupported();
617             }
618
619             return SignHash(hash, GetAlgorithmId(hashAlgorithm));
620         }
621
622         public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) {
623             if (hash == null) {
624                 throw new ArgumentNullException("hash");
625             }
626             if (signature == null) {
627                 throw new ArgumentNullException("signature");
628             }
629             if (String.IsNullOrEmpty(hashAlgorithm.Name)) {
630                 throw HashAlgorithmNameNullOrEmpty();
631             }
632             if (padding == null) {
633                 throw new ArgumentNullException("padding");
634             }
635             if (padding != RSASignaturePadding.Pkcs1) {
636                 throw PaddingModeNotSupported();
637             }
638
639             return VerifyHash(hash, GetAlgorithmId(hashAlgorithm), signature);
640         }
641
642         private static Exception PaddingModeNotSupported() {
643             return new CryptographicException(Environment.GetResourceString("Cryptography_InvalidPaddingMode"));
644         }
645     }
646 }