/* Copyright 2001-2007 Markus Hahn All rights reserved. See documentation for license details. */ using System; using System.Text; namespace DG.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); } } }