//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.Security.Cryptography { using System; using System.Web.Configuration; // The central ASP.NET class for providing ICryptoService instances. // Get an instance of this class via the static Instance property. internal sealed class AspNetCryptoServiceProvider : ICryptoServiceProvider { private static readonly Lazy _singleton = new Lazy(GetSingletonCryptoServiceProvider); private readonly ICryptoAlgorithmFactory _cryptoAlgorithmFactory; private readonly IDataProtectorFactory _dataProtectorFactory; private readonly bool _isDataProtectorEnabled; private KeyDerivationFunction _keyDerivationFunction; private readonly MachineKeySection _machineKeySection; private readonly IMasterKeyProvider _masterKeyProvider; // This constructor is used only for testing purposes and by the singleton provider // and should not otherwise be called during ASP.NET request processing. internal AspNetCryptoServiceProvider(MachineKeySection machineKeySection = null, ICryptoAlgorithmFactory cryptoAlgorithmFactory = null, IMasterKeyProvider masterKeyProvider = null, IDataProtectorFactory dataProtectorFactory = null, KeyDerivationFunction keyDerivationFunction = null) { _machineKeySection = machineKeySection; _cryptoAlgorithmFactory = cryptoAlgorithmFactory; _masterKeyProvider = masterKeyProvider; _dataProtectorFactory = dataProtectorFactory; _keyDerivationFunction = keyDerivationFunction; // This CryptoServiceProvider is active if specified as such in the section IsDefaultProvider = (machineKeySection != null && machineKeySection.CompatibilityMode >= MachineKeyCompatibilityMode.Framework45); // The DataProtectorCryptoService is active if specified as such in config _isDataProtectorEnabled = (machineKeySection != null && !String.IsNullOrWhiteSpace(machineKeySection.DataProtectorType)); } internal static AspNetCryptoServiceProvider Instance { get { return _singleton.Value; } } // Returns a value indicating whether this crypto service provider is the default // provider for the current application. internal bool IsDefaultProvider { get; private set; } public ICryptoService GetCryptoService(Purpose purpose, CryptoServiceOptions options = CryptoServiceOptions.None) { ICryptoService cryptoService; if (_isDataProtectorEnabled && options == CryptoServiceOptions.None) { // We can only use DataProtector if it's configured and the caller didn't ask for any special behavior like cacheability cryptoService = GetDataProtectorCryptoService(purpose); } else { // Otherwise we fall back to using the algorithms for cryptography cryptoService = GetNetFXCryptoService(purpose, options); } // always homogenize errors returned from the crypto service return new HomogenizingCryptoServiceWrapper(cryptoService); } private DataProtectorCryptoService GetDataProtectorCryptoService(Purpose purpose) { // just return the ICryptoService directly return new DataProtectorCryptoService(_dataProtectorFactory, purpose); } private NetFXCryptoService GetNetFXCryptoService(Purpose purpose, CryptoServiceOptions options) { // Extract the encryption and validation keys from the provided Purpose object CryptographicKey encryptionKey = purpose.GetDerivedEncryptionKey(_masterKeyProvider, _keyDerivationFunction); CryptographicKey validationKey = purpose.GetDerivedValidationKey(_masterKeyProvider, _keyDerivationFunction); // and return the ICryptoService // (predictable IV turned on if the caller requested cacheable output) return new NetFXCryptoService(_cryptoAlgorithmFactory, encryptionKey, validationKey, predictableIV: (options == CryptoServiceOptions.CacheableOutput)); } private static AspNetCryptoServiceProvider GetSingletonCryptoServiceProvider() { // Provides all of the necessary dependencies for an application-level // AspNetCryptoServiceProvider. MachineKeySection machineKeySection = MachineKeySection.GetApplicationConfig(); return new AspNetCryptoServiceProvider( machineKeySection: machineKeySection, cryptoAlgorithmFactory: new MachineKeyCryptoAlgorithmFactory(machineKeySection), masterKeyProvider: new MachineKeyMasterKeyProvider(machineKeySection), dataProtectorFactory: new MachineKeyDataProtectorFactory(machineKeySection), keyDerivationFunction: SP800_108.DeriveKey); } } }