📄 blowfishecb.cs
字号:
/*
Copyright 2001-2007 Markus Hahn
All rights reserved. See documentation for license details.
*/
using System;
namespace BlowfishNET
{
/// <summary>Blowfish ECB implementation.</summary>
/// <remarks>Use this class to encrypt or decrypt byte arrays or a single
/// block with Blowfish in the ECB (Electronic Code Book) mode. The key
/// length can be flexible from zero up to 56 bytes.</remarks>
public class BlowfishECB : ICloneable
{
/// <summary>The maximum and recommended key size in bytes.</summary>
public const int MAX_KEY_LENGTH = 56;
/// <summary>The block size in bytes.</summary>
public const int BLOCK_SIZE = 8;
const int PBOX_ENTRIES = 18;
const int SBOX_ENTRIES = 256;
#region Cipher State
/// <summary>Runtime p-box.</summary>
protected uint[] pbox = new uint[PBOX_ENTRIES];
/// <summary>Runtime s-box #1.</summary>
protected uint[] sbox1 = new uint[SBOX_ENTRIES];
/// <summary>Runtime s-box #2.</summary>
protected uint[] sbox2 = new uint[SBOX_ENTRIES];
/// <summary>Runtime s-box #3.</summary>
protected uint[] sbox3 = new uint[SBOX_ENTRIES];
/// <summary>Runtime s-box #4.</summary>
protected uint[] sbox4 = new uint[SBOX_ENTRIES];
/// <summary>Single block cache.</summary>
protected byte[] block = new byte[BLOCK_SIZE];
/// <summary>1 if a weak key was detected, 0 if not and -1 if it hasn't
/// been determined yet.</summary>
protected int isWeakKey;
#endregion
/// <summary>To check if the key used is weak.</summary>
/// <remarks>If a key is weak it means that eventually an attack is easier to apply than
/// just a simple brute force on keys. Due to the randomness in the key setup process
/// such a case however is unlikely to happen, yet checking after each setup might still
/// be the preferred way. In the case of a weak key detected a simple recreation with a
/// different key (or just a different salt value) is the recommended solution. For
/// performance reasons we don't do the weak key check during the initialization, but on
/// demand only, and then only once to determine the flag.</remarks>
public bool IsWeakKey
{
get
{
if (-1 == this.isWeakKey)
{
this.isWeakKey = 0;
int i, j;
for (i = 0; i < SBOX_ENTRIES - 1; i++)
{
j = i + 1;
while (j < SBOX_ENTRIES)
{
if ((this.sbox1[i] == this.sbox1[j]) |
(this.sbox2[i] == this.sbox2[j]) |
(this.sbox3[i] == this.sbox3[j]) |
(this.sbox4[i] == this.sbox4[j])) break;
else j++;
}
if (j < SBOX_ENTRIES)
{
this.isWeakKey = 1;
break;
}
}
}
return (1 == this.isWeakKey);
}
}
/// <summary>Resets the instance with new or initial key material. Allows the switch of
/// keys at runtime without any new internal object allocation.</summary>
/// <param name="key">The buffer with the key material.</param>
/// <param name="ofs">Position at which the key material starts in the buffer.</param>
/// <param name="len">Size of the key material, up to MAX_KEY_LENGTH bytes.</param>
public void Initialize(byte[] key, int ofs, int len)
{
int i, j, keyPos, keyEnd;
uint build, hi, lo;
uint[] box;
this.isWeakKey = -1;
Array.Copy(PBOX_INIT , 0, this.pbox , 0, PBOX_INIT.Length);
Array.Copy(SBOX_INIT_1, 0, this.sbox1, 0, SBOX_INIT_1.Length);
Array.Copy(SBOX_INIT_2, 0, this.sbox2, 0, SBOX_INIT_2.Length);
Array.Copy(SBOX_INIT_3, 0, this.sbox3, 0, SBOX_INIT_3.Length);
Array.Copy(SBOX_INIT_4, 0, this.sbox4, 0, SBOX_INIT_4.Length);
if (0 == len)
{
return;
}
keyPos = ofs;
keyEnd = ofs + len;
build = 0;
for (i = 0; i < PBOX_ENTRIES; i++)
{
for (j = 0; j < 4; j++)
{
build = (build << 8) | key[keyPos];
if (++keyPos == keyEnd)
{
keyPos = ofs;
}
}
this.pbox[i] ^= build;
}
hi = lo = 0;
box = this.pbox;
for (i = 0; i < PBOX_ENTRIES;)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i++] = hi;
box[i++] = lo;
}
box = this.sbox1;
for (i = 0; i < SBOX_ENTRIES;)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i++] = hi;
box[i++] = lo;
}
box = this.sbox2;
for (i = 0; i < SBOX_ENTRIES;)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i++] = hi;
box[i++] = lo;
}
box = this.sbox3;
for (i = 0; i < SBOX_ENTRIES;)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i++] = hi;
box[i++] = lo;
}
box = this.sbox4;
for (i = 0; i < SBOX_ENTRIES;)
{
EncryptBlock(hi, lo, out hi, out lo);
box[i++] = hi;
box[i++] = lo;
}
}
/// <summary>Zero constructor, properly initializes an instance. Initialize afterwards
/// to set up a valid key!</summary>
public BlowfishECB()
{
Initialize(null, 0, 0);
}
/// <see cref="BlowfishECB.Initialize"/>
public BlowfishECB(byte[] key, int ofs, int len)
{
Initialize(key, ofs, len);
}
/// <summary> Deletes all internal data structures and invalidates this instance.</summary>
/// <remarks>Call this method as soon as the work with a particular instance is done,
/// so no sensitive translated key material remains. The instance is invalid after this
/// call and usage can lead to unexpected results!</remarks>
public void Invalidate()
{
Array.Clear(this.pbox, 0, this.pbox.Length);
Array.Clear(this.sbox1, 0, this.sbox1.Length);
Array.Clear(this.sbox2, 0, this.sbox2.Length);
Array.Clear(this.sbox3, 0, this.sbox3.Length);
Array.Clear(this.sbox4, 0, this.sbox4.Length);
Array.Clear(this.block, 0, this.block.Length);
}
static readonly byte[] TEST_KEY = { 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef };
static readonly uint[] TEST_VECTOR_PLAIN = { 0x30553228, 0x6d6f295a };
static readonly uint[] TEST_VECTOR_CIPHER = { 0x55cb3774, 0xd13ef201 };
/// <summary>To execute a selftest.</summary>
/// <remarks>Call this method to make sure that the implemenation is able to produce
/// valid output according to the specification. This should usually be done at process
/// startup time, before the usage of this class and its inherited variants.</remarks>
/// <returns>True if the selftest passed or false is it failed. In such a case you must
/// not use the cipher to avoid data corruption!</returns>
public static bool RunSelfTest()
{
uint hi, lo;
BlowfishECB bfe;
hi = TEST_VECTOR_PLAIN[0];
lo = TEST_VECTOR_PLAIN[1];
bfe = new BlowfishECB(TEST_KEY, 0, TEST_KEY.Length);
bfe.EncryptBlock(hi, lo, out hi, out lo);
if ((TEST_VECTOR_CIPHER[0] != hi) ||
(TEST_VECTOR_CIPHER[1] != lo))
{
return false;
}
bfe.DecryptBlock(hi, lo, out hi, out lo);
if ((TEST_VECTOR_PLAIN[0] != hi) ||
(TEST_VECTOR_PLAIN[1] != lo))
{
return false;
}
return true;
}
/// <summary>Encrypts a single block.</summary>
/// <param name="hi">The high 32bit word of the block.</param>
/// <param name="lo">The low 32bit word of the block.</param>
/// <param name="outHi">Where to put the encrypted high word.</param>
/// <param name="outLo">Where to put the encrypted low word.</param>
public void EncryptBlock(
uint hi,
uint lo,
out uint outHi,
out uint outLo)
{
byte[] block;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -