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();
}
}
}