using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace GSF.Net.Snmp.Security { /// /// Class for holding computed crypto values which are referenced by password/engineId combination /// This class is not thread safe, it does not contain any static parameters. /// public class CryptoKeyCache { /// /// Number of elements that Cache will hold before deleting old elements /// private const int CacheCapacity = 100; #region InternalClasses /// /// Class for holding cached crypto keys computed values, since every password/engine id /// combination will produce a different key this class is modeled using /// Dictionary of Dictionaries. This class is not thread safe. /// private class EngineIdCache { /// /// Cache to map engineId to keys /// private Cache _engineIdCache; /// /// Default ctor initializes EngineIdCache /// public EngineIdCache(int capacity) { _engineIdCache = new Cache(capacity); } /// /// Gets the cached value associated with the specified key. /// /// The engineId of the cached value to get. /// /// When this method returns, contains the cachedValue associated with the specified /// engineId, if the engineId is found; otherwise, the default value for the type of the /// cachedValue parameter. This parameter is passed uninitialized. /// /// True if the cache contains an element with the specified engineId; otherwise, false. public bool TryGetCachedValue(byte[] engineId, out byte[] cachedValue) { bool success = _engineIdCache.TryGetValue(Stringanize(engineId), out cachedValue); return success; } /// /// Adds value to cache /// /// engine id associated with the value /// value to cache public void AddValueToCache(byte[] engineId, byte[] valueToCache) { _engineIdCache.Add(Stringanize(engineId), valueToCache); } } #endregion private Cache _cryptoCache; /// /// Ctor /// public CryptoKeyCache(int capacity) { _cryptoCache = new Cache(CacheCapacity); } /// /// Get the cached value if it exists in the cache /// /// password associated with cached value /// engine id associated with cached value /// cached value, if no cache exists for specified password/engine id /// combination default value is assigned to cachedValue /// True if value exists in cache for specified password/engine id combination, false otherwise public bool TryGetCachedValue(byte[] password, byte[] engineId, out byte[] cachedValue) { EngineIdCache engineCache; string strPassword = Stringanize(password); bool success = false; cachedValue = null; success = _cryptoCache.TryGetValue(strPassword, out engineCache); if (success) { success = engineCache.TryGetCachedValue(engineId, out cachedValue); } return success; } /// /// Adds computed value to the cache /// /// password to associate cached value with /// engine id to associate cached value with /// value being cached public void AddValueToCache(byte[] password, byte[] engineId, byte[] valueToCache) { string strPassword = Stringanize(password); if (!_cryptoCache.ContainsKey(strPassword)) { _cryptoCache.Add(strPassword, new EngineIdCache(CacheCapacity)); } EngineIdCache engineCache = _cryptoCache[strPassword]; engineCache.AddValueToCache(engineId, valueToCache); } /// /// Converts an array of bytes into a string this way we can use /// string.GetHashCode and string.Equals to allow the array of bytes /// be the key in a hash table /// /// /// private static string Stringanize(byte[] bytes) { StringBuilder builder = new StringBuilder(); foreach (byte b in bytes) { builder.Append(b.ToString()); } return builder.ToString(); } } }