package com.limegroup.gnutella.guess;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Random;
import java.math.BigInteger;
import junit.framework.Test;
import com.limegroup.gnutella.util.BaseTestCase;
import com.limegroup.gnutella.util.PrivilegedAccessor;
public class TEAQueryKeyGeneratorTest extends BaseTestCase {
public TEAQueryKeyGeneratorTest(String name) {
super(name);
}
public static Test suite() {
return buildTestSuite(TEAQueryKeyGeneratorTest.class);
}
// Generates 420 QueryKeys using random secret keys
// and makes sure none of them contain 0x00 or 0x1C
public void testAllBytesNetworkSafe() throws Exception {
Random rand = new Random();
InetAddress[] addresses = new InetAddress[20];
byte[] randAddressBytes = new byte[4];
for(int i=addresses.length-1; i >= 0; --i) {
rand.nextBytes(randAddressBytes);
addresses[i] = InetAddress.getByAddress(randAddressBytes);
}
for(int i=20; i > 0; --i) {
TEAQueryKeyGenerator key = new TEAQueryKeyGenerator();
for(int j=addresses.length-1; j >= 0; --j) {
byte[] keyBytes = key.getKeyBytes(addresses[j], 1024 + i);
for(int k=keyBytes.length-1; k >= 0; --k) {
int keyByte = keyBytes[k];
if (keyByte == 0x00 || keyByte == 0x1C) {
byte[] printBuf = new byte[keyBytes.length+1];
System.arraycopy(keyBytes, 0, printBuf, 1, keyBytes.length);
printBuf[0] = (byte) 1;
fail("keyBytes contains illegal byte "+
(new BigInteger(1,printBuf)).toString(16));
}
}
}
}
}
// Generates 420 QueryKeys using random secret keys
// and makes sure that they all can be verified by
// the QueryKeyGenerator that created them
public void testKeyVerification() throws Exception {
Random rand = new Random();
InetAddress[] addresses = new InetAddress[20];
byte[] randAddressBytes = new byte[4];
for(int i=addresses.length-1; i >= 0; --i) {
rand.nextBytes(randAddressBytes);
addresses[i] = InetAddress.getByAddress(randAddressBytes);
}
for(int i=20; i > 0; --i) {
TEAQueryKeyGenerator key = new TEAQueryKeyGenerator();
for(int j=addresses.length-1; j >= 0; --j) {
byte[] keyBytes = key.getKeyBytes(addresses[j], 1024 + i);
if (! key.checkKeyBytes(keyBytes, addresses[j], 1024 + i)) {
byte[] printBuf = new byte[keyBytes.length+1];
System.arraycopy(keyBytes, 0, printBuf, 1, keyBytes.length);
printBuf[0] = (byte) 1;
fail("keyBytes fails to verify "+
(new BigInteger(1,printBuf)).toString(16));
}
}
}
}
// Breaks abstraction, but ensures that TEA is implemented correctly
public void testTEAtestVectors() throws Exception {
TEAVectorTester key = new TEAVectorTester(0,0,0,0,0,0);
long cipherBlock = key.publicEncrypt(0x0L);
assertEquals("TEA test vecotr failed", 0x41EA3A0A94BAA940L, cipherBlock);
assertEquals("TEA test vector failed.", 0x41EA3A0A, key.encrypt(0,0));
// get at the other half of the block and test the 64-bit rotation code
key = new TEAVectorTester(0,0,0,0,0,32);
assertEquals("TEA test vector failed.", 0x94BAA940, key.encrypt(0,0));
}
private class TEAVectorTester extends TEAQueryKeyGenerator {
/** Set up a tester with given TEA encryption keys */
public TEAVectorTester(int k0, int k1, int k2, int k3,
int preRotate, int postRotate) {
super(k0,k1,k2,k3, preRotate, postRotate);
}
/** In the absence of 0x00 and 0x1C bytes, returns the
* left int of the TEA encryption block after encrypting (left,right).
* Use the postRotate to get at different parts of the TEA encryption
* output.
*/
public int encrypt(int left, int right) throws UnknownHostException {
// Prepare right for the unusual encoding
// of IP addresses as ints used in QueryKeyGenerator
for(int i=0x80; i>0; i <<= 8) {
if ((right & i) != 0) {
right = (~right) ^ (i-1) ^ i;
}
}
byte[] ipBytes = new byte[4];
for(int i=0; i <= 3; ++i) {
ipBytes[i] = (byte) right;
right >>>= 8;
}
byte[] resultBytes = getKeyBytes(InetAddress.getByAddress(ipBytes), left);
int byteCount = resultBytes.length;
int result = 0;
for(int i=byteCount-4; i<byteCount ; ++i) {
result <<= 8;
result |= 0xFF & resultBytes[i];
}
return result;
}
// Accesses the private method super.encrypt(long)
public long publicEncrypt(long arg)
throws NoSuchMethodException, IllegalAccessException,
java.lang.reflect.InvocationTargetException {
Long result = (Long) PrivilegedAccessor.invokeMethod(this, "encrypt",
new Object[] { new Long(arg)},
new Class[] { long.class });
return result.longValue();
}
}
}