📄 blowfish.cs
字号:
/* ---------------------------------------------------------------------------
*
* Copyright (c) Routrek Networks, Inc. All Rights Reserved..
*
* This file is a part of the Granados SSH Client Library that is subject to
* the license included in the distributed package.
* You may not use this file except in compliance with the license.
*
* ---------------------------------------------------------------------------
*
* I implemented this algorithm with reference to following products and books though the algorithm is known publicly.
* * MindTerm ( AppGate Network Security )
* * Applied Cryptography ( Bruce Schneier )
*/
using System;
namespace Routrek.Crypto {
public class Blowfish {
byte[] IV;
byte[] enc;
byte[] dec;
private const int BLOCK_SIZE = 8; // bytes in a data-block
protected uint[] S0;
protected uint[] S1;
protected uint[] S2;
protected uint[] S3;
protected uint[] P;
public Blowfish() {
S0 = new uint[256];
S1 = new uint[256];
S2 = new uint[256];
S3 = new uint[256];
P = new uint[18];
IV = new byte[8];
enc = new byte[8];
dec = new byte[8];
}
public void SetIV(byte[] newiv) {
Array.Copy(newiv, 0, IV, 0, IV.Length);
}
public void initializeKey(byte[] key) {
int i, j, len = key.Length;
uint temp;
Array.Copy(blowfish_pbox, 0, P, 0, 18);
Array.Copy(blowfish_sbox, 0, S0, 0, 256);
Array.Copy(blowfish_sbox, 256, S1, 0, 256);
Array.Copy(blowfish_sbox, 512, S2, 0, 256);
Array.Copy(blowfish_sbox, 768, S3, 0, 256);
for(j = 0, i = 0; i < 16 + 2; i++) {
temp = (((uint)(key[j ]) << 24) |
((uint)(key[(j + 1) % len]) << 16) |
((uint)(key[(j + 2) % len]) << 8) |
((uint)(key[(j + 3) % len])));
P[i] = P[i] ^ temp;
j = (j + 4) % len;
}
byte[] LR = new byte[8];
for(i = 0; i < 16 + 2; i += 2) {
blockEncrypt(LR, 0, LR, 0);
P[i] = CipherUtil.GetIntBE(LR, 0);
P[i + 1] = CipherUtil.GetIntBE(LR, 4);
}
for(j = 0; j < 256; j += 2) {
blockEncrypt(LR, 0, LR, 0);
S0[j] = CipherUtil.GetIntBE(LR, 0);
S0[j + 1] = CipherUtil.GetIntBE(LR, 4);
}
for(j = 0; j < 256; j += 2) {
blockEncrypt(LR, 0, LR, 0);
S1[j] = CipherUtil.GetIntBE(LR, 0);
S1[j + 1] = CipherUtil.GetIntBE(LR, 4);
}
for(j = 0; j < 256; j += 2) {
blockEncrypt(LR, 0, LR, 0);
S2[j] = CipherUtil.GetIntBE(LR, 0);
S2[j + 1] = CipherUtil.GetIntBE(LR, 4);
}
for(j = 0; j < 256; j += 2) {
blockEncrypt(LR, 0, LR, 0);
S3[j] = CipherUtil.GetIntBE(LR, 0);
S3[j + 1] = CipherUtil.GetIntBE(LR, 4);
}
}
public void blockEncrypt(byte[] input, int inOffset, byte[] output, int outOffset) {
uint L, R;
L = CipherUtil.GetIntBE(input, inOffset);
R = CipherUtil.GetIntBE(input, inOffset + 4);
L ^= P[0];
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[1]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[2]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[3]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[4]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[5]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[6]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[7]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[8]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[9]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[10]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[11]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[12]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[13]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[14]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[15]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[16]);
R ^= P[17];
CipherUtil.PutIntBE(R, output, outOffset);
CipherUtil.PutIntBE(L, output, outOffset + 4);
}
public void blockDecrypt(byte[] input, int inOffset, byte[] output, int outOffset) {
uint L, R;
L = CipherUtil.GetIntBE(input, inOffset);
R = CipherUtil.GetIntBE(input, inOffset + 4);
L ^= P[17];
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[16]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[15]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[14]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[13]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[12]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[11]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[10]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[9]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[8]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[7]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[6]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[5]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[4]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[3]);
R ^= ((((S0[(int)((L >> 24) & 0xff)] + S1[(int)((L >> 16) & 0xff)]) ^
S2[(int)((L >> 8) & 0xff)]) + S3[(int)(L & 0xff)]) ^ P[2]);
L ^= ((((S0[(int)((R >> 24) & 0xff)] + S1[(int)((R >> 16) & 0xff)]) ^
S2[(int)((R >> 8) & 0xff)]) + S3[(int)(R & 0xff)]) ^ P[1]);
R ^= P[0];
CipherUtil.PutIntBE(R, output, outOffset);
CipherUtil.PutIntBE(L, output, outOffset + 4);
}
public void encryptSSH1Style(byte[] src, int srcOff, int len, byte[] dest, int destOff) {
int end = srcOff + len;
int i, j;
for(int si = srcOff, di = destOff; si < end; si += 8, di += 8) {
for(i = 0; i < 4; i++) {
j = 3 - i;
IV[i] ^= src[si + j];
IV[i + 4] ^= src[si + 4 + j];
}
blockEncrypt(IV, 0, IV, 0);
for(i = 0; i < 4; i++) {
j = 3 - i;
dest[di + i] = IV[j];
dest[di + i + 4] = IV[4 + j];
}
}
}
public void decryptSSH1Style(byte[] src, int srcOff, int len, byte[] dest, int destOff) {
int end = srcOff + len;
int i, j;
for(int si = srcOff, di = destOff; si < end; si += 8, di += 8) {
for(i = 0; i < 4; i++) {
j = (3 - i);
enc[i] = src[si + j];
enc[i + 4] = src[si + 4 + j];
}
blockDecrypt(enc, 0, dec, 0);
for(i = 0; i < 4; i++) {
j = 3 - i;
dest[di + i] = (byte)((IV[j] ^ dec[j]) & 0xff);
IV[j] = enc[j];
dest[di + i + 4] = (byte)((IV[4 + j] ^ dec[4 + j]) & 0xff);
IV[4 + j] = enc[4 + j];
}
}
}
public void encryptCBC(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
int nBlocks = inputLen / BLOCK_SIZE;
for(int bc = 0; bc < nBlocks; bc++) {
CipherUtil.BlockXor(input, inputOffset, BLOCK_SIZE, IV, 0);
blockEncrypt(IV, 0, output, outputOffset);
Array.Copy(output, outputOffset, IV, 0, BLOCK_SIZE);
inputOffset += BLOCK_SIZE;
outputOffset += BLOCK_SIZE;
}
}
public void decryptCBC(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) {
byte[] tmpBlk = new byte[BLOCK_SIZE];
int nBlocks = inputLen / BLOCK_SIZE;
for(int bc = 0; bc < nBlocks; bc++) {
blockDecrypt(input, inputOffset, tmpBlk, 0);
for(int i = 0; i < BLOCK_SIZE; i++) {
tmpBlk[i] ^= IV[i];
IV[i] = input[inputOffset + i];
output[outputOffset + i] = tmpBlk[i];
}
inputOffset += BLOCK_SIZE;
outputOffset += BLOCK_SIZE;
}
}
private static readonly uint[] blowfish_pbox = new uint[] {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
};
private static readonly uint[] blowfish_sbox = new uint[] {
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -