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