📄 blowfishengine.java
字号:
0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
};
//====================================
// Useful constants
//====================================
private static final int ROUNDS = 16;
private static final int BLOCK_SIZE = 8; // bytes = 64 bits
private static final int SBOX_SK = 256;
private static final int P_SZ = ROUNDS + 2;
private final int[] S0, S1, S2, S3; // the s-boxes
private final int[] P; // the p-array
private boolean encrypting = false;
private byte[] workingKey = null;
public BlowfishEngine() {
S0 = new int[SBOX_SK];
S1 = new int[SBOX_SK];
S2 = new int[SBOX_SK];
S3 = new int[SBOX_SK];
P = new int[P_SZ];
}
/**
* initialise a Blowfish cipher.
*
* @param forEncryption whether or not we are for encryption.
* @param params the parameters required to set up the cipher.
* @exception IllegalArgumentException if the params argument is
* inappropriate.
*/
public void init(
boolean encrypting,
byte[] key) {
this.encrypting = encrypting;
this.workingKey = key;
setKey(this.workingKey);
return;
}
public String getAlgorithmName() {
return "Blowfish";
}
public final int processBlock(
byte[] in,
int inOff,
byte[] out,
int outOff) throws IOException {
if (workingKey == null) {
throw new IllegalStateException("Blowfish not initialised");
}
if ( (inOff + BLOCK_SIZE) > in.length) {
throw new IOException("input buffer too short");
}
if ( (outOff + BLOCK_SIZE) > out.length) {
throw new IOException("output buffer too short");
}
if (encrypting) {
encryptBlock(in, inOff, out, outOff);
}
else {
decryptBlock(in, inOff, out, outOff);
}
return BLOCK_SIZE;
}
public void reset() {
}
public int getBlockSize() {
return BLOCK_SIZE;
}
//==================================
// Private Implementation
//==================================
private int F(int x) {
return ( ( (S0[ (x >>> 24)] + S1[ (x >>> 16) & 0xff])
^ S2[ (x >>> 8) & 0xff]) + S3[x & 0xff]);
}
/**
* apply the encryption cycle to each value pair in the table.
*/
private void processTable(
int xl,
int xr,
int[] table) {
int size = table.length;
for (int s = 0; s < size; s += 2) {
xl ^= P[0];
for (int i = 1; i < ROUNDS; i += 2) {
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr ^= P[ROUNDS + 1];
table[s] = xr;
table[s + 1] = xl;
xr = xl; // end of cycle swap
xl = table[s];
}
}
private void setKey(byte[] key) {
/*
* - comments are from _Applied Crypto_, Schneier, p338
* please be careful comparing the two, AC numbers the
* arrays from 1, the enclosed code from 0.
*
* (1)
* Initialise the S-boxes and the P-array, with a fixed string
* This string contains the hexadecimal digits of pi (3.141...)
*/
System.arraycopy(KS0, 0, S0, 0, SBOX_SK);
System.arraycopy(KS1, 0, S1, 0, SBOX_SK);
System.arraycopy(KS2, 0, S2, 0, SBOX_SK);
System.arraycopy(KS3, 0, S3, 0, SBOX_SK);
System.arraycopy(KP, 0, P, 0, P_SZ);
/*
* (2)
* Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
* second 32-bits of the key, and so on for all bits of the key
* (up to P[17]). Repeatedly cycle through the key bits until the
* entire P-array has been XOR-ed with the key bits
*/
int keyLength = key.length;
int keyIndex = 0;
for (int i = 0; i < P_SZ; i++) {
// get the 32 bits of the key, in 4 * 8 bit chunks
int data = 0x0000000;
for (int j = 0; j < 4; j++) {
// create a 32 bit block
data = (data << 8) | (key[keyIndex++] & 0xff);
// wrap when we get to the end of the key
if (keyIndex >= keyLength) {
keyIndex = 0;
}
}
// XOR the newly created 32 bit chunk onto the P-array
P[i] ^= data;
}
/*
* (3)
* Encrypt the all-zero string with the Blowfish algorithm, using
* the subkeys described in (1) and (2)
*
* (4)
* Replace P1 and P2 with the output of step (3)
*
* (5)
* Encrypt the output of step(3) using the Blowfish algorithm,
* with the modified subkeys.
*
* (6)
* Replace P3 and P4 with the output of step (5)
*
* (7)
* Continue the process, replacing all elements of the P-array
* and then all four S-boxes in order, with the output of the
* continuously changing Blowfish algorithm
*/
processTable(0, 0, P);
processTable(P[P_SZ - 2], P[P_SZ - 1], S0);
processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
}
/**
* Encrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
private void encryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex) {
int xl = BytesTo32bits(src, srcIndex);
int xr = BytesTo32bits(src, srcIndex + 4);
xl ^= P[0];
for (int i = 1; i < ROUNDS; i += 2) {
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr ^= P[ROUNDS + 1];
Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex + 4);
}
/**
* Decrypt the given input starting at the given offset and place
* the result in the provided buffer starting at the given offset.
* The input will be an exact multiple of our blocksize.
*/
private void decryptBlock(
byte[] src,
int srcIndex,
byte[] dst,
int dstIndex) {
int xl = BytesTo32bits(src, srcIndex);
int xr = BytesTo32bits(src, srcIndex + 4);
xl ^= P[ROUNDS + 1];
for (int i = ROUNDS; i > 0; i -= 2) {
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i - 1];
}
xr ^= P[0];
Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex + 4);
}
private int BytesTo32bits(byte[] b, int i) {
return ( (b[i] & 0xff) << 24) |
( (b[i + 1] & 0xff) << 16) |
( (b[i + 2] & 0xff) << 8) |
( (b[i + 3] & 0xff));
}
private void Bits32ToBytes(int in, byte[] b, int offset) {
b[offset + 3] = (byte) in;
b[offset + 2] = (byte) (in >> 8);
b[offset + 1] = (byte) (in >> 16);
b[offset] = (byte) (in >> 24);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -