1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Security
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.ServiceModel.Channels;
10 using System.ServiceModel;
11 using System.Reflection;
12 using System.Threading;
15 using System.Runtime.InteropServices;
16 using System.IdentityModel.Tokens;
19 using System.Diagnostics;
20 using System.Diagnostics.CodeAnalysis;
21 using System.Security.Cryptography;
23 using Psha1DerivedKeyGenerator = System.IdentityModel.Psha1DerivedKeyGenerator;
24 using CryptoAlgorithms = System.IdentityModel.CryptoHelper;
26 static class CryptoHelper
28 static byte[] emptyBuffer;
29 static readonly RandomNumberGenerator random = new RNGCryptoServiceProvider();
31 enum CryptoAlgorithmType
38 internal static byte[] EmptyBuffer
42 if (emptyBuffer == null)
44 byte[] tmp = new byte[0];
51 internal static HashAlgorithm NewSha1HashAlgorithm()
53 return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest);
56 internal static HashAlgorithm NewSha256HashAlgorithm()
58 return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest);
61 [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Required as SOAP spec requires supporting SHA1.")]
62 internal static HashAlgorithm CreateHashAlgorithm(string digestMethod)
64 object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(digestMethod);
65 if (algorithmObject != null)
67 HashAlgorithm hashAlgorithm = algorithmObject as HashAlgorithm;
68 if (hashAlgorithm != null)
70 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidHashAlgorithm, digestMethod)));
75 case SecurityAlgorithms.Sha1Digest:
76 if (SecurityUtilsEx.RequiresFipsCompliance)
77 return new SHA1CryptoServiceProvider();
79 return new SHA1Managed();
80 case SecurityAlgorithms.Sha256Digest:
81 if (SecurityUtilsEx.RequiresFipsCompliance)
82 return new SHA256CryptoServiceProvider();
84 return new SHA256Managed();
86 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnsupportedCryptoAlgorithm, digestMethod)));
91 [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Required as SOAP spec requires supporting SHA1.")]
92 internal static HashAlgorithm CreateHashForAsymmetricSignature(string signatureMethod)
94 object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(signatureMethod);
95 if (algorithmObject != null)
97 HashAlgorithm hashAlgorithm;
98 SignatureDescription signatureDescription = algorithmObject as SignatureDescription;
100 if (signatureDescription != null)
102 hashAlgorithm = signatureDescription.CreateDigest();
103 if (hashAlgorithm != null)
104 return hashAlgorithm;
107 hashAlgorithm = algorithmObject as HashAlgorithm;
108 if (hashAlgorithm != null)
109 return hashAlgorithm;
111 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.CustomCryptoAlgorithmIsNotValidAsymmetricSignature, signatureMethod)));
114 switch (signatureMethod)
116 case SecurityAlgorithms.RsaSha1Signature:
117 case SecurityAlgorithms.DsaSha1Signature:
118 if (SecurityUtilsEx.RequiresFipsCompliance)
119 return new SHA1CryptoServiceProvider();
121 return new SHA1Managed();
123 case SecurityAlgorithms.RsaSha256Signature:
124 if (SecurityUtilsEx.RequiresFipsCompliance)
125 return new SHA256CryptoServiceProvider();
127 return new SHA256Managed();
130 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new MessageSecurityException(SR.GetString(SR.UnsupportedCryptoAlgorithm, signatureMethod)));
134 internal static byte[] ExtractIVAndDecrypt(SymmetricAlgorithm algorithm, byte[] cipherText, int offset, int count)
136 if (cipherText == null)
138 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("cipherText");
140 if (count < 0 || count > cipherText.Length)
142 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeInRange, 0, cipherText.Length)));
145 if (offset < 0 || offset > cipherText.Length - count)
147 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeInRange, 0, cipherText.Length - count)));
150 int ivSize = algorithm.BlockSize / 8;
151 byte[] iv = new byte[ivSize];
152 Buffer.BlockCopy(cipherText, offset, iv, 0, iv.Length);
153 algorithm.Padding = PaddingMode.ISO10126;
154 algorithm.Mode = CipherMode.CBC;
157 using (ICryptoTransform decrTransform = algorithm.CreateDecryptor(algorithm.Key, iv))
159 return decrTransform.TransformFinalBlock(cipherText, offset + iv.Length, count - iv.Length);
162 catch (CryptographicException ex)
164 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageSecurityException(SR.GetString(SR.DecryptionFailed), ex));
168 internal static void FillRandomBytes(byte[] buffer)
170 random.GetBytes(buffer);
173 static CryptoAlgorithmType GetAlgorithmType(string algorithm)
175 object algorithmObject = null;
179 algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(algorithm);
181 catch (InvalidOperationException)
183 algorithmObject = null;
184 // We ---- the exception and continue.
186 if (algorithmObject != null)
188 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
189 KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
190 if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
191 return CryptoAlgorithmType.Symmetric;
193 // NOTE: A KeyedHashAlgorithm is symmetric in nature.
195 AsymmetricAlgorithm asymmetricAlgorithm = algorithmObject as AsymmetricAlgorithm;
196 SignatureDescription signatureDescription = algorithmObject as SignatureDescription;
197 if (asymmetricAlgorithm != null || signatureDescription != null)
198 return CryptoAlgorithmType.Asymmetric;
200 return CryptoAlgorithmType.Unknown;
205 case SecurityAlgorithms.DsaSha1Signature:
206 case SecurityAlgorithms.RsaSha1Signature:
207 case SecurityAlgorithms.RsaSha256Signature:
208 case SecurityAlgorithms.RsaOaepKeyWrap:
209 case SecurityAlgorithms.RsaV15KeyWrap:
210 return CryptoAlgorithmType.Asymmetric;
211 case SecurityAlgorithms.HmacSha1Signature:
212 case SecurityAlgorithms.HmacSha256Signature:
213 case SecurityAlgorithms.Aes128Encryption:
214 case SecurityAlgorithms.Aes192Encryption:
215 case SecurityAlgorithms.Aes256Encryption:
216 case SecurityAlgorithms.TripleDesEncryption:
217 case SecurityAlgorithms.Aes128KeyWrap:
218 case SecurityAlgorithms.Aes192KeyWrap:
219 case SecurityAlgorithms.Aes256KeyWrap:
220 case SecurityAlgorithms.TripleDesKeyWrap:
221 case SecurityAlgorithms.Psha1KeyDerivation:
222 case SecurityAlgorithms.Psha1KeyDerivationDec2005:
223 return CryptoAlgorithmType.Symmetric;
225 return CryptoAlgorithmType.Unknown;
229 internal static byte[] GenerateIVAndEncrypt(SymmetricAlgorithm algorithm, byte[] plainText, int offset, int count)
233 GenerateIVAndEncrypt(algorithm, new ArraySegment<byte>(plainText, offset, count), out iv, out cipherText);
234 byte[] output = DiagnosticUtility.Utility.AllocateByteArray(checked(iv.Length + cipherText.Length));
235 Buffer.BlockCopy(iv, 0, output, 0, iv.Length);
236 Buffer.BlockCopy(cipherText, 0, output, iv.Length, cipherText.Length);
240 internal static void GenerateIVAndEncrypt(SymmetricAlgorithm algorithm, ArraySegment<byte> plainText, out byte[] iv, out byte[] cipherText)
242 int ivSize = algorithm.BlockSize / 8;
243 iv = new byte[ivSize];
245 algorithm.Padding = PaddingMode.PKCS7;
246 algorithm.Mode = CipherMode.CBC;
247 using (ICryptoTransform encrTransform = algorithm.CreateEncryptor(algorithm.Key, iv))
249 cipherText = encrTransform.TransformFinalBlock(plainText.Array, plainText.Offset, plainText.Count);
253 internal static bool IsEqual(byte[] a, byte[] b)
255 if (a == null || b == null || a.Length != b.Length)
260 for (int i = 0; i < a.Length; i++)
270 internal static bool IsSymmetricAlgorithm(string algorithm)
272 return GetAlgorithmType(algorithm) == CryptoAlgorithmType.Symmetric;
275 internal static bool IsSymmetricSupportedAlgorithm(string algorithm, int keySize)
278 object algorithmObject = null;
282 algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(algorithm);
284 catch (InvalidOperationException)
286 algorithmObject = null;
287 // We ---- the exception and continue.
289 if (algorithmObject != null)
291 SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
292 KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
293 if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
299 case SecurityAlgorithms.DsaSha1Signature:
300 case SecurityAlgorithms.RsaSha1Signature:
301 case SecurityAlgorithms.RsaSha256Signature:
302 case SecurityAlgorithms.RsaOaepKeyWrap:
303 case SecurityAlgorithms.RsaV15KeyWrap:
305 case SecurityAlgorithms.HmacSha1Signature:
306 case SecurityAlgorithms.HmacSha256Signature:
307 case SecurityAlgorithms.Psha1KeyDerivation:
308 case SecurityAlgorithms.Psha1KeyDerivationDec2005:
310 case SecurityAlgorithms.Aes128Encryption:
311 case SecurityAlgorithms.Aes128KeyWrap:
312 return keySize == 128;
313 case SecurityAlgorithms.Aes192Encryption:
314 case SecurityAlgorithms.Aes192KeyWrap:
315 return keySize == 192;
316 case SecurityAlgorithms.Aes256Encryption:
317 case SecurityAlgorithms.Aes256KeyWrap:
318 return keySize == 256;
319 case SecurityAlgorithms.TripleDesEncryption:
320 case SecurityAlgorithms.TripleDesKeyWrap:
321 return keySize == 128 || keySize == 192;
329 internal static void ValidateBufferBounds(Array buffer, int offset, int count)
333 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("buffer"));
335 if (count < 0 || count > buffer.Length)
337 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeInRange, 0, buffer.Length)));
339 if (offset < 0 || offset > buffer.Length - count)
341 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("offset", SR.GetString(SR.ValueMustBeInRange, 0, buffer.Length - count)));
345 internal static void ValidateSymmetricKeyLength(int keyLength, SecurityAlgorithmSuite algorithmSuite)
347 if (!algorithmSuite.IsSymmetricKeyLengthSupported(keyLength))
349 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ArgumentOutOfRangeException("algorithmSuite",
350 SR.GetString(SR.UnsupportedKeyLength, keyLength, algorithmSuite.ToString())));
352 if (keyLength % 8 != 0)
354 throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new ArgumentOutOfRangeException("algorithmSuite",
355 SR.GetString(SR.KeyLengthMustBeMultipleOfEight, keyLength)));