📄 blowfishcipher.java
字号:
// BlowfishCipher - the Blowfish encryption method
//
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/
package Acme.Crypto;
import java.io.*;
/// The Blowfish encryption method.
// <P>
// This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
// in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream,
// it does around 8000 bytes/second, somewhat faster than Acme.Crypto.DesCipher.
// <P>
// With help from David Brownell.
// <P>
// <A HREF="/resources/classes/Acme/Crypto/BlowfishCipher.java">Fetch the software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
// <P>
// @see EncryptedOutputStream
// @see EncryptedInputStream
public class BlowfishCipher extends BlockCipher
{
private static final int N = 16; // number of rounds
// Constructor, string key.
public BlowfishCipher( String keyStr )
{
super( 0, 8 );
setKey( keyStr );
}
// Constructor, byte-array key.
public BlowfishCipher( byte[] key )
{
super( 0, 8 );
setKey( key );
}
// Key routines.
private int[] P = new int[N + 2];
private int[][] S = new int[4][256];
/// Set the key.
public void setKey( byte[] key )
{
int i, j, k;
int data, datal, datar;
// Initialize P and S.
for ( i = 0; i < N + 2; ++i )
P[i] = Pinit[i];
for ( i = 0; i < 4; ++i )
for ( j = 0; j < 256; ++j )
S[i][j] = Sinit[i][j];
// XOR the key into P.
j = 0;
for ( i = 0; i < N + 2; ++i )
{
data = 0x00000000;
for ( k = 0; k < 4; ++k )
{
data = ( data << 8 ) | ( key[j % key.length] & 0xff );
++j;
}
P[i] ^= data;
}
// Auto-munge P and S.
int[] datalr = { 0x00000000, 0x00000000 };
for ( i = 0; i < N + 2; i += 2 )
{
encrypt( datalr );
P[i] = datalr[0];
P[i + 1] = datalr[1];
}
for ( i = 0; i < 4; ++i )
{
for ( j = 0; j < 256; j += 2 )
{
encrypt( datalr );
S[i][j] = datalr[0];
S[i][j + 1] = datalr[1];
}
}
}
// Block encryption routines.
/// Encrypt a block of eight bytes.
public void encrypt( byte[] clearText, int clearOff, byte[] cipherText, int cipherOff )
{
int[] tempInts = new int[2];
squashBytesToInts( clearText, clearOff, tempInts, 0, 2 );
encrypt( tempInts );
spreadIntsToBytes( tempInts, 0, cipherText, cipherOff, 2 );
}
/// Encrypt a block of two ints.
private void encrypt( int[] text )
{
int xl, xr, temp;
int i;
xl = text[0];
xr = text[1];
xl ^= P[0];
xr ^= F( xl ) ^ P[1];
xl ^= F( xr ) ^ P[2];
xr ^= F( xl ) ^ P[3];
xl ^= F( xr ) ^ P[4];
xr ^= F( xl ) ^ P[5];
xl ^= F( xr ) ^ P[6];
xr ^= F( xl ) ^ P[7];
xl ^= F( xr ) ^ P[8];
xr ^= F( xl ) ^ P[9];
xl ^= F( xr ) ^ P[10];
xr ^= F( xl ) ^ P[11];
xl ^= F( xr ) ^ P[12];
xr ^= F( xl ) ^ P[13];
xl ^= F( xr ) ^ P[14];
xr ^= F( xl ) ^ P[15];
xl ^= F( xr ) ^ P[16];
xr ^= P[17];
text[0] = xr;
text[1] = xl;
}
/// Decrypt a block of eight bytes.
public void decrypt( byte[] cipherText, int cipherOff, byte[] clearText, int clearOff )
{
int[] tempInts = new int[2];
squashBytesToInts( cipherText, cipherOff, tempInts, 0, 2 );
decrypt( tempInts );
spreadIntsToBytes( tempInts, 0, clearText, clearOff, 2 );
}
/// Decrypt a block of two ints.
public void decrypt( int[] text )
{
int xl, xr, temp;
int i;
xr = text[0];
xl = text[1];
xr ^= P[17];
xl ^= F( xr ) ^ P[16];
xr ^= F( xl ) ^ P[15];
xl ^= F( xr ) ^ P[14];
xr ^= F( xl ) ^ P[13];
xl ^= F( xr ) ^ P[12];
xr ^= F( xl ) ^ P[11];
xl ^= F( xr ) ^ P[10];
xr ^= F( xl ) ^ P[9];
xl ^= F( xr ) ^ P[8];
xr ^= F( xl ) ^ P[7];
xl ^= F( xr ) ^ P[6];
xr ^= F( xl ) ^ P[5];
xl ^= F( xr ) ^ P[4];
xr ^= F( xl ) ^ P[3];
xl ^= F( xr ) ^ P[2];
xr ^= F( xl ) ^ P[1];
xl ^= P[0];
text[0] = xl;
text[1] = xr;
}
private int F( int x )
{
int a, b, c, d;
d = x & 0x00FF;
x >>= 8;
c = x & 0x00FF;
x >>= 8;
b = x & 0x00FF;
x >>= 8;
a = x & 0x00FF;
return ( ( S[0][a] + S[1][b] ) ^ S[2][c] ) + S[3][d];
}
/// Test routine.
public static void main( String[] args )
{
byte[] cipherText = new byte[8];
byte[] decipherText = new byte[8];
BlockCipher bf1 = new BlowfishCipher( "abcdefghijklmnopqrstuvwxyz" );
byte[] clearText1 = {
(byte) 0x42, (byte) 0x4c, (byte) 0x4f, (byte) 0x57,
(byte) 0x46, (byte) 0x49, (byte) 0x53, (byte) 0x48 };
byte[] desiredText1 = {
(byte) 0x32, (byte) 0x4e, (byte) 0xd0, (byte) 0xfe,
(byte) 0xf4, (byte) 0x13, (byte) 0xa2, (byte) 0x03 };
System.out.println( "cleartext: " + toStringBlock( clearText1 ) );
bf1.encrypt( clearText1, cipherText );
System.out.println( "encrypted: " + toStringBlock( cipherText ) );
System.out.println( "desired: " + toStringBlock( desiredText1 ) );
bf1.decrypt( cipherText, decipherText );
System.out.println( "decrypted: " + toStringBlock( decipherText ) );
System.out.println();
BlockCipher bf2 = new BlowfishCipher( "Who is John Galt?" );
byte[] clearText2 = {
(byte) 0xfe, (byte) 0xdc, (byte) 0xba, (byte) 0x98,
(byte) 0x76, (byte) 0x54, (byte) 0x32, (byte) 0x10 };
byte[] desiredText2 = {
(byte) 0xcc, (byte) 0x91, (byte) 0x73, (byte) 0x2b,
(byte) 0x80, (byte) 0x22, (byte) 0xf6, (byte) 0x84 };
System.out.println( "cleartext: " + toStringBlock( clearText2 ) );
bf2.encrypt( clearText2, cipherText );
System.out.println( "encrypted: " + toStringBlock( cipherText ) );
System.out.println( "desired: " + toStringBlock( desiredText2 ) );
bf2.decrypt( cipherText, decipherText );
System.out.println( "decrypted: " + toStringBlock( decipherText ) );
}
// Initialization data.
private static final int[] Pinit = {
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -