package freenet.crypt.ciphers;
import java.security.InvalidKeyException;
import freenet.crypt.BlockCipher;
import freenet.crypt.UnsupportedCipherException;
import freenet.support.HexUtil;
//import freenet.support.Logger;
import thaw.core.Logger;
/*
This code is part of the Java Adaptive Network Client by Ian Clarke.
It is distributed under the GNU Public Licence (GPL) version 2. See
http://www.gnu.org/ for further details of the GPL.
*/
/**
* Interfaces with the Rijndael AES candidate to implement the Rijndael
* algorithm
*/
public class Rijndael implements BlockCipher {
private Object sessionKey;
private final int keysize, blocksize;
// FIXME remove. This is used to simulate an old security threatening bug in order
// to have backwards compatibility with old keys.
private final int cryptBlockSize;
// for Util.getCipherByName.. and yes, screw you too, java
public Rijndael(Integer keysize) throws UnsupportedCipherException {
this(keysize.intValue());
}
public Rijndael(int keysize) throws UnsupportedCipherException {
this(keysize, 128, false);
}
/**
* Create a Rijndael instance.
* @param keysize The key size.
* @param blocksize The block size.
* @param fakeInsecure If true, only encrypt the first 128 bits of any block. This
* is insecure! It is used for backwards compatibility with old data encrypted with
* the old code.
* @throws UnsupportedCipherException
*/
public Rijndael(int keysize, int blocksize, boolean fakeInsecure) throws UnsupportedCipherException {
if (! ((keysize == 128) ||
(keysize == 192) ||
(keysize == 256)))
throw new UnsupportedCipherException("Invalid keysize");
if (! ((blocksize == 128) ||
(blocksize == 192) ||
(blocksize == 256)))
throw new UnsupportedCipherException("Invalid blocksize");
this.keysize=keysize;
this.blocksize=blocksize;
// FIXME This is deliberate insecurity! It is used for backwards compatibility *ONLY*!
// FIXME IT MUST BE REMOVED SOON!
if(fakeInsecure)
this.cryptBlockSize = 128;
else
this.cryptBlockSize = blocksize;
}
public Rijndael() {
this.keysize = 128;
this.blocksize = 128;
this.cryptBlockSize = 128;
}
public final int getBlockSize() {
return blocksize;
}
public final int getKeySize() {
return keysize;
}
public final void initialize(byte[] key) {
try {
byte[] nkey=new byte[keysize>>3];
System.arraycopy(key, 0, nkey, 0, nkey.length);
sessionKey=Rijndael_Algorithm.makeKey(nkey, cryptBlockSize/8);
} catch (InvalidKeyException e) {
e.printStackTrace();
Logger.error(this,"Invalid key");
}
}
public synchronized final void encipher(byte[] block, byte[] result) {
if(block.length != blocksize/8)
throw new IllegalArgumentException();
Rijndael_Algorithm.blockEncrypt(block, result, 0, sessionKey, cryptBlockSize/8);
}
/**
* @return Size of temporary int[] a, t. If these are passed in, this can speed
* things up by avoiding unnecessary allocations between rounds.
*/
public synchronized final int getTempArraySize() {
return cryptBlockSize/(8*4);
}
public synchronized final void encipher(byte[] block, byte[] result, int[] a, int[] t) {
if(block.length != blocksize/8)
throw new IllegalArgumentException();
if(a.length != t.length || t.length != cryptBlockSize/(8*4))
throw new IllegalArgumentException();
Rijndael_Algorithm.blockEncrypt(block, result, 0, sessionKey, cryptBlockSize/8, a, t);
}
public synchronized final void decipher(byte[] block, byte[] result) {
if(block.length != blocksize/8)
throw new IllegalArgumentException();
Rijndael_Algorithm.blockDecrypt(block, result, 0, sessionKey, cryptBlockSize/8);
}
public static void main(String[] args) throws UnsupportedCipherException {
// Perform the Monte Carlo test
System.out.println("KEYSIZE=128\n");
monteCarlo(128);
System.out.println("=========================\n");
System.out.println("KEYSIZE=192\n");
monteCarlo(192);
System.out.println("=========================\n");
System.out.println("KEYSIZE=256\n");
monteCarlo(256);
}
static void monteCarlo(int keySize) throws UnsupportedCipherException {
Rijndael ctx=new Rijndael(keySize);
int kb=keySize/8;
byte[] P=new byte[16], C=new byte[16],
CL=new byte[16], KEY=new byte[kb];
for (int i=0; i<400; i++) {
System.out.println("I="+i);
System.out.println("KEY="+HexUtil.bytesToHex(KEY,0,kb));
System.out.println("PT="+HexUtil.bytesToHex(P,0,16));
ctx.initialize(KEY);
for (int j=0; j<10000; j++) {
System.arraycopy(C, 0, CL, 0, C.length);
ctx.encipher(P, C);
System.arraycopy(C, 0, P, 0, P.length);
}
System.out.println("CT="+HexUtil.bytesToHex(C,0,16));
for (int x=0; x<kb; x++) {
if (keySize==192)
if (x<8)
KEY[x]^=CL[8+x];
else
KEY[x]^=C[x-8];
else if (keySize==256)
if (x<16)
KEY[x]^=CL[x];
else
KEY[x]^=C[x-16];
else KEY[x]^=C[x];
}
if (keySize==192)
for (int x=0; x<8; x++)
KEY[x+16]^=CL[x+8];
else if (keySize==256)
for (int x=0; x<16; x++)
KEY[x+16]^=CL[x];
System.out.println();
}
}
}