| File: System\IdentityModel\CryptoHelper.cs | Web Access |
| Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.IdentityModel.Tokens; using System.Reflection; using System.Security.Cryptography; using System.ServiceModel; namespace System.IdentityModel { internal static class CryptoHelper { private static RandomNumberGenerator s_random; private const string SHAString = "SHA"; private const string SHA1String = "SHA1"; private const string SHA256String = "SHA256"; private const string SystemSecurityCryptographySha1String = "System.Security.Cryptography.SHA1"; private static Dictionary<string, Func<object>> s_algorithmDelegateDictionary = new Dictionary<string, Func<object>>(); private static object s_algorithmDictionaryLock = new object(); internal static bool IsSymmetricAlgorithm(string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static byte[] UnwrapKey(byte[] wrappingKey, byte[] wrappedKey, string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static byte[] WrapKey(byte[] wrappingKey, byte[] keyToBeWrapped, string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static byte[] GenerateDerivedKey(byte[] key, string algorithm, byte[] label, byte[] nonce, int derivedKeySize, int position) { throw ExceptionHelper.PlatformNotSupported(); } internal static int GetIVSize(string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static KeyedHashAlgorithm CreateKeyedHashAlgorithm(byte[] key, string algorithm) { object algorithmObject = GetAlgorithmFromConfig(algorithm); if (algorithmObject != null) { KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm; if (keyedHashAlgorithm != null) { keyedHashAlgorithm.Key = key; return keyedHashAlgorithm; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SRP.Format(SRP.CustomCryptoAlgorithmIsNotValidKeyedHashAlgorithm, algorithm))); } switch (algorithm) { case SecurityAlgorithms.HmacSha1Signature: #pragma warning disable CA5350 // Do not use insecure cryptographic algorithm SHA1. return new HMACSHA1(key);// CodeQL [SM02200] Insecure cryptographic algorithm HMACSHA1 is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1. case SecurityAlgorithms.HmacSha256Signature: return new HMACSHA256(key); default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SRP.Format(SRP.UnsupportedCryptoAlgorithm, algorithm))); } } internal static SymmetricAlgorithm GetSymmetricAlgorithm(byte[] key, string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static bool IsAsymmetricAlgorithm(string algorithm) { throw ExceptionHelper.PlatformNotSupported(); } internal static bool IsSymmetricSupportedAlgorithm(string algorithm, int keySize) { bool found = false; object algorithmObject = null; try { algorithmObject = GetAlgorithmFromConfig(algorithm); } catch (InvalidOperationException) { // We swallow the exception and continue. } if (algorithmObject != null) { SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm; KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm; if (symmetricAlgorithm != null || keyedHashAlgorithm != null) { found = true; } // The reason we do not return here even when the user has provided a custom algorithm to CryptoConfig // is because we need to check if the user has overwritten an existing standard URI. } switch (algorithm) { case SecurityAlgorithms.DsaSha1Signature: case SecurityAlgorithms.RsaSha1Signature: case SecurityAlgorithms.RsaSha256Signature: case SecurityAlgorithms.RsaOaepKeyWrap: case SecurityAlgorithms.RsaV15KeyWrap: return false; case SecurityAlgorithms.HmacSha1Signature: case SecurityAlgorithms.HmacSha256Signature: case SecurityAlgorithms.Psha1KeyDerivation: case SecurityAlgorithms.Psha1KeyDerivationDec2005: return true; case SecurityAlgorithms.Aes128Encryption: case SecurityAlgorithms.Aes128KeyWrap: return keySize >= 128 && keySize <= 256; case SecurityAlgorithms.Aes192Encryption: case SecurityAlgorithms.Aes192KeyWrap: return keySize >= 192 && keySize <= 256; case SecurityAlgorithms.Aes256Encryption: case SecurityAlgorithms.Aes256KeyWrap: return keySize == 256; case SecurityAlgorithms.TripleDesEncryption: case SecurityAlgorithms.TripleDesKeyWrap: return keySize == 128 || keySize == 192; default: if (found) { return true; } return false; // We do not expect the user to map the uri of an existing standrad algorithm with say key size 128 bit // to a custom algorithm with keySize 192 bits. If he does that, we anyways make sure that we return false. } } internal static void FillRandomBytes(byte[] buffer) { RandomNumberGenerator.GetBytes(buffer); } internal static RandomNumberGenerator RandomNumberGenerator { get { if (s_random == null) { s_random = RandomNumberGenerator.Create(); } return s_random; } } internal static HashAlgorithm CreateHashAlgorithm(string algorithm) { object algorithmObject = GetAlgorithmFromConfig(algorithm); if (algorithmObject != null) { HashAlgorithm hashAlgorithm = algorithmObject as HashAlgorithm; if (hashAlgorithm != null) { return hashAlgorithm; } throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SRP.Format(SRP.CustomCryptoAlgorithmIsNotValidHashAlgorithm, algorithm))); } switch (algorithm) { case SHAString: case SHA1String: case SystemSecurityCryptographySha1String: case SecurityAlgorithms.Sha1Digest: #pragma warning disable CA5350 // Do not use insecure cryptographic algorithm SHA1. return SHA1.Create();// CodeQL [SM02196] Insecure cryptographic algorithm SHA1 is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1. case SHA256String: case SecurityAlgorithms.Sha256Digest: return SHA256.Create(); default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SRP.Format(SRP.UnsupportedCryptoAlgorithm, algorithm))); } } private static object GetDefaultAlgorithm(string algorithm) { if (string.IsNullOrEmpty(algorithm)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(algorithm))); } switch (algorithm) { //case SecurityAlgorithms.RsaSha1Signature: //case SecurityAlgorithms.DsaSha1Signature: // For these algorithms above, crypto config returns internal objects. // As we cannot create those internal objects, we are returning null. // If no custom algorithm is plugged-in, at least these two algorithms // will be inside the delegate dictionary. case SecurityAlgorithms.Sha1Digest: #pragma warning disable CA5350 // Do not use insecure cryptographic algorithm SHA1. return SHA1.Create();// CodeQL [SM02196] Insecure cryptographic algorithm SHA1 is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1. case SecurityAlgorithms.ExclusiveC14n: throw ExceptionHelper.PlatformNotSupported(); case SHA256String: case SecurityAlgorithms.Sha256Digest: return SHA256.Create(); case SecurityAlgorithms.Sha512Digest: return SHA512.Create(); case SecurityAlgorithms.Aes128Encryption: case SecurityAlgorithms.Aes192Encryption: case SecurityAlgorithms.Aes256Encryption: case SecurityAlgorithms.Aes128KeyWrap: case SecurityAlgorithms.Aes192KeyWrap: case SecurityAlgorithms.Aes256KeyWrap: return Aes.Create(); case SecurityAlgorithms.TripleDesEncryption: case SecurityAlgorithms.TripleDesKeyWrap: #pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms return TripleDES.Create();// CodeQL [SM02192] Weak cryptographic algorithm TripleDES is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms case SecurityAlgorithms.HmacSha1Signature: #pragma warning disable CA5350 // Do not use insecure cryptographic algorithm SHA1. return new HMACSHA1();// CodeQL [SM02200] Insecure cryptographic algorithm HMACSHA1 is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1. case SecurityAlgorithms.HmacSha256Signature: return new HMACSHA256(); case SecurityAlgorithms.ExclusiveC14nWithComments: throw ExceptionHelper.PlatformNotSupported(); case SecurityAlgorithms.Ripemd160Digest: return null; case SecurityAlgorithms.DesEncryption: #pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms return DES.Create();// CodeQL [SM02192] Broken cryptographic algorithm DES is needed here as a requirement of SOAP protocols #pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms default: return null; } } internal static object GetAlgorithmFromConfig(string algorithm) { if (string.IsNullOrEmpty(algorithm)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(algorithm))); } object algorithmObject = null; object defaultObject = null; Func<object> delegateFunction = null; if (!s_algorithmDelegateDictionary.TryGetValue(algorithm, out delegateFunction)) { lock (s_algorithmDictionaryLock) { if (!s_algorithmDelegateDictionary.ContainsKey(algorithm)) { try { algorithmObject = CryptoConfig.CreateFromName(algorithm); } catch (TargetInvocationException) { s_algorithmDelegateDictionary[algorithm] = null; } if (algorithmObject == null) { s_algorithmDelegateDictionary[algorithm] = null; } else { defaultObject = GetDefaultAlgorithm(algorithm); if (defaultObject != null && defaultObject.GetType() == algorithmObject.GetType()) { s_algorithmDelegateDictionary[algorithm] = null; } else { // Create a factory delegate which returns new instances of the algorithm type for later calls. Type algorithmType = algorithmObject.GetType(); Linq.Expressions.NewExpression algorithmCreationExpression = Linq.Expressions.Expression.New(algorithmType); Linq.Expressions.LambdaExpression creationFunction = Linq.Expressions.Expression.Lambda<Func<object>>(algorithmCreationExpression); delegateFunction = creationFunction.Compile() as Func<object>; if (delegateFunction != null) { s_algorithmDelegateDictionary[algorithm] = delegateFunction; } return algorithmObject; } } } } } else { if (delegateFunction != null) { return delegateFunction.Invoke(); } } // // This is a fallback in case CryptoConfig fails to return a valid // algorithm object. CrytoConfig does not understand all the uri's and // can return a null in that case, in which case it is our responsibility // to fallback and create the right algorithm if it is a uri we understand // switch (algorithm) { case SHA256String: case SecurityAlgorithms.Sha256Digest: return SHA256.Create(); case SecurityAlgorithms.Sha1Digest: #pragma warning disable CA5350 // Do not use insecure cryptographic algorithm SHA1. return SHA1.Create();// CodeQL [SM02196] Insecure cryptographic algorithm SHA1 is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1. case SecurityAlgorithms.HmacSha1Signature: #pragma warning disable CA5350 // Do not use insecure cryptographic algorithm SHA1. return new HMACSHA1();// CodeQL [SM02200] Insecure cryptographic algorithm HMACSHA1 is needed here as a requirement of SOAP protocols #pragma warning restore CA5350 // Do not use insecure cryptographic algorithm SHA1. default: break; } return null; } internal static HashAlgorithm NewSha1HashAlgorithm() { return CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest); } internal static HashAlgorithm NewSha256HashAlgorithm() { return CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest); } internal static KeyedHashAlgorithm NewHmacSha1KeyedHashAlgorithm(byte[] key) { return CryptoHelper.CreateKeyedHashAlgorithm(key, SecurityAlgorithms.HmacSha1Signature); } } }