using System;
using System.Security.Cryptography;
namespace Sleis.Utility
{
public class EncryptionUtility
{
private readonly System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
private readonly string _passphrase;
private readonly int _tokenValidForHours;
public EncryptionUtility(string passphrase, int tokenValidForHours)
{
ArgumentValidationUtility.ThrowOnEmpty(passphrase, "passphrase required");
if (tokenValidForHours < 1){
throw new ArgumentOutOfRangeException("Must be greater than one hour");
}
_passphrase = passphrase;
_tokenValidForHours = tokenValidForHours;
}
public string EncryptTokenForUrl(int id)
{
string val = String.Format("{0}|{1}", id, DateTime.Now);
return EncryptStringForUrl(val);
}
public int DecryptTokenFromUrl(string content)
{
string val = content.Replace("--B--", "+")
.Replace("--F--", "/")
.Replace("--0--", " ")
.Replace("--Q--", "?")
.Replace("--A--", "&");
val = DecryptStringFromUrl(val);
string[] tokenParts = val.Split('|');
if (tokenParts.Length != 2)
{
throw new ArgumentOutOfRangeException("Invalid number of token parts");
}
DateTime tokenCreatedOn = Convert.ToDateTime(tokenParts[1]);
TimeSpan tokenSpan = DateTime.Now - tokenCreatedOn;
if (tokenSpan.TotalHours > _tokenValidForHours)
{
throw new ArgumentOutOfRangeException("Token expired");
}
int id = Convert.ToInt32(tokenParts[0]);
return id;
}
public string EncryptStringForUrl(string content)
{
string val = TripleDESEncrypt(content);
val = val.Replace("+", "--B--")
.Replace("/", "--F--")
.Replace(" ", "--0--")
.Replace("?", "--Q--")
.Replace("&", "--A--");
return val;
}
public string DecryptStringFromUrl(string content)
{
string val = content.Replace("***B***", "+")
.Replace("***F***", "/")
.Replace("***0***", " ")
.Replace("***Q***", "?")
.Replace("***A***", "&");
val = TripleDESDecrypt(val);
return val;
}
///
/// Performs a one-way hash
///
///
/// SHA512 hash, base 64 encoded (88 char output). With no salt specified, the output will be 100 characters long
public string OneWayHash(string content)
{
ArgumentValidationUtility.ThrowOnEmpty(content, "content required");
var contentBytes = new System.Text.UnicodeEncoding().GetBytes(_passphrase + content);
var hashBytes = new SHA512Managed().ComputeHash(contentBytes);
return System.Convert.ToBase64String(hashBytes);
}
///
/// Encrypt in a way that we can decrypt it later
///
/// String to encrypt
/// Base 64 encoded string
public string TripleDESEncrypt(string content)
{
ArgumentValidationUtility.ThrowOnEmpty(content, "content required");
byte[] results = null;
MD5CryptoServiceProvider hashProvider = new MD5CryptoServiceProvider();
byte[] tdesKey = hashProvider.ComputeHash(UTF8.GetBytes(_passphrase));
TripleDESCryptoServiceProvider tdesAlgorithm = new TripleDESCryptoServiceProvider();
tdesAlgorithm.Key = tdesKey;
tdesAlgorithm.Mode = CipherMode.ECB;
tdesAlgorithm.Padding = PaddingMode.PKCS7;
byte[] dataToEncrypt = UTF8.GetBytes(content);
try
{
ICryptoTransform encryptor = tdesAlgorithm.CreateEncryptor();
results = encryptor.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);
}
finally
{
tdesAlgorithm.Clear();
hashProvider.Clear();
}
return Convert.ToBase64String(results);
}
///
/// Decrypt previously encrypted string
///
/// Base 64 encoded string
/// Decrypted string
public string TripleDESDecrypt(string content)
{
ArgumentValidationUtility.ThrowOnEmpty(content, "content required");
byte[] results = null;
MD5CryptoServiceProvider hashProvider = new MD5CryptoServiceProvider();
byte[] tdesKey = hashProvider.ComputeHash(UTF8.GetBytes(_passphrase));
TripleDESCryptoServiceProvider tdesAlgorithm = new TripleDESCryptoServiceProvider();
tdesAlgorithm.Key = tdesKey;
tdesAlgorithm.Mode = CipherMode.ECB;
tdesAlgorithm.Padding = PaddingMode.PKCS7;
byte[] dataToDecrypt = Convert.FromBase64String(content);
try
{
ICryptoTransform decryptor = tdesAlgorithm.CreateDecryptor();
results = decryptor.TransformFinalBlock(dataToDecrypt, 0, dataToDecrypt.Length);
}
finally
{
tdesAlgorithm.Clear();
hashProvider.Clear();
}
return UTF8.GetString(results);
}
}
}