Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.IdentityModel / System / IdentityModel / CryptoHelper.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.IdentityModel
6 {
7     using System.Collections.Generic;
8     using System.IdentityModel.Tokens;
9     using System.Reflection;
10     using System.Security.Cryptography;
11     using System.Security.Cryptography.X509Certificates;
12     using System.Security.Cryptography.Xml;
13     using System.ServiceModel.Security;
14
15     static class CryptoHelper
16     {
17         static byte[] emptyBuffer;
18         static RandomNumberGenerator random;
19         static Rijndael rijndael;
20         static TripleDES tripleDES;
21
22         static Dictionary<string, Func<object>> algorithmDelegateDictionary = new Dictionary<string, Func<object>>();
23         static object AlgorithmDictionaryLock = new object();
24         public const int WindowsVistaMajorNumber = 6;
25         const string SHAString = "SHA";
26         const string SHA1String = "SHA1";
27         const string SHA256String = "SHA256";
28         const string SystemSecurityCryptographySha1String = "System.Security.Cryptography.SHA1";
29
30
31         /// <summary>
32         /// The helper class which helps user to compute the combined entropy as well as the session
33         /// key
34         /// </summary>
35         public static class KeyGenerator
36         {
37             static RandomNumberGenerator _random = CryptoHelper.RandomNumberGenerator;
38
39             //
40             // 1/(2^32) keys will be weak.  20 random keys will never happen by chance without the RNG being messed up.
41             //
42             const int _maxKeyIterations = 20;
43             /// <summary>
44             /// Computes the session key based on PSHA1 algorithm.
45             /// </summary>
46             /// <param name="requestorEntropy">The entropy from the requestor side.</param>
47             /// <param name="issuerEntropy">The entropy from the token issuer side.</param>
48             /// <param name="keySizeInBits">The desired key size in bits.</param>
49             /// <returns>The computed session key.</returns>
50             public static byte[] ComputeCombinedKey( byte[] requestorEntropy, byte[] issuerEntropy, int keySizeInBits )
51             {
52                 if ( null == requestorEntropy )
53                 {
54                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "requestorEntropy" );
55                 }
56
57                 if ( null == issuerEntropy )
58                 {
59                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "issuerEntropy" );
60                 }
61
62                 int keySizeInBytes = ValidateKeySizeInBytes( keySizeInBits );
63
64                 byte[] key = new byte[keySizeInBytes]; // Final key
65
66                 // The symmetric key generation chosen is 
67                 // http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1
68                 // which per the WS-Trust specification is defined as follows:
69                 //
70                 //   The key is computed using P_SHA1
71                 //   from the TLS specification to generate
72                 //   a bit stream using entropy from both
73                 //   sides. The exact form is:
74                 //
75                 //   key = P_SHA1 (EntREQ, EntRES)
76                 //
77                 // where P_SHA1 is defined per http://www.ietf.org/rfc/rfc2246.txt 
78                 // and EntREQ is the entropy supplied by the requestor and EntRES 
79                 // is the entrophy supplied by the issuer.
80                 //
81                 // From http://www.faqs.org/rfcs/rfc2246.html:
82                 // 
83                 // 8<------------------------------------------------------------>8
84                 // First, we define a data expansion function, P_hash(secret, data)
85                 // which uses a single hash function to expand a secret and seed 
86                 // into an arbitrary quantity of output:
87                 // 
88                 // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
89                 //                        HMAC_hash(secret, A(2) + seed) +
90                 //                        HMAC_hash(secret, A(3) + seed) + ...
91                 //
92                 // Where + indicates concatenation.
93                 //
94                 // A() is defined as:
95                 //   A(0) = seed
96                 //   A(i) = HMAC_hash(secret, A(i-1))
97                 //
98                 // P_hash can be iterated as many times as is necessary to produce
99                 // the required quantity of data. For example, if P_SHA-1 was 
100                 // being used to create 64 bytes of data, it would have to be 
101                 // iterated 4 times (through A(4)), creating 80 bytes of output 
102                 // data; the last 16 bytes of the final iteration would then be 
103                 // discarded, leaving 64 bytes of output data.
104                 // 8<------------------------------------------------------------>8
105
106                 // Note that requestorEntrophy is considered the 'secret'.
107                 using ( KeyedHashAlgorithm kha = CryptoHelper.NewHmacSha1KeyedHashAlgorithm() )
108                 {
109                     kha.Key = requestorEntropy;
110
111                     byte[] a = issuerEntropy; // A(0), the 'seed'.
112                     byte[] b = new byte[kha.HashSize / 8 + a.Length]; // Buffer for A(i) + seed
113                     byte[] result = null;
114
115                     try
116                     {
117
118                         for ( int i = 0; i < keySizeInBytes; )
119                         {
120                             // Calculate A(i+1).                
121                             kha.Initialize();
122                             a = kha.ComputeHash( a );
123
124                             // Calculate A(i) + seed
125                             a.CopyTo( b, 0 );
126                             issuerEntropy.CopyTo( b, a.Length );
127                             kha.Initialize();
128                             result = kha.ComputeHash( b );
129
130                             for ( int j = 0; j < result.Length; j++ )
131                             {
132                                 if ( i < keySizeInBytes )
133                                 {
134                                     key[i++] = result[j];
135                                 }
136                                 else
137                                 {
138                                     break;
139                                 }
140                             }
141                         }
142                     }
143                     catch
144                     {
145                         Array.Clear( key, 0, key.Length );
146                         throw;
147                     }
148                     finally
149                     {
150                         if ( result != null )
151                         {
152                             Array.Clear( result, 0, result.Length );
153                         }
154
155                         Array.Clear( b, 0, b.Length );
156
157                         kha.Clear();
158                     }
159                 }
160
161                 return key;
162             }
163
164             /// <summary>
165             /// Generates a symmetric key with a given size.
166             /// </summary>
167             /// <remarks>This function should not be used to generate DES keys because it does not perform an IsWeakKey check.
168             /// Use GenerateDESKey() instead.</remarks>
169             /// <param name="keySizeInBits">The key size in bits.</param>
170             /// <returns>The symmetric key.</returns>
171             /// <exception cref="ArgumentException">When keySizeInBits is not a whole number of bytes.</exception>
172             public static byte[] GenerateSymmetricKey( int keySizeInBits )
173             {
174                 int keySizeInBytes = ValidateKeySizeInBytes( keySizeInBits );
175
176                 byte[] key = new byte[keySizeInBytes];
177
178                 CryptoHelper.GenerateRandomBytes( key );
179
180                 return key;
181             }
182
183             /// <summary>
184             /// Generates a combined-entropy key.
185             /// </summary>
186             /// <remarks>This function should not be used to generate DES keys because it does not perform an IsWeakKey check.
187             /// Use GenerateDESKey() instead.</remarks>
188             /// <param name="keySizeInBits">The key size in bits.</param>
189             /// <param name="senderEntropy">Requestor's entropy.</param>
190             /// <param name="receiverEntropy">The issuer's entropy.</param>
191             /// <returns>The computed symmetric key based on PSHA1 algorithm.</returns>
192             /// <exception cref="ArgumentException">When keySizeInBits is not a whole number of bytes.</exception>
193             public static byte[] GenerateSymmetricKey( int keySizeInBits, byte[] senderEntropy, out byte[] receiverEntropy )
194             {
195                 if ( senderEntropy == null )
196                 {
197                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "senderEntropy" );
198                 }
199
200                 int keySizeInBytes = ValidateKeySizeInBytes( keySizeInBits );
201
202                 //
203                 // Generate proof key using sender entropy and receiver entropy
204                 //
205                 receiverEntropy = new byte[keySizeInBytes];
206
207                 _random.GetNonZeroBytes( receiverEntropy );
208
209                 return ComputeCombinedKey( senderEntropy, receiverEntropy, keySizeInBits );
210             }
211
212             /// <summary>
213             /// Generates a symmetric key for use with the DES or Triple-DES algorithms.  This function will always return a key that is
214             /// not considered weak by TripleDES.IsWeakKey().
215             /// </summary>
216             /// <param name="keySizeInBits">The key size in bits.</param>
217             /// <returns>The symmetric key.</returns>
218             /// <exception cref="ArgumentException">When keySizeInBits is not a proper DES key size.</exception>
219             public static byte[] GenerateDESKey( int keySizeInBits )
220             {
221                 int keySizeInBytes = ValidateKeySizeInBytes( keySizeInBits );
222
223                 byte[] key = new byte[keySizeInBytes];
224                 int tries = 0;
225
226                 do
227                 {
228                     if ( tries > _maxKeyIterations )
229                     {
230                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new CryptographicException( SR.GetString( SR.ID6048, _maxKeyIterations ) ) );
231                     }
232
233                     CryptoHelper.GenerateRandomBytes( key );
234                     ++tries;
235
236                 } while ( TripleDES.IsWeakKey( key ) );
237
238                 return key;
239             }
240
241             /// <summary>
242             /// Generates a combined-entropy key for use with the DES or Triple-DES algorithms.  This function will always return a key that is
243             /// not considered weak by TripleDES.IsWeakKey().
244             /// </summary>
245             /// <param name="keySizeInBits">The key size in bits.</param>
246             /// <param name="senderEntropy">Requestor's entropy.</param>
247             /// <param name="receiverEntropy">The issuer's entropy.</param>
248             /// <returns>The computed symmetric key based on PSHA1 algorithm.</returns>
249             /// <exception cref="ArgumentException">When keySizeInBits is not a proper DES key size.</exception>
250             public static byte[] GenerateDESKey( int keySizeInBits, byte[] senderEntropy, out byte[] receiverEntropy )
251             {
252                 int keySizeInBytes = ValidateKeySizeInBytes( keySizeInBits );
253
254                 byte[] key = new byte[keySizeInBytes];
255                 int tries = 0;
256
257                 do
258                 {
259                     if ( tries > _maxKeyIterations )
260                     {
261                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new CryptographicException( SR.GetString( SR.ID6048, _maxKeyIterations ) ) );
262                     }
263
264                     receiverEntropy = new byte[keySizeInBytes];
265                     _random.GetNonZeroBytes( receiverEntropy );
266                     key = ComputeCombinedKey( senderEntropy, receiverEntropy, keySizeInBits );
267                     ++tries;
268
269                 } while ( TripleDES.IsWeakKey( key ) );
270
271                 return key;
272             }
273
274             static int ValidateKeySizeInBytes( int keySizeInBits )
275             {
276                 int keySizeInBytes = keySizeInBits / 8;
277
278                 if ( keySizeInBits <= 0 )
279                 {
280                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException( "keySizeInBits", SR.GetString( SR.ID6033, keySizeInBits ) ) );
281                 }
282                 else if ( keySizeInBytes * 8 != keySizeInBits )
283                 {
284                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentException( SR.GetString( SR.ID6002, keySizeInBits ), "keySizeInBits" ) );
285                 }
286
287                 return keySizeInBytes;
288             }
289
290             /// <summary>
291             /// Gets a security key identifier which contains the BinarySecretKeyIdentifierClause or 
292             /// EncryptedKeyIdentifierClause if the wrapping credentials is available.
293             /// </summary>
294             public static SecurityKeyIdentifier GetSecurityKeyIdentifier(byte[] secret, EncryptingCredentials wrappingCredentials)
295             {
296                 if (secret == null)
297                 {
298                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("secret");
299                 }
300
301                 if (secret.Length == 0)
302                 {
303                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("secret", SR.GetString(SR.ID6031));
304                 }
305
306                 if (wrappingCredentials == null || wrappingCredentials.SecurityKey == null)
307                 {
308                     //
309                     // BinarySecret case
310                     //
311                     return new SecurityKeyIdentifier(new BinarySecretKeyIdentifierClause(secret));
312                 }
313                 else
314                 {
315                     //
316                     // EncryptedKey case
317                     //
318                     byte[] wrappedKey = wrappingCredentials.SecurityKey.EncryptKey(wrappingCredentials.Algorithm, secret);
319
320                     return new SecurityKeyIdentifier(new EncryptedKeyIdentifierClause(wrappedKey, wrappingCredentials.Algorithm, wrappingCredentials.SecurityKeyIdentifier));
321                 }
322             }
323
324         }
325
326         /// <summary>
327         /// Provides an integer-domain mathematical operation for 
328         /// Ceiling( dividend / divisor ). 
329         /// </summary>
330         /// <param name="dividend"></param>
331         /// <param name="divisor"></param>
332         /// <returns></returns>
333         public static int CeilingDivide( int dividend, int divisor )
334         {
335             int remainder, quotient;
336
337             remainder = dividend % divisor;
338             quotient = dividend / divisor;
339
340             if ( remainder > 0 )
341             {
342                 quotient++;
343             }
344
345             return quotient;
346         }
347
348         internal static byte[] EmptyBuffer
349         {
350             get
351             {
352                 if (emptyBuffer == null)
353                 {
354                     byte[] tmp = new byte[0];
355                     emptyBuffer = tmp;
356                 }
357                 return emptyBuffer;
358             }
359         }
360
361         internal static Rijndael Rijndael
362         {
363             get
364             {
365                 if (rijndael == null)
366                 {
367                     Rijndael tmp = SecurityUtils.RequiresFipsCompliance ? (Rijndael)new RijndaelCryptoServiceProvider() : new RijndaelManaged();
368                     tmp.Padding = PaddingMode.ISO10126;
369                     rijndael = tmp;
370                 }
371                 return rijndael;
372             }
373         }
374
375         internal static TripleDES TripleDES
376         {
377             get
378             {
379                 if (tripleDES == null)
380                 {
381                     TripleDESCryptoServiceProvider tmp = new TripleDESCryptoServiceProvider();
382                     tmp.Padding = PaddingMode.ISO10126;
383                     tripleDES = tmp;
384                 }
385                 return tripleDES;
386             }
387         }
388
389         internal static RandomNumberGenerator RandomNumberGenerator
390         {
391             get
392             {
393                 if (random == null)
394                 {
395                     random = new RNGCryptoServiceProvider();
396                 }
397                 return random;
398             }
399         }
400
401         /// <summary>
402         /// Creates the default encryption algorithm.
403         /// </summary>
404         /// <returns>A SymmetricAlgorithm instance that must be disposed by the caller after use.</returns>
405         internal static SymmetricAlgorithm NewDefaultEncryption()
406         {
407             return GetSymmetricAlgorithm(null, SecurityAlgorithms.DefaultEncryptionAlgorithm );
408         }
409
410         internal static HashAlgorithm NewSha1HashAlgorithm()
411         {
412             return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest);
413         }
414
415         internal static HashAlgorithm NewSha256HashAlgorithm()
416         {
417             return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest);
418         }
419
420         internal static KeyedHashAlgorithm NewHmacSha1KeyedHashAlgorithm()
421         {
422             KeyedHashAlgorithm algorithm = GetAlgorithmFromConfig( SecurityAlgorithms.HmacSha1Signature ) as KeyedHashAlgorithm;
423             if ( algorithm == null )
424             {
425                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( "algorithm", SR.GetString( SR.ID6037, SecurityAlgorithms.HmacSha1Signature ) );
426             }
427             return algorithm;
428         }
429
430         internal static KeyedHashAlgorithm NewHmacSha1KeyedHashAlgorithm(byte[] key)
431         {
432             return CryptoHelper.CreateKeyedHashAlgorithm(key, SecurityAlgorithms.HmacSha1Signature);
433         }
434
435         internal static KeyedHashAlgorithm NewHmacSha256KeyedHashAlgorithm(byte[] key)
436         {
437             return CryptoHelper.CreateKeyedHashAlgorithm(key, SecurityAlgorithms.HmacSha256Signature);
438         }
439
440         internal static Rijndael NewRijndaelSymmetricAlgorithm()
441         {
442             Rijndael rijndael = (GetSymmetricAlgorithm(null, SecurityAlgorithms.Aes128Encryption) as Rijndael);
443             if (rijndael != null)
444                 return rijndael;
445             throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidSymmetricAlgorithm, SecurityAlgorithms.Aes128Encryption)));
446         }
447
448         internal static ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, string algorithm)
449         {
450             object algorithmObject = GetAlgorithmFromConfig(algorithm);
451
452             if (algorithmObject != null)
453             {
454                 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
455
456                 if (symmetricAlgorithm != null)
457                 {
458                     return symmetricAlgorithm.CreateDecryptor(key, iv);
459                 }
460                 //NOTE: KeyedHashAlgorithms are symmetric in nature but we still throw if it is passed as an argument. 
461
462                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidSymmetricAlgorithm, algorithm)));
463             }
464
465             switch (algorithm)
466             {
467                 case SecurityAlgorithms.TripleDesEncryption:
468                     return TripleDES.CreateDecryptor(key, iv);
469                 case SecurityAlgorithms.Aes128Encryption:
470                 case SecurityAlgorithms.Aes192Encryption:
471                 case SecurityAlgorithms.Aes256Encryption:
472                     return Rijndael.CreateDecryptor(key, iv);
473                 default:
474                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedEncryptionAlgorithm, algorithm)));
475             }
476         }
477
478         internal static ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, string algorithm)
479         {
480
481             object algorithmObject = GetAlgorithmFromConfig(algorithm);
482
483             if (algorithmObject != null)
484             {
485                 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
486                 if (symmetricAlgorithm != null)
487                 {
488                     return symmetricAlgorithm.CreateEncryptor(key, iv);
489                 }
490                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidSymmetricAlgorithm, algorithm)));
491             }
492
493             switch (algorithm)
494             {
495                 case SecurityAlgorithms.TripleDesEncryption:
496                     return TripleDES.CreateEncryptor(key, iv);
497                 case SecurityAlgorithms.Aes128Encryption:
498                 case SecurityAlgorithms.Aes192Encryption:
499                 case SecurityAlgorithms.Aes256Encryption:
500                     return Rijndael.CreateEncryptor(key, iv);
501                 default:
502                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedEncryptionAlgorithm, algorithm)));
503             }
504         }
505
506         internal static HashAlgorithm CreateHashAlgorithm(string algorithm)
507         {
508             object algorithmObject = GetAlgorithmFromConfig(algorithm);
509
510             if (algorithmObject != null)
511             {
512                 HashAlgorithm hashAlgorithm = algorithmObject as HashAlgorithm;
513                 if (hashAlgorithm != null)
514                 {
515                     return hashAlgorithm;
516                 }
517                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidHashAlgorithm, algorithm)));
518             }
519
520             switch (algorithm)
521             {
522                 case SHAString:
523                 case SHA1String:
524                 case SystemSecurityCryptographySha1String:
525                 case SecurityAlgorithms.Sha1Digest:
526                     if (SecurityUtils.RequiresFipsCompliance)
527                         return new SHA1CryptoServiceProvider();
528                     else
529                         return new SHA1Managed();
530                 case SHA256String:
531                 case SecurityAlgorithms.Sha256Digest:
532                     if (SecurityUtils.RequiresFipsCompliance)
533                         return new SHA256CryptoServiceProvider();
534                     else
535                         return new SHA256Managed();
536                 default:
537                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedCryptoAlgorithm, algorithm)));
538             }
539         }
540
541         internal static KeyedHashAlgorithm CreateKeyedHashAlgorithm(byte[] key, string algorithm)
542         {
543             object algorithmObject = GetAlgorithmFromConfig(algorithm);
544
545             if (algorithmObject != null)
546             {
547                 KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
548                 if (keyedHashAlgorithm != null)
549                 {
550                     keyedHashAlgorithm.Key = key;
551                     return keyedHashAlgorithm;
552                 }
553
554                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidKeyedHashAlgorithm, algorithm)));
555             }
556
557             switch (algorithm)
558             {
559                 case SecurityAlgorithms.HmacSha1Signature:
560                     return new HMACSHA1(key, !SecurityUtils.RequiresFipsCompliance);
561                 case SecurityAlgorithms.HmacSha256Signature:
562                     if (!SecurityUtils.RequiresFipsCompliance)
563                         return new HMACSHA256(key);
564                     else
565                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CryptoAlgorithmIsNotFipsCompliant, algorithm)));
566                 default:
567                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedCryptoAlgorithm, algorithm)));
568             }
569         }
570
571         internal static byte[] ComputeHash(byte[] buffer)
572         {
573             using (HashAlgorithm hasher = CryptoHelper.NewSha1HashAlgorithm())
574             {
575                 return hasher.ComputeHash(buffer);
576             }
577         }
578
579         internal static byte[] GenerateDerivedKey(byte[] key, string algorithm, byte[] label, byte[] nonce, int derivedKeySize, int position)
580         {
581             if ((algorithm != SecurityAlgorithms.Psha1KeyDerivation) && (algorithm != SecurityAlgorithms.Psha1KeyDerivationDec2005))
582             {
583                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedKeyDerivationAlgorithm, algorithm)));
584             }
585             return new Psha1DerivedKeyGenerator(key).GenerateDerivedKey(label, nonce, derivedKeySize, position);
586         }
587
588         internal static int GetIVSize(string algorithm)
589         {
590             object algorithmObject = GetAlgorithmFromConfig(algorithm);
591
592             if (algorithmObject != null)
593             {
594                 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
595                 if (symmetricAlgorithm != null)
596                 {
597                     return symmetricAlgorithm.BlockSize;
598                 }
599                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidSymmetricAlgorithm, algorithm)));
600             }
601
602             switch (algorithm)
603             {
604                 case SecurityAlgorithms.TripleDesEncryption:
605                     return TripleDES.BlockSize;
606                 case SecurityAlgorithms.Aes128Encryption:
607                 case SecurityAlgorithms.Aes192Encryption:
608                 case SecurityAlgorithms.Aes256Encryption:
609                     return Rijndael.BlockSize;
610                 default:
611                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedEncryptionAlgorithm, algorithm)));
612             }
613         }
614
615         internal static void FillRandomBytes( byte[] buffer )
616         {
617             RandomNumberGenerator.GetBytes( buffer );
618         }
619
620         /// <summary>
621         /// This generates the entropy using random number. This is usually used on the sending 
622         /// side to generate the requestor's entropy.
623         /// </summary>
624         /// <param name="data">The array to fill with cryptographically strong random nonzero bytes.</param>
625         public static void GenerateRandomBytes( byte[] data )
626         {
627             RandomNumberGenerator.GetNonZeroBytes( data );
628         }
629
630         /// <summary>
631         /// This method generates a random byte array used as entropy with the given size. 
632         /// </summary>
633         /// <param name="sizeInBits"></param>
634         /// <returns></returns>
635         public static byte[] GenerateRandomBytes( int sizeInBits )
636         {
637             int sizeInBytes = sizeInBits / 8;
638             if ( sizeInBits <= 0 )
639             {
640                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentOutOfRangeException( "sizeInBits", SR.GetString( SR.ID6033, sizeInBits ) ) );
641             }
642             else if ( sizeInBytes * 8 != sizeInBits )
643             {
644                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new ArgumentException( SR.GetString( SR.ID6002, sizeInBits ), "sizeInBits" ) );
645             }
646
647             byte[] data = new byte[sizeInBytes];
648             GenerateRandomBytes( data );
649
650             return data;
651         }
652             
653         internal static SymmetricAlgorithm GetSymmetricAlgorithm(byte[] key, string algorithm)
654         {
655             SymmetricAlgorithm symmetricAlgorithm;
656
657             object algorithmObject = GetAlgorithmFromConfig(algorithm);
658
659             if (algorithmObject != null)
660             {
661                 symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
662                 if (symmetricAlgorithm != null)
663                 {
664                     if (key != null)
665                     {
666                         symmetricAlgorithm.Key = key;
667                     }
668                     return symmetricAlgorithm;
669                 }
670                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidSymmetricAlgorithm, algorithm)));
671             }
672
673             // NOTE: HMACSHA1 and HMACSHA256 ( KeyedHashAlgorithms ) are symmetric algorithms but they do not extend Symmetric class. 
674             // Hence the function throws when they are passed as arguments.
675
676             switch (algorithm)
677             {
678                 case SecurityAlgorithms.TripleDesEncryption:
679                 case SecurityAlgorithms.TripleDesKeyWrap:
680                     symmetricAlgorithm = new TripleDESCryptoServiceProvider();
681                     break;
682                 case SecurityAlgorithms.Aes128Encryption:
683                 case SecurityAlgorithms.Aes192Encryption:
684                 case SecurityAlgorithms.Aes256Encryption:
685                 case SecurityAlgorithms.Aes128KeyWrap:
686                 case SecurityAlgorithms.Aes192KeyWrap:
687                 case SecurityAlgorithms.Aes256KeyWrap:
688                     symmetricAlgorithm = SecurityUtils.RequiresFipsCompliance ? (Rijndael)new RijndaelCryptoServiceProvider() : new RijndaelManaged();
689                     break;
690                 default:
691                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedEncryptionAlgorithm, algorithm)));
692
693             }
694
695             if (key != null)
696             {
697                 symmetricAlgorithm.Key = key;
698             }
699             return symmetricAlgorithm;
700         }
701
702         /// <summary>
703         /// Wrapper that creates a signature for SHA256 taking into consideration the special logic required for FIPS compliance
704         /// </summary>
705         /// <param name="formatter">the signature formatter</param>
706         /// <param name="hash">the hash algorithm</param>
707         /// <returns>byte array representing the signature</returns>
708         internal static byte[] CreateSignatureForSha256( AsymmetricSignatureFormatter formatter, HashAlgorithm hash )
709         {
710             if ( SecurityUtils.RequiresFipsCompliance )
711             {
712                 //
713                 // When FIPS is turned ON. We need to set the hash algorithm specifically 
714                 // as we need to pass the pre-computed buffer to CreateSignature, else
715                 // for SHA256 and FIPS turned ON, the underlying formatter does not understand the 
716                 // OID for the hashing algorithm.
717                 //
718                 formatter.SetHashAlgorithm( "SHA256" );
719                 return formatter.CreateSignature( hash.Hash );
720             }
721             else
722             {
723                 //
724                 // Calling the formatter with the object allows us to be Crypto-Agile
725                 //
726                 return formatter.CreateSignature( hash );
727             }
728         }
729
730         /// <summary>
731         /// Wrapper that verifies the signature for SHA256 taking into consideration the special logic for FIPS compliance
732         /// </summary>
733         /// <param name="deformatter">the signature deformatter</param>
734         /// <param name="hash">the hash algorithm</param>
735         /// <param name="signatureValue">the byte array for the signature value</param>
736         /// <returns>true/false indicating if signature was verified or not</returns>
737         internal static bool VerifySignatureForSha256( AsymmetricSignatureDeformatter deformatter, HashAlgorithm hash, byte[] signatureValue )
738         {
739             if ( SecurityUtils.RequiresFipsCompliance )
740             {
741                 //
742                 // When FIPS is turned ON. We need to set the hash algorithm specifically 
743                 // else for SHA256 and FIPS turned ON, the underlying deformatter does not understand the 
744                 // OID for the hashing algorithm.
745                 //
746                 deformatter.SetHashAlgorithm( "SHA256" );
747                 return deformatter.VerifySignature( hash.Hash, signatureValue );
748             }
749             else
750             {
751                 return deformatter.VerifySignature( hash, signatureValue );
752             }
753         }
754
755         
756         /// <summary>
757         /// This method returns an AsymmetricSignatureFormatter capable of supporting Sha256 signatures. 
758         /// </summary>
759         /// <param name="key"></param>
760         /// <returns></returns>
761         internal static AsymmetricSignatureFormatter GetSignatureFormatterForSha256( AsymmetricSecurityKey key )
762         {
763             AsymmetricAlgorithm algorithm = key.GetAsymmetricAlgorithm( SecurityAlgorithms.RsaSha256Signature, true );
764             RSACryptoServiceProvider rsaProvider = algorithm as RSACryptoServiceProvider;
765             if ( null != rsaProvider )
766             {
767                 return GetSignatureFormatterForSha256( rsaProvider );
768             }
769             else
770             {
771                 //
772                 // If not an RSaCryptoServiceProvider, we can only hope that
773                 //  the derived imlementation does the correct thing thing WRT Sha256.
774                 //
775                 return new RSAPKCS1SignatureFormatter( algorithm );
776             }
777         }
778
779         /// <summary>
780         /// This method returns an AsymmetricSignatureFormatter capable of supporting Sha256 signatures. 
781         /// </summary>
782         internal static AsymmetricSignatureFormatter GetSignatureFormatterForSha256( RSACryptoServiceProvider rsaProvider )
783         {
784             const int PROV_RSA_AES = 24;    // CryptoApi provider type for an RSA provider supporting sha-256 digital signatures
785             AsymmetricSignatureFormatter formatter = null;
786             CspParameters csp = new CspParameters();
787             csp.ProviderType = PROV_RSA_AES;
788             if ( PROV_RSA_AES == rsaProvider.CspKeyContainerInfo.ProviderType )
789             {
790                 csp.ProviderName = rsaProvider.CspKeyContainerInfo.ProviderName;
791             }
792             csp.KeyContainerName = rsaProvider.CspKeyContainerInfo.KeyContainerName;
793             csp.KeyNumber = (int)rsaProvider.CspKeyContainerInfo.KeyNumber;
794             if ( rsaProvider.CspKeyContainerInfo.MachineKeyStore )
795             {
796                 csp.Flags = CspProviderFlags.UseMachineKeyStore;
797             }
798
799             csp.Flags |= CspProviderFlags.UseExistingKey;
800             rsaProvider = new RSACryptoServiceProvider( csp );
801             formatter = new RSAPKCS1SignatureFormatter( rsaProvider );
802             return formatter;
803         }
804
805         /// <summary>
806         /// This method returns an AsymmetricSignatureDeFormatter capable of supporting Sha256 signatures. 
807         /// </summary>
808         /// <param name="key"></param>
809         /// <returns></returns>
810         internal static AsymmetricSignatureDeformatter GetSignatureDeFormatterForSha256( AsymmetricSecurityKey key )
811         {
812             RSAPKCS1SignatureDeformatter deformatter;
813             AsymmetricAlgorithm algorithm = key.GetAsymmetricAlgorithm( SecurityAlgorithms.RsaSha256Signature, false );
814             RSACryptoServiceProvider rsaProvider = algorithm as RSACryptoServiceProvider;
815             if ( null != rsaProvider )
816             {
817                 return GetSignatureDeFormatterForSha256( rsaProvider );
818             }
819             else
820             {
821                 //
822                 // If not an RSaCryptoServiceProvider, we can only hope that
823                 //  the derived imlementation does the correct thing WRT Sha256.
824                 //
825                 deformatter = new RSAPKCS1SignatureDeformatter( algorithm );
826             }
827
828             return deformatter;
829         }
830
831         /// <summary>
832         /// This method returns an AsymmetricSignatureDeFormatter capable of supporting Sha256 signatures. 
833         /// </summary>
834         internal static AsymmetricSignatureDeformatter GetSignatureDeFormatterForSha256( RSACryptoServiceProvider rsaProvider )
835         {
836             const int PROV_RSA_AES = 24;    // CryptoApi provider type for an RSA provider supporting sha-256 digital signatures
837             AsymmetricSignatureDeformatter deformatter = null;
838             CspParameters csp = new CspParameters();
839             csp.ProviderType = PROV_RSA_AES;
840             if ( PROV_RSA_AES == rsaProvider.CspKeyContainerInfo.ProviderType )
841             {
842                 csp.ProviderName = rsaProvider.CspKeyContainerInfo.ProviderName;
843             }
844             csp.KeyNumber = (int)rsaProvider.CspKeyContainerInfo.KeyNumber;
845             if ( rsaProvider.CspKeyContainerInfo.MachineKeyStore )
846             {
847                 csp.Flags = CspProviderFlags.UseMachineKeyStore;
848             }
849             
850             csp.Flags |= CspProviderFlags.UseExistingKey;
851             RSACryptoServiceProvider rsaPublicProvider = new RSACryptoServiceProvider( csp );
852             rsaPublicProvider.ImportCspBlob( rsaProvider.ExportCspBlob( false ) );
853             deformatter = new RSAPKCS1SignatureDeformatter( rsaPublicProvider );
854             return deformatter;
855         }
856
857         internal static bool IsAsymmetricAlgorithm(string algorithm)
858         {
859             object algorithmObject = null;
860
861             try
862             {
863                 algorithmObject = GetAlgorithmFromConfig(algorithm);
864             }
865             catch (InvalidOperationException)
866             {
867                 algorithmObject = null;
868                 // We ---- the exception and continue.
869             }
870
871             if (algorithmObject != null)
872             {
873                 AsymmetricAlgorithm asymmetricAlgorithm = algorithmObject as AsymmetricAlgorithm;
874                 SignatureDescription signatureDescription = algorithmObject as SignatureDescription;
875                 if (asymmetricAlgorithm != null || signatureDescription != null)
876                     return true;
877                 return false;
878             }
879
880             switch (algorithm)
881             {
882                 case SecurityAlgorithms.DsaSha1Signature:
883                 case SecurityAlgorithms.RsaSha1Signature:
884                 case SecurityAlgorithms.RsaSha256Signature:
885                 case SecurityAlgorithms.RsaOaepKeyWrap:
886                 case SecurityAlgorithms.RsaV15KeyWrap:
887                     return true;
888                 default:
889                     return false;
890             }
891         }
892
893         internal static bool IsSymmetricAlgorithm(string algorithm)
894         {
895             object algorithmObject = null;
896
897             try
898             {
899                 algorithmObject = GetAlgorithmFromConfig(algorithm);
900             }
901             catch (InvalidOperationException)
902             {
903                 algorithmObject = null;
904                 // We ---- the exception and continue.
905             }
906             if (algorithmObject != null)
907             {
908                 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
909                 KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
910                 if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
911                     return true;
912                 return false;
913             }
914
915             // NOTE: A KeyedHashAlgorithm is symmetric in nature.
916
917             switch (algorithm)
918             {
919                 case SecurityAlgorithms.DsaSha1Signature:
920                 case SecurityAlgorithms.RsaSha1Signature:
921                 case SecurityAlgorithms.RsaSha256Signature:
922                 case SecurityAlgorithms.RsaOaepKeyWrap:
923                 case SecurityAlgorithms.RsaV15KeyWrap:
924                     return false;
925                 case SecurityAlgorithms.HmacSha1Signature:
926                 case SecurityAlgorithms.HmacSha256Signature:
927                 case SecurityAlgorithms.Aes128Encryption:
928                 case SecurityAlgorithms.Aes192Encryption:
929                 case SecurityAlgorithms.DesEncryption:
930                 case SecurityAlgorithms.Aes256Encryption:
931                 case SecurityAlgorithms.TripleDesEncryption:
932                 case SecurityAlgorithms.Aes128KeyWrap:
933                 case SecurityAlgorithms.Aes192KeyWrap:
934                 case SecurityAlgorithms.Aes256KeyWrap:
935                 case SecurityAlgorithms.TripleDesKeyWrap:
936                 case SecurityAlgorithms.Psha1KeyDerivation:
937                 case SecurityAlgorithms.Psha1KeyDerivationDec2005:
938                     return true;
939                 default:
940                     return false;
941             }
942         }
943
944         internal static bool IsSymmetricSupportedAlgorithm(string algorithm, int keySize)
945         {
946             bool found = false;
947             object algorithmObject = null;
948
949             try
950             {
951                 algorithmObject = GetAlgorithmFromConfig(algorithm);
952             }
953             catch (InvalidOperationException)
954             {
955                 // We ---- the exception and continue.
956             }
957             if (algorithmObject != null)
958             {
959                 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
960                 KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
961
962                 if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
963                     found = true;
964                 // The reason we do not return here even when the user has provided a custom algorithm in machine.config 
965                 // is because we need to check if the user has overwritten an existing standard URI.
966             }
967
968             switch (algorithm)
969             {
970                 case SecurityAlgorithms.DsaSha1Signature:
971                 case SecurityAlgorithms.RsaSha1Signature:
972                 case SecurityAlgorithms.RsaSha256Signature:
973                 case SecurityAlgorithms.RsaOaepKeyWrap:
974                 case SecurityAlgorithms.RsaV15KeyWrap:
975                     return false;
976                 case SecurityAlgorithms.HmacSha1Signature:
977                 case SecurityAlgorithms.HmacSha256Signature:
978                 case SecurityAlgorithms.Psha1KeyDerivation:
979                 case SecurityAlgorithms.Psha1KeyDerivationDec2005:
980                     return true;
981                 case SecurityAlgorithms.Aes128Encryption:
982                 case SecurityAlgorithms.Aes128KeyWrap:
983                     return keySize >= 128 && keySize <= 256;
984                 case SecurityAlgorithms.Aes192Encryption:
985                 case SecurityAlgorithms.Aes192KeyWrap:
986                     return keySize >= 192 && keySize <= 256;
987                 case SecurityAlgorithms.Aes256Encryption:
988                 case SecurityAlgorithms.Aes256KeyWrap:
989                     return keySize == 256;
990                 case SecurityAlgorithms.TripleDesEncryption:
991                 case SecurityAlgorithms.TripleDesKeyWrap:
992                     return keySize == 128 || keySize == 192;
993                 default:
994                     if (found)
995                         return true;
996                     return false;
997                 // We do not expect the user to map the uri of an existing standrad algorithm with say key size 128 bit 
998                 // to a custom algorithm with keySize 192 bits. If he does that, we anyways make sure that we return false.
999             }
1000         }
1001
1002         // We currently call the CLR APIs to do symmetric key wrap.
1003         // This ends up causing a triple cloning of the byte arrays.
1004         // However, the symmetric key wrap exists now primarily for
1005         // the feature completeness of cryptos and tokens.  That is,
1006         // it is never encountered in any Indigo AuthenticationMode.
1007         // The performance of this should be reviewed if this gets hit
1008         // in any mainline scenario.
1009         internal static byte[] UnwrapKey(byte[] wrappingKey, byte[] wrappedKey, string algorithm)
1010         {
1011             SymmetricAlgorithm symmetricAlgorithm;
1012             object algorithmObject = GetAlgorithmFromConfig(algorithm);
1013             if (algorithmObject != null)
1014             {
1015                 symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
1016                 if (symmetricAlgorithm == null)
1017                 {
1018                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.InvalidCustomKeyWrapAlgorithm, algorithm)));
1019                 }
1020                 using (symmetricAlgorithm)
1021                 {
1022                     symmetricAlgorithm.Key = wrappingKey;
1023                     return EncryptedXml.DecryptKey(wrappedKey, symmetricAlgorithm);
1024                 }
1025             }
1026             switch (algorithm)
1027             {
1028                 case SecurityAlgorithms.TripleDesKeyWrap:
1029                     symmetricAlgorithm = new TripleDESCryptoServiceProvider();
1030                     break;
1031                 case SecurityAlgorithms.Aes128KeyWrap:
1032                 case SecurityAlgorithms.Aes192KeyWrap:
1033                 case SecurityAlgorithms.Aes256KeyWrap:
1034                     symmetricAlgorithm = SecurityUtils.RequiresFipsCompliance ? (Rijndael)new RijndaelCryptoServiceProvider() : new RijndaelManaged();
1035                     break;
1036                 default:
1037                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedKeyWrapAlgorithm, algorithm)));
1038             }
1039
1040             using (symmetricAlgorithm)
1041             {
1042                 symmetricAlgorithm.Key = wrappingKey;
1043                 return EncryptedXml.DecryptKey(wrappedKey, symmetricAlgorithm);
1044             }
1045         }
1046
1047         internal static byte[] WrapKey(byte[] wrappingKey, byte[] keyToBeWrapped, string algorithm)
1048         {
1049             SymmetricAlgorithm symmetricAlgorithm;
1050             object algorithmObject = GetAlgorithmFromConfig(algorithm);
1051             if (algorithmObject != null)
1052             {
1053                 symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
1054                 if (symmetricAlgorithm == null)
1055                 {
1056                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.InvalidCustomKeyWrapAlgorithm, algorithm)));
1057                 }
1058                 using (symmetricAlgorithm)
1059                 {
1060                     symmetricAlgorithm.Key = wrappingKey;
1061                     return EncryptedXml.EncryptKey(keyToBeWrapped, symmetricAlgorithm);
1062                 }
1063             }
1064
1065             switch (algorithm)
1066             {
1067                 case SecurityAlgorithms.TripleDesKeyWrap:
1068                     symmetricAlgorithm = new TripleDESCryptoServiceProvider();
1069                     break;
1070                 case SecurityAlgorithms.Aes128KeyWrap:
1071                 case SecurityAlgorithms.Aes192KeyWrap:
1072                 case SecurityAlgorithms.Aes256KeyWrap:
1073                     symmetricAlgorithm = SecurityUtils.RequiresFipsCompliance ? (Rijndael)new RijndaelCryptoServiceProvider() : new RijndaelManaged();
1074                     break;
1075                 default:
1076                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.GetString(SR.UnsupportedKeyWrapAlgorithm, algorithm)));
1077             }
1078
1079             using (symmetricAlgorithm)
1080             {
1081                 symmetricAlgorithm.Key = wrappingKey;
1082                 return EncryptedXml.EncryptKey(keyToBeWrapped, symmetricAlgorithm);
1083             }
1084         }
1085
1086         internal static void ValidateBufferBounds(Array buffer, int offset, int count)
1087         {
1088             if (buffer == null)
1089             {
1090                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer"));
1091             }
1092             if (count < 0 || count > buffer.Length)
1093             {
1094                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeInRange, 0, buffer.Length)));
1095             }
1096             if (offset < 0 || offset > buffer.Length - count)
1097             {
1098                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeInRange, 0, buffer.Length - count)));
1099             }
1100         }
1101
1102         internal static bool IsEqual(byte[] a, byte[] b)
1103         {
1104             if (ReferenceEquals(a, b))
1105             {
1106                 return true;
1107             }
1108
1109             if (a == null || b == null || a.Length != b.Length)
1110             {
1111                 return false;
1112             }
1113
1114             for (int i = 0; i < a.Length; i++)
1115             {
1116                 if (a[i] != b[i])
1117                 {
1118                     return false;
1119                 }
1120             }
1121             return true;
1122         }
1123
1124         private static object GetDefaultAlgorithm(string algorithm)
1125         {
1126             if (string.IsNullOrEmpty(algorithm))
1127             {
1128                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("algorithm"));
1129             }
1130
1131             switch (algorithm)
1132             {
1133                 //case SecurityAlgorithms.RsaSha1Signature:
1134                 //case SecurityAlgorithms.DsaSha1Signature:
1135                 // For these algorithms above, crypto config returns internal objects.
1136                 // As we cannot create those internal objects, we are returning null.
1137                 // If no custom algorithm is plugged-in, at least these two algorithms
1138                 // will be inside the delegate dictionary.
1139                 case SecurityAlgorithms.Sha1Digest:
1140                     if (SecurityUtils.RequiresFipsCompliance)
1141                         return new SHA1CryptoServiceProvider();
1142                     else
1143                         return new SHA1Managed();
1144                 case SecurityAlgorithms.ExclusiveC14n:
1145                     return new XmlDsigExcC14NTransform();
1146                 case SHA256String:
1147                 case SecurityAlgorithms.Sha256Digest:
1148                     if (SecurityUtils.RequiresFipsCompliance)
1149                         return new SHA256CryptoServiceProvider();
1150                     else
1151                         return new SHA256Managed();
1152                 case SecurityAlgorithms.Sha512Digest:
1153                     if (SecurityUtils.RequiresFipsCompliance)
1154                         return new SHA512CryptoServiceProvider();
1155                     else
1156                         return new SHA512Managed();
1157                 case SecurityAlgorithms.Aes128Encryption:
1158                 case SecurityAlgorithms.Aes192Encryption:
1159                 case SecurityAlgorithms.Aes256Encryption:
1160                 case SecurityAlgorithms.Aes128KeyWrap:
1161                 case SecurityAlgorithms.Aes192KeyWrap:
1162                 case SecurityAlgorithms.Aes256KeyWrap:
1163                     if (SecurityUtils.RequiresFipsCompliance)
1164                         return new RijndaelCryptoServiceProvider();
1165                     else
1166                         return new RijndaelManaged();
1167                 case SecurityAlgorithms.TripleDesEncryption:
1168                 case SecurityAlgorithms.TripleDesKeyWrap:
1169                     return new TripleDESCryptoServiceProvider();
1170                 case SecurityAlgorithms.HmacSha1Signature:
1171                     byte[] key = new byte[64];
1172                     new RNGCryptoServiceProvider().GetBytes(key);
1173                     return new HMACSHA1(key, !SecurityUtils.RequiresFipsCompliance);
1174                 case SecurityAlgorithms.HmacSha256Signature:
1175                     if (!SecurityUtils.RequiresFipsCompliance)
1176                         return new HMACSHA256();
1177                     return null;
1178                 case SecurityAlgorithms.ExclusiveC14nWithComments:
1179                     return new XmlDsigExcC14NWithCommentsTransform();
1180                 case SecurityAlgorithms.Ripemd160Digest:
1181                     if (!SecurityUtils.RequiresFipsCompliance)
1182                         return new RIPEMD160Managed();
1183                     return null;
1184                 case SecurityAlgorithms.DesEncryption:
1185                     return new DESCryptoServiceProvider();
1186                 default:
1187                     return null;
1188             }
1189         }
1190
1191         internal static object GetAlgorithmFromConfig(string algorithm)
1192         {
1193             if (string.IsNullOrEmpty(algorithm))
1194             {
1195                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("algorithm"));
1196             }
1197
1198             object algorithmObject = null;
1199             object defaultObject = null;
1200             Func<object> delegateFunction = null;
1201
1202             if (!algorithmDelegateDictionary.TryGetValue(algorithm, out delegateFunction))
1203             {
1204                 lock (AlgorithmDictionaryLock)
1205                 {
1206                     if (!algorithmDelegateDictionary.ContainsKey(algorithm))
1207                     {
1208                         try
1209                         {
1210                             algorithmObject = CryptoConfig.CreateFromName(algorithm);
1211                         }
1212                         catch (TargetInvocationException)
1213                         {
1214                             algorithmDelegateDictionary[algorithm] = null;
1215                         }
1216
1217                         if (algorithmObject == null)
1218                         {
1219                             algorithmDelegateDictionary[algorithm] = null;
1220                         }
1221                         else
1222                         {
1223                             defaultObject = GetDefaultAlgorithm(algorithm);
1224                             if ((!SecurityUtils.RequiresFipsCompliance && algorithmObject is SHA1CryptoServiceProvider)
1225                                 || (defaultObject != null && defaultObject.GetType() == algorithmObject.GetType()))
1226                             {
1227                                 algorithmDelegateDictionary[algorithm] = null;
1228                             }
1229                             else
1230                             {
1231
1232                                 // Create a factory delegate which returns new instances of the algorithm type for later calls.
1233                                 Type algorithmType = algorithmObject.GetType();
1234                                 System.Linq.Expressions.NewExpression algorithmCreationExpression = System.Linq.Expressions.Expression.New(algorithmType);
1235                                 System.Linq.Expressions.LambdaExpression creationFunction = System.Linq.Expressions.Expression.Lambda<Func<object>>(algorithmCreationExpression);
1236                                 delegateFunction = creationFunction.Compile() as Func<object>;
1237
1238                                 if (delegateFunction != null)
1239                                 {
1240                                     algorithmDelegateDictionary[algorithm] = delegateFunction;
1241                                 }
1242                                 return algorithmObject;
1243                             }
1244                         }
1245                     }
1246                 }
1247             }
1248             else
1249             {
1250                 if (delegateFunction != null)
1251                 {
1252                     return delegateFunction.Invoke();
1253                 }
1254             }
1255
1256             //
1257             // This is a fallback in case CryptoConfig fails to return a valid
1258             // algorithm object. CrytoConfig does not understand all the uri's and
1259             // can return a null in that case, in which case it is our responsibility
1260             // to fallback and create the right algorithm if it is a uri we understand
1261             //
1262             switch (algorithm)
1263             {
1264                 case SHA256String:
1265                 case SecurityAlgorithms.Sha256Digest:
1266                     if (SecurityUtils.RequiresFipsCompliance)
1267                     {
1268                         return new SHA256CryptoServiceProvider();
1269                     }
1270                     else
1271                     {
1272                         return new SHA256Managed();
1273                     }
1274                 case SecurityAlgorithms.Sha1Digest:
1275                     if (SecurityUtils.RequiresFipsCompliance)
1276                     {
1277                         return new SHA1CryptoServiceProvider();
1278                     }
1279                     else
1280                     {
1281                         return new SHA1Managed();
1282                     }
1283                 case SecurityAlgorithms.HmacSha1Signature:
1284                     return new HMACSHA1(GenerateRandomBytes(64),
1285                                                     !SecurityUtils.RequiresFipsCompliance /* indicates the managed version of the algortithm */ );
1286                 default:
1287                     break;
1288             }
1289
1290             return null;
1291         }
1292
1293         public static void ResetAllCertificates(X509Certificate2Collection certificates)
1294         {
1295             if (certificates != null)
1296             {
1297                 for (int i = 0; i < certificates.Count; ++i)
1298                 {
1299                     certificates[i].Reset();
1300                 }
1301             }
1302         }
1303
1304     }
1305 }
1306