// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using Microsoft.AspNet.Security.DataProtection.SafeHandles; namespace Microsoft.AspNet.Security.DataProtection.Cng { /// /// Provides cached CNG algorithm provider instances, as calling BCryptOpenAlgorithmProvider is expensive. /// Callers should use caution never to dispose of the algorithm provider instances returned by this type. /// internal static class CachedAlgorithmHandles { private static CachedAlgorithmInfo _aesCbc = new CachedAlgorithmInfo(() => GetAesAlgorithm(chainingMode: Constants.BCRYPT_CHAIN_MODE_CBC)); private static CachedAlgorithmInfo _aesGcm = new CachedAlgorithmInfo(() => GetAesAlgorithm(chainingMode: Constants.BCRYPT_CHAIN_MODE_GCM)); private static CachedAlgorithmInfo _hmacSha1 = new CachedAlgorithmInfo(() => GetHmacAlgorithm(algorithm: Constants.BCRYPT_SHA1_ALGORITHM)); private static CachedAlgorithmInfo _hmacSha256 = new CachedAlgorithmInfo(() => GetHmacAlgorithm(algorithm: Constants.BCRYPT_SHA256_ALGORITHM)); private static CachedAlgorithmInfo _hmacSha512 = new CachedAlgorithmInfo(() => GetHmacAlgorithm(algorithm: Constants.BCRYPT_SHA512_ALGORITHM)); private static CachedAlgorithmInfo _pbkdf2 = new CachedAlgorithmInfo(GetPbkdf2Algorithm); private static CachedAlgorithmInfo _sha1 = new CachedAlgorithmInfo(() => GetHashAlgorithm(algorithm: Constants.BCRYPT_SHA1_ALGORITHM)); private static CachedAlgorithmInfo _sha256 = new CachedAlgorithmInfo(() => GetHashAlgorithm(algorithm: Constants.BCRYPT_SHA256_ALGORITHM)); private static CachedAlgorithmInfo _sha512 = new CachedAlgorithmInfo(() => GetHashAlgorithm(algorithm: Constants.BCRYPT_SHA512_ALGORITHM)); private static CachedAlgorithmInfo _sp800_108_ctr_hmac = new CachedAlgorithmInfo(GetSP800_108_CTR_HMACAlgorithm); public static BCryptAlgorithmHandle AES_CBC { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _aesCbc); } } public static BCryptAlgorithmHandle AES_GCM { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _aesGcm); } } public static BCryptAlgorithmHandle HMAC_SHA1 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _hmacSha1); } } public static BCryptAlgorithmHandle HMAC_SHA256 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _hmacSha256); } } public static BCryptAlgorithmHandle HMAC_SHA512 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _hmacSha512); } } // Only available on Win8+. public static BCryptAlgorithmHandle PBKDF2 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _pbkdf2); } } public static BCryptAlgorithmHandle SHA1 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _sha1); } } public static BCryptAlgorithmHandle SHA256 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _sha256); } } public static BCryptAlgorithmHandle SHA512 { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _sha512); } } public static BCryptAlgorithmHandle SP800_108_CTR_HMAC { get { return CachedAlgorithmInfo.GetAlgorithmHandle(ref _sp800_108_ctr_hmac); } } private static BCryptAlgorithmHandle GetAesAlgorithm(string chainingMode) { var algHandle = BCryptAlgorithmHandle.OpenAlgorithmHandle(Constants.BCRYPT_AES_ALGORITHM); algHandle.SetChainingMode(chainingMode); return algHandle; } private static BCryptAlgorithmHandle GetHashAlgorithm(string algorithm) { return BCryptAlgorithmHandle.OpenAlgorithmHandle(algorithm, hmac: false); } private static BCryptAlgorithmHandle GetHmacAlgorithm(string algorithm) { return BCryptAlgorithmHandle.OpenAlgorithmHandle(algorithm, hmac: true); } private static BCryptAlgorithmHandle GetPbkdf2Algorithm() { return BCryptAlgorithmHandle.OpenAlgorithmHandle(Constants.BCRYPT_PBKDF2_ALGORITHM, implementation: Constants.MS_PRIMITIVE_PROVIDER); } private static BCryptAlgorithmHandle GetSP800_108_CTR_HMACAlgorithm() { return BCryptAlgorithmHandle.OpenAlgorithmHandle(Constants.BCRYPT_SP800108_CTR_HMAC_ALGORITHM, implementation: Constants.MS_PRIMITIVE_PROVIDER); } // Warning: mutable struct! private struct CachedAlgorithmInfo { private WeakReference _algorithmHandle; private readonly Func _factory; public CachedAlgorithmInfo(Func factory) { _algorithmHandle = null; _factory = factory; } public static BCryptAlgorithmHandle GetAlgorithmHandle(ref CachedAlgorithmInfo cachedAlgorithmInfo) { return WeakReferenceHelpers.GetSharedInstance(ref cachedAlgorithmInfo._algorithmHandle, cachedAlgorithmInfo._factory); } } } }