📄 blowfishsimple.cs
字号:
/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
using System;
using System.Text;
using System.Security.Cryptography;
namespace BlowfishNET
{
/// <summary>An easy-to-use-string encryption solution using Blowfish/CBC.</summary>
/// <remarks>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.</remarks>
public class BlowfishSimple
{
BlowfishCBC bfc;
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
String keyChecksum;
/// <summary>The secure checksum of the key used for encryption.</summary>
/// <remarks>Store this checksum somewhere to be able to check later on by
/// calling the VerifyKey() method, to see if a key matches for decryption
/// or not.</remarks>
public String KeyChecksum
{
get
{
return this.keyChecksum;
}
}
static byte[] TransformKey(String key)
{
UTF8Encoding ue = new UTF8Encoding();
return ue.GetBytes(key);
}
static byte[] CalcKeyChecksum(byte[] salt, byte[] key)
{
HashAlgorithm sha = new SHA1CryptoServiceProvider();
byte[] keyCombo = new byte[20 + key.Length];
Array.Copy(salt, 0, keyCombo, 0, 20);
Array.Copy(key, 0, keyCombo, 20, key.Length);
byte[] result = sha.ComputeHash(keyCombo);
Array.Clear(keyCombo, 0, keyCombo.Length);
return result;
}
/// <summary>To verify a key before it is used for decryption.</summary>
/// <remarks> By passing the currently available key and a key checksum
/// retrieved during the former encryption process you will be assured that
/// the key will decrypt the data correctly.</remarks>
/// <param name="key">The key to verify.</param>
/// <param name="keyChecksum">The original key checksum.</param>
/// <returns>True if key seems to be the right one or false if it doesn't match.
/// </returns>
public static bool VerifyKey(String key, String keyChecksum)
{
int i;
byte[] checksumCombo, keyRaw, checksum;
checksumCombo = Convert.FromBase64String(keyChecksum);
if (40 != checksumCombo.Length)
{
return false;
}
keyRaw = TransformKey(key);
checksum = CalcKeyChecksum(checksumCombo, keyRaw);
i = 0;
while (i < checksum.Length)
{
if (checksum[i] != checksumCombo[checksum.Length + i])
{
break;
}
i++;
}
return (i == checksum.Length);
}
/// <summary>Empty constructor. Before using the instance you MUST call Initialize(),
/// otherwise any result or behavior is unpredictable!</summary>
public BlowfishSimple()
{
}
/// <summary>Default constructor.</summary>
/// <param name="keyStr">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!</param>
public BlowfishSimple(String keyStr)
{
Initialize(keyStr);
}
/// <summary>Initializes the instance with a (new) key string.</summary>
/// <param name="keyStr">The key material.</param>
/// <see cref="BlowfishSimple(String)"/>
public void Initialize(String keyStr)
{
HashAlgorithm sha;
byte[] keyRaw, key, checksumSalt, checksum, checksumCombo;
keyRaw = TransformKey(keyStr);
sha = new SHA1CryptoServiceProvider();
key = sha.ComputeHash(keyRaw);
checksumSalt = new byte[20];
this.rng.GetBytes(checksumSalt);
checksum = CalcKeyChecksum(checksumSalt, keyRaw);
checksumCombo = new byte[checksumSalt.Length + checksum.Length];
Array.Copy(
checksumSalt,
0,
checksumCombo,
0,
checksumSalt.Length);
Array.Copy(
checksum,
0,
checksumCombo,
checksumSalt.Length,
checksum.Length);
this.keyChecksum = Convert.ToBase64String(checksumCombo);
this.bfc = new BlowfishCBC(key, 0, key.Length);
Array.Clear(keyRaw, 0, keyRaw.Length);
Array.Clear(key, 0, key.Length);
}
/// <summary>Encrypts a string.</summary>
/// <remarks>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.</remarks>
/// <param name="plainText">The string to encrypt.</param>
/// <returns>The encrypted string.</returns>
public String Encrypt(String plainText)
{
int i, origLen, len, mod;
byte[] ueData, inBuf, outBuf, iv;
ueData = Encoding.UTF8.GetBytes(plainText);
origLen = ueData.Length;
len = origLen;
mod = len % BlowfishCBC.BLOCK_SIZE;
len = (len - mod) + BlowfishCBC.BLOCK_SIZE;
inBuf = new byte[len];
Array.Copy(ueData, 0, inBuf, 0, origLen);
i = len - (BlowfishCBC.BLOCK_SIZE - mod);
while (i < len)
{
inBuf[i++] = (byte)mod;
}
outBuf = new byte[inBuf.Length + BlowfishCBC.BLOCK_SIZE];
iv = new byte[BlowfishCBC.BLOCK_SIZE];
this.rng.GetBytes(iv);
this.bfc.IV = iv;
this.bfc.Encrypt(
inBuf,
0,
outBuf,
BlowfishCBC.BLOCK_SIZE,
inBuf.Length);
Array.Copy(iv, 0, outBuf, 0, BlowfishCBC.BLOCK_SIZE);
String sResult = Convert.ToBase64String(outBuf);
Array.Clear(inBuf, 0, inBuf.Length);
return sResult;
}
/// <summary>Decrypts a string which was formely generated by the Encrypt()
/// method and a particular key.</summary>
/// <remarks>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.</remarks>
/// <param name="cipherText">The string to decrypt.</param>
/// <returns>The decrypted string, or null on error (usually caused by a wrong
/// key passed in).</returns>
public String Decrypt(String cipherText)
{
int dataAbs, origSize, mod;
byte[] cdata, outBuf;
try
{
cdata = Convert.FromBase64String(cipherText);
}
catch (FormatException)
{
return null;
}
if (BlowfishCBC.BLOCK_SIZE > cdata.Length)
{
return null;
}
this.bfc.SetIV(cdata, 0);
outBuf = new byte[cdata.Length];
dataAbs = cdata.Length - BlowfishCBC.BLOCK_SIZE;
dataAbs /= BlowfishCBC.BLOCK_SIZE;
dataAbs *= BlowfishCBC.BLOCK_SIZE;
this.bfc.Decrypt(
cdata,
BlowfishCBC.BLOCK_SIZE,
outBuf,
0,
dataAbs);
mod = outBuf[dataAbs - 1];
if ((0 > mod) || (BlowfishCBC.BLOCK_SIZE <= mod))
{
return null;
}
origSize = dataAbs
- BlowfishCBC.BLOCK_SIZE
+ outBuf[dataAbs - 1];
return Encoding.UTF8.GetString(outBuf, 0, origSize);
}
/// <summary>Destructor to clean up the internal instance and with it all the
/// key material.</summary>
~BlowfishSimple()
{
this.bfc.Invalidate();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -