/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
using System;
using System.Text;
namespace SMVC.Tool
{
/// An easy-to-use-string encryption solution using Blowfish/CBC.
/// As a simple solution for developers, who want nothing more than protect
/// single strings with a password, this class provides the necessary functionality.
/// The password (aka as key) is hashed using the SHA-1 implementation of the .NET
/// framework. The random number generator for the CBC initialization vector (IV)
/// and BASE64 are used from the framework's security services.
public class BlowfishSimple
{
BlowfishCBC bfc;
private byte[] iv;
private byte[] IV
{
get
{
if (iv == null || iv.Length < 8)
{
return Encoding.UTF8.GetBytes("Blowfish");
}
return iv;
}
set { iv = value; }
}
static byte[] TransformKey(String key)
{
UTF8Encoding ue = new UTF8Encoding();
return ue.GetBytes(key);
}
/// Empty constructor. Before using the instance you MUST call Initialize(),
/// otherwise any result or behavior is unpredictable!
public BlowfishSimple()
{
}
/// Default constructor.
/// The string which is used as the key material (aka as
/// password or passphrase). Internally the UTF-8 representation of this string
/// is used, hashed with SHA-1. The result is then a 160bit binary key. Notice
/// that this transformation will not make weak (meaning short or easily guessable)
/// keys any safer!
public BlowfishSimple(String keyStr)
{
Initialize(keyStr, null);
}
public BlowfishSimple(String keyStr, Byte[] iv)
{
Initialize(keyStr, iv);
}
/// Initializes the instance with a (new) key string.
/// The key material.
///
public void Initialize(String keyStr, Byte[] iv)
{
IV = iv;
byte[] key = TransformKey(keyStr);
this.bfc = new BlowfishCBC(key, 0, key.Length);
Array.Clear(key, 0, key.Length);
}
/// Encrypts a string.
/// For efficiency the given string will be UTF-8 encoded and padded to
/// the next 8byte block border. The CBC IV plus the encrypted data will then be
/// BASE64 encoded and returned as the final encryption result.
/// The string to encrypt.
/// The encrypted string.
public String Encrypt(String plainText)
{
return Encrypt(plainText, this.IV);
}
public String Encrypt(String plainText, byte[] iv)
{
if (string.IsNullOrEmpty(plainText)) return string.Empty;
int txtLen = plainText.Length;
if (txtLen % 8 != 0)
plainText = plainText.PadRight(txtLen - txtLen % 8 + 8, ' ');
byte[] ueData = Encoding.UTF8.GetBytes(plainText);
int origLen = ueData.Length;
byte[] inBuf = new byte[origLen];
Array.Copy(ueData, 0, inBuf, 0, origLen);
byte[] outBuf = new byte[inBuf.Length];
this.bfc.IV = iv;
this.bfc.Encrypt(
inBuf,
0,
outBuf,
0,
inBuf.Length);
String sResult = Convert.ToBase64String(outBuf);
Array.Clear(inBuf, 0, inBuf.Length);
return sResult;
}
/// Decrypts a string which was formely generated by the Encrypt()
/// method and a particular key.
/// The string has to be decrypted with the same key, otherwise the
/// result will be simply garbage. If you want to check if the key is the right
/// one use the VerifyKey() method.
/// The string to decrypt.
/// The decrypted string, or null on error (usually caused by a wrong
/// key passed in).
public String Decrypt(String cipherText)
{
return Decrypt(cipherText, this.IV);
}
public String Decrypt(String cipherText, byte[] iv)
{
byte[] cdata;
try
{
cdata = Convert.FromBase64String(cipherText);
}
catch (FormatException)
{
return null;
}
this.bfc.SetIV(iv, 0);
byte[] outBuf = new byte[cdata.Length];
int dataAbs = outBuf.Length;
this.bfc.Decrypt(
cdata,
0,
outBuf,
0,
dataAbs);
return Encoding.UTF8.GetString(outBuf);
}
}
}