//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.Security.Cryptography { using System; using System.Security.Cryptography; using System.Web.Configuration; // Can create cryptographic algorithms from a given element internal sealed class MachineKeyCryptoAlgorithmFactory : ICryptoAlgorithmFactory { private Func _encryptionAlgorithmFactory; private readonly MachineKeySection _machineKeySection; private Func _validationAlgorithmFactory; public MachineKeyCryptoAlgorithmFactory(MachineKeySection machineKeySection) { _machineKeySection = machineKeySection; } public SymmetricAlgorithm GetEncryptionAlgorithm() { if (_encryptionAlgorithmFactory == null) { _encryptionAlgorithmFactory = GetEncryptionAlgorithmFactory(); } return _encryptionAlgorithmFactory(); } private Func GetEncryptionAlgorithmFactory() { return GetGenericAlgorithmFactory( configAttributeName: "decryption", configAttributeValue: _machineKeySection.GetDecryptionAttributeSkipValidation(), switchStatement: algorithmName => { // We suppress CS0618 since some of the algorithms we support are marked with [Obsolete]. // These deprecated algorithms are *not* enabled by default. Developers must opt-in to // them, so we're secure by default. #pragma warning disable 618 switch (algorithmName) { case "AES": case "Auto": // currently "Auto" defaults to AES return CryptoAlgorithms.CreateAes; case "DES": return CryptoAlgorithms.CreateDES; case "3DES": return CryptoAlgorithms.CreateTripleDES; default: return null; // unknown #pragma warning restore 618 } }, errorResourceString: SR.Wrong_decryption_enum); } public KeyedHashAlgorithm GetValidationAlgorithm() { if (_validationAlgorithmFactory == null) { _validationAlgorithmFactory = GetValidationAlgorithmFactory(); } return _validationAlgorithmFactory(); } private Func GetValidationAlgorithmFactory() { return GetGenericAlgorithmFactory( configAttributeName: "validation", configAttributeValue: _machineKeySection.GetValidationAttributeSkipValidation(), switchStatement: algorithmName => { switch (algorithmName) { case "SHA1": return CryptoAlgorithms.CreateHMACSHA1; case "HMACSHA256": return CryptoAlgorithms.CreateHMACSHA256; case "HMACSHA384": return CryptoAlgorithms.CreateHMACSHA384; case "HMACSHA512": return CryptoAlgorithms.CreateHMACSHA512; default: return null; // unknown } }, errorResourceString: SR.Wrong_validation_enum_FX45); } // Contains common logic for creating encryption / validation factories, including // custom algorithm lookup and exception handling. private Func GetGenericAlgorithmFactory(string configAttributeName, string configAttributeValue, Func> switchStatement, string errorResourceString) where TResult : class, IDisposable { Func factory; if (configAttributeValue != null && configAttributeValue.StartsWith("alg:", StringComparison.Ordinal)) { string algorithmName = configAttributeValue.Substring("alg:".Length); factory = () => { // Since the custom algorithm might depend on the impersonated // identity, we must instantiate it under app-level impersonation. using (new ApplicationImpersonationContext()) { return (TResult)CryptoConfig.CreateFromName(algorithmName); } }; } else { // If using a built-in algorithm, consult the switch statement to get the factory. factory = switchStatement(configAttributeValue); } // Invoke the factory once to make sure there aren't any configuration errors. Exception factoryCreationException = null; try { if (factory != null) { TResult algorithm = factory(); if (algorithm != null) { algorithm.Dispose(); return factory; // we know at this point the factory is good } } } catch (Exception ex) { factoryCreationException = ex; } // If we reached this point, there was a failure: // the factory returned null, threw, or did something else unexpected. throw ConfigUtil.MakeConfigurationErrorsException( message: SR.GetString(errorResourceString), innerException: factoryCreationException, // can be null configProperty: _machineKeySection.ElementInformation.Properties[configAttributeName]); } } }