/// <summary> /// Static constructor for the <see cref="Cipher"/> class. /// </summary> static Cipher() { #if MONO // Common .NET FIPS wrapper algorithms are implemented as managed code under Mono, check status of Crimson project s_managedEncryption = true; s_textEncoding = Encoding.Default; #else const string fipsKeyOld = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa"; const string fipsKeyNew = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\FipsAlgorithmPolicy"; // Determine if the user needs to use FIPS-compliant algorithms s_managedEncryption = (Registry.GetValue(fipsKeyNew, "Enabled", 0) ?? Registry.GetValue(fipsKeyOld, "FIPSAlgorithmPolicy", 0)).ToString() == "0"; s_textEncoding = Encoding.Unicode; #endif KeyIVCache localKeyIVCache; string localCacheFileName = DefaultCacheFileName; double retryDelayInterval = DefaultRetryDelayInterval; int maximumRetryAttempts = DefaultMaximumRetryAttempts; // Load cryptographic settings ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings[CryptoServicesSettingsCategory]; settings.Add("CryptoCache", localCacheFileName, "Path and file name of cryptographic key and initialization vector cache."); settings.Add("CacheRetryDelayInterval", retryDelayInterval, "Wait interval, in milliseconds, before retrying load of cryptographic key and initialization vector cache."); settings.Add("CacheMaximumRetryAttempts", maximumRetryAttempts, "Maximum retry attempts allowed for loading cryptographic key and initialization vector cache."); localCacheFileName = FilePath.GetAbsolutePath(settings["CryptoCache"].ValueAs(localCacheFileName)); retryDelayInterval = settings["CacheRetryDelayInterval"].ValueAs(retryDelayInterval); maximumRetryAttempts = settings["CacheMaximumRetryAttempts"].ValueAs(maximumRetryAttempts); // Initialize local cryptographic key and initialization vector cache (application may only have read-only access to this cache) localKeyIVCache = new KeyIVCache { FileName = localCacheFileName, RetryDelayInterval = retryDelayInterval, MaximumRetryAttempts = maximumRetryAttempts, ManagedEncryption = s_managedEncryption, #if DNF45 && !MONO ReloadOnChange = true, #else // Reload on change is disabled to eliminate GC handle leaks on .NET 4.0, this prevents // automatic runtime reloading of key/iv data cached by another application. ReloadOnChange = false, #endif AutoSave = false }; // Load initial keys localKeyIVCache.Load(); try { // Validate that user has write access to the local cryptographic cache folder string tempFile = FilePath.GetDirectoryName(localCacheFileName) + Guid.NewGuid() + ".tmp"; using (File.Create(tempFile)) { } if (File.Exists(tempFile)) File.Delete(tempFile); // No access issues exist, use local cache as the primary cryptographic key and initialization vector cache s_keyIVCache = localKeyIVCache; s_keyIVCache.AutoSave = true; localKeyIVCache = null; } catch (UnauthorizedAccessException) { // User does not have needed serialization access to common cryptographic cache folder, use a path where user will have rights string userCacheFolder = FilePath.AddPathSuffix(FilePath.GetApplicationDataFolder()); string userCacheFileName = userCacheFolder + FilePath.GetFileName(localCacheFileName); // Make sure user directory exists if (!Directory.Exists(userCacheFolder)) Directory.CreateDirectory(userCacheFolder); // Copy existing common cryptographic cache if none exists if (File.Exists(localCacheFileName) && !File.Exists(userCacheFileName)) File.Copy(localCacheFileName, userCacheFileName); // Initialize primary cryptographic key and initialization vector cache within user folder s_keyIVCache = new KeyIVCache { FileName = userCacheFileName, RetryDelayInterval = retryDelayInterval, MaximumRetryAttempts = maximumRetryAttempts, #if DNF45 && !MONO ReloadOnChange = true, #else // Reload on change is disabled to eliminate GC handle leaks on .NET 4.0, this prevents // automatic runtime reloading of key/iv data cached by another application. ReloadOnChange = false, #endif AutoSave = true }; // Load initial keys s_keyIVCache.Load(); // Merge new or updated keys, protected folder keys taking precedence over user keys s_keyIVCache.MergeRight(localKeyIVCache); } if ((object)localKeyIVCache != null) localKeyIVCache.Dispose(); }
/// <summary> /// Manually loads keys into the local system key cache. /// </summary> public static void ReloadCache() { ConfigurationFile config; CategorizedSettingsElementCollection settings; string commonCacheFileName = string.Empty; double retryDelayInterval = 0.0; int maximumRetryAttempts = 0; // Load the system key cache s_keyIVCache.Load(); // Load cryptographic settings config = ConfigurationFile.Current; settings = config.Settings[CryptoServicesSettingsCategory]; commonCacheFileName = FilePath.GetAbsolutePath(settings["CryptoCache"].ValueAs(commonCacheFileName)); if (commonCacheFileName != s_keyIVCache.FileName) { // System key cache is not loaded from common cache folder. // We need to merge the common key cache with the system key cache. retryDelayInterval = settings["CacheRetryDelayInterval"].ValueAs(retryDelayInterval); maximumRetryAttempts = settings["CacheMaximumRetryAttempts"].ValueAs(maximumRetryAttempts); // Initialize local cryptographic key and initialization vector cache (application may only have read-only access to this cache) using (KeyIVCache commonKeyIVCache = new KeyIVCache { FileName = commonCacheFileName, RetryDelayInterval = retryDelayInterval, MaximumRetryAttempts = maximumRetryAttempts, ManagedEncryption = s_managedEncryption, ReloadOnChange = false, AutoSave = false }) { // Load initial keys commonKeyIVCache.Load(); // Merge new or updated keys, common cache folder keys taking precedence s_keyIVCache.MergeRight(commonKeyIVCache); } } }
/// <summary> /// Static constructor for the <see cref="Cipher"/> class. /// </summary> static Cipher() { KeyIVCache localKeyIVCache; string localCacheFileName = DefaultCacheFileName; double retryDelayInterval = DefaultRetryDelayInterval; int maximumRetryAttempts = DefaultMaximumRetryAttempts; string fipsKeyOld = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa"; string fipsKeyNew = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\FipsAlgorithmPolicy"; // Load cryptographic settings ConfigurationFile config = ConfigurationFile.Current; CategorizedSettingsElementCollection settings = config.Settings[CryptoServicesSettingsCategory]; settings.Add("CryptoCache", localCacheFileName, "Path and file name of cryptographic key and initialization vector cache."); settings.Add("CacheRetryDelayInterval", retryDelayInterval, "Wait interval, in milliseconds, before retrying load of cryptographic key and initialization vector cache."); settings.Add("CacheMaximumRetryAttempts", maximumRetryAttempts, "Maximum retry attempts allowed for loading cryptographic key and initialization vector cache."); localCacheFileName = FilePath.GetAbsolutePath(settings["CryptoCache"].ValueAs(localCacheFileName)); retryDelayInterval = settings["CacheRetryDelayInterval"].ValueAs(retryDelayInterval); maximumRetryAttempts = settings["CacheMaximumRetryAttempts"].ValueAs(maximumRetryAttempts); // Determine if the user needs to use FIPS-compliant algorithms. s_managedEncryption = (Registry.GetValue(fipsKeyNew, "Enabled", 0) ?? Registry.GetValue(fipsKeyOld, "FipsAlgorithmPolicy", 0)).ToString() == "0"; // Initialize local cryptographic key and initialization vector cache (application may only have read-only access to this cache) localKeyIVCache = new KeyIVCache() { FileName = localCacheFileName, RetryDelayInterval = retryDelayInterval, MaximumRetryAttempts = maximumRetryAttempts, ManagedEncryption = s_managedEncryption, ReloadOnChange = false, AutoSave = false }; // Load initial keys localKeyIVCache.Load(); try { // Validate that user has write access to the local cryptographic cache folder System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(FilePath.GetDirectoryName(localCacheFileName)); // No access issues exist, use local cache as the primary cryptographic key and initialization vector cache s_keyIVCache = localKeyIVCache; s_keyIVCache.AutoSave = true; } catch (UnauthorizedAccessException) { // User does not have needed serialization access to common cryptographic cache folder, use a path where user will have rights string userCacheFolder = FilePath.AddPathSuffix(FilePath.GetApplicationDataFolder()); string userCacheFileName = userCacheFolder + FilePath.GetFileName(localCacheFileName); // Make sure user directory exists if (!Directory.Exists(userCacheFolder)) Directory.CreateDirectory(userCacheFolder); // Copy existing common cryptographic cache if none exists if (File.Exists(localCacheFileName) && !File.Exists(userCacheFileName)) File.Copy(localCacheFileName, userCacheFileName); // Initialize primary cryptographic key and initialization vector cache within user folder s_keyIVCache = new KeyIVCache() { FileName = userCacheFileName, RetryDelayInterval = retryDelayInterval, MaximumRetryAttempts = maximumRetryAttempts, // TODO: Reload on change is disabled for now by default to eliminate GC handle leaks, if .NET fixes bug http://support.microsoft.com/kb/2628838 // then this can be safely reenabled. For now this will prevent automatic runtime reloading of keys cached by another application. ReloadOnChange = false, AutoSave = true }; // Load initial keys s_keyIVCache.Load(); // Merge new or updated keys, protected folder keys taking precendence over user keys s_keyIVCache.MergeRight(localKeyIVCache); } }