From 1b0e6a6bb938202857ac80a305eabee3f6de3943 Mon Sep 17 00:00:00 2001
From: Chetan Hosmani <chetanspecial@gmail.com>
Date: Wed, 4 Apr 2012 01:49:42 +0530
Subject: [PATCH] Add JCACipher and modify FNPPacketMangler

---
 src/freenet/crypt/ciphers/JCACipher.java |  132 ++++++++++++++++++++++++++++++
 src/freenet/node/FNPPacketMangler.java   |   69 ++++++++++------
 2 files changed, 177 insertions(+), 24 deletions(-)
 create mode 100644 src/freenet/crypt/ciphers/JCACipher.java

diff --git a/src/freenet/crypt/ciphers/JCACipher.java b/src/freenet/crypt/ciphers/JCACipher.java
new file mode 100644
index 0000000..a2fbfae
--- /dev/null
+++ b/src/freenet/crypt/ciphers/JCACipher.java
@@ -0,0 +1,132 @@
+package freenet.crypt.ciphers;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+
+import freenet.crypt.BlockCipher;
+import freenet.support.Logger;
+
+public class JCACipher implements BlockCipher {
+	
+	private final int keySize, blockSize;
+	private Cipher aesCipher;
+	private SecretKeySpec sKey;
+	private final String algorithm, cipherTransformation;
+	private boolean flag = false;
+	
+	/**
+	 *  Create a JCA based Cipher
+	 *  <br /> keySize = 256
+	 *  <br /> blockSize = 256
+	 *  <br /> Encryption = AES/CFB32
+	 */
+	public JCACipher(){
+		this.keySize = 256;
+		this.blockSize = 256;
+		this.algorithm = "AES";
+		this.cipherTransformation = "AES/CFB32/PKCS5Padding";
+	}
+	
+	/**
+	 *  Create a JCA based Cipher
+	 *  @param keysize The key size.
+	 *  @param blocksize The block size.
+	 *  <br /> Encryption = AES/CFB32 
+	 */
+	public JCACipher(int keySize, int blockSize){
+		this.keySize = keySize;
+		this.blockSize = blockSize;
+		this.algorithm = "AES";
+		this.cipherTransformation = "AES/CFB" + (blockSize/8) + "/PKCS5Padding";
+	}
+
+	/**
+	 *  Create a JCA based Cipher
+	 *  @param keysize The key size.
+	 *  @param blocksize The block size.
+	 *  @param algorithm The name of the SecretKey algorithm. e.g. AES, DES, PBE
+	 *  @param cipherTransformation The name of the transformation used to generate Cipher. e.g. AES/CFB32/PKCS5Padding
+	 *  <br /> Please refer to JCA Standard Algorithm Name Documentation for details
+	 */
+	public JCACipher(int keySize, int blockSize, String algorithm, String cipherTransformation){
+		this.keySize = keySize;
+		this.blockSize = blockSize;
+		this.algorithm = algorithm;
+		this.cipherTransformation = cipherTransformation;
+	}
+	
+	@Override
+	public final void initialize(byte[] key){
+		if(!flag){
+			try {
+				sKey = new SecretKeySpec(key, algorithm);
+				aesCipher = Cipher.getInstance(cipherTransformation);
+				flag = true;
+			} catch (NoSuchAlgorithmException e) {
+				e.printStackTrace();
+				Logger.error(this,"No such algorithm");
+			}catch (NoSuchPaddingException e) {
+				e.printStackTrace();
+				Logger.error(this,"No such padding mechanism");
+			}
+		}
+		else
+			throw new IllegalStateException("Cipher cannot be re-initialized");
+	}
+
+	@Override
+	public final int getKeySize() {
+		return keySize;
+	}
+
+	@Override
+	public final int getBlockSize() {
+		return blockSize;
+	}
+
+	@Override
+	public synchronized final void encipher(byte[] block, byte[] result) {
+		if(flag){
+			try {
+				aesCipher.init(Cipher.ENCRYPT_MODE, sKey);
+				result = aesCipher.doFinal(block);
+			} catch (IllegalBlockSizeException e) {
+				e.printStackTrace();
+				Logger.error(this,"Invalid block size");
+			} catch (BadPaddingException e) {
+				e.printStackTrace();
+				Logger.error(this,"Invalid padding of data");
+			} catch (InvalidKeyException e) {
+				e.printStackTrace();
+				Logger.error(this,"Invalid keys");
+			}
+		}
+		else
+			throw new IllegalStateException("Initialize Cipher with a key");
+	}
+
+	@Override
+	public synchronized final void decipher(byte[] block, byte[] result) {
+		if(flag){
+			try {
+				aesCipher.init(Cipher.DECRYPT_MODE, sKey);
+				result = aesCipher.doFinal(block);
+			} catch (IllegalBlockSizeException e) {
+				e.printStackTrace();
+			} catch (BadPaddingException e) {
+				e.printStackTrace();
+			} catch (InvalidKeyException e) {
+				e.printStackTrace();
+			}
+		}
+		else
+			throw new IllegalStateException("Initialize Cipher with a key");
+	}
+
+}
diff --git a/src/freenet/node/FNPPacketMangler.java b/src/freenet/node/FNPPacketMangler.java
index 22ed11a..5417548 100644
--- a/src/freenet/node/FNPPacketMangler.java
+++ b/src/freenet/node/FNPPacketMangler.java
@@ -26,6 +26,7 @@ import freenet.crypt.HMAC;
 import freenet.crypt.PCFBMode;
 import freenet.crypt.SHA256;
 import freenet.crypt.UnsupportedCipherException;
+import freenet.crypt.ciphers.JCACipher;
 import freenet.crypt.ciphers.Rijndael;
 import freenet.io.AddressTracker;
 import freenet.io.AddressTracker.Status;
@@ -621,7 +622,7 @@ public class FNPPacketMangler implements OutgoingPacketMangler {
 			Logger.error(this, "Decrypted auth packet but invalid version: "+version);
 			return;
 		}
-		if(!(negType == 2 || negType == 4 || negType == 6 || negType == 7)) {
+		if(!(negType == 2 || negType == 4 || negType == 6 || negType == 7 || negType == 8)) {
 			Logger.error(this, "Unknown neg type: "+negType);
 			return;
 		}
@@ -668,7 +669,7 @@ public class FNPPacketMangler implements OutgoingPacketMangler {
 			Logger.error(this, "Decrypted auth packet but invalid version: "+version);
 			return;
 		}
-		if(!(negType == 2 || negType == 4 || negType == 6 || negType == 7)) {
+		if(!(negType == 2 || negType == 4 || negType == 6 || negType == 7 || negType == 8)) {
 			Logger.error(this, "Unknown neg type: "+negType);
 			return;
 		}
@@ -734,7 +735,7 @@ public class FNPPacketMangler implements OutgoingPacketMangler {
 		} else if (negType == 1) {
 			Logger.error(this, "Old StationToStation (negType 1) not supported.");
 			return;
-		} else if (negType==2 || negType == 4 || negType == 6 || negType == 7) {
+		} else if (negType==2 || negType == 4 || negType == 6 || negType == 7 || negType == 8) {
 			// negType == 3 was buggy
 			// negType == 4 => negotiate whether to use a new PacketTracker when rekeying
 			// negType == 5 => same as 4, but use new packet format after negotiation
@@ -1351,17 +1352,26 @@ public class FNPPacketMangler implements OutgoingPacketMangler {
 		BlockCipher outgoingCipher = null;
 		BlockCipher incommingCipher = null;
 		BlockCipher ivCipher = null;
-		try {
-			outgoingCipher = new Rijndael(256, 256);
-			incommingCipher = new Rijndael(256, 256);
-			ivCipher = new Rijndael(256, 256);
-		} catch (UnsupportedCipherException e) {
-			throw new RuntimeException(e);
+		if(negType != 8){
+			try {
+				outgoingCipher = new Rijndael(256, 256);
+				incommingCipher = new Rijndael(256, 256);
+				ivCipher = new Rijndael(256, 256);
+			} catch (UnsupportedCipherException e) {
+				throw new RuntimeException(e);
+			}
+			outgoingCipher.initialize(outgoingKey);
+			incommingCipher.initialize(incommingKey);
+			ivCipher.initialize(ivKey);
+		}
+		else{
+			outgoingCipher = new JCACipher(256, 256);
+			incommingCipher = new JCACipher(256, 256);
+			ivCipher = new JCACipher(256, 256);
+			outgoingCipher.initialize(outgoingKey);
+			incommingCipher.initialize(incommingKey);
+			ivCipher.initialize(ivKey);
 		}
-		outgoingCipher.initialize(outgoingKey);
-		incommingCipher.initialize(incommingKey);
-		ivCipher.initialize(ivKey);
-
 		// Promote if necessary
 		boolean dontWant = false;
 		if(oldOpennetPeer) {
@@ -1620,17 +1630,28 @@ public class FNPPacketMangler implements OutgoingPacketMangler {
 		BlockCipher ivCipher = null;
 		BlockCipher outgoingCipher = null;
 		BlockCipher incommingCipher = null;
-		try {
-			ivCipher = new Rijndael(256, 256);
-			outgoingCipher = new Rijndael(256, 256);
-			incommingCipher = new Rijndael(256, 256);
-		} catch (UnsupportedCipherException e) {
-			throw new RuntimeException(e);
+		if(negType != 8){
+			try {
+				outgoingCipher = new Rijndael(256, 256);
+				incommingCipher = new Rijndael(256, 256);
+				ivCipher = new Rijndael(256, 256);
+			} catch (UnsupportedCipherException e) {
+				throw new RuntimeException(e);
+			}
+			outgoingCipher.initialize(pn.outgoingKey);
+			incommingCipher.initialize(pn.incommingKey);
+			ivCipher.initialize(pn.ivKey);
 		}
+		else{
+			outgoingCipher = new JCACipher(256, 256);
+			incommingCipher = new JCACipher(256, 256);
+			ivCipher = new JCACipher(256, 256);
+			outgoingCipher.initialize(pn.outgoingKey);
+			incommingCipher.initialize(pn.incommingKey);
+			ivCipher.initialize(pn.ivKey);
+		}
+
 
-		outgoingCipher.initialize(pn.outgoingKey);
-		incommingCipher.initialize(pn.incommingKey);
-		ivCipher.initialize(pn.ivKey);
 
 		long newTrackerID = pn.completedHandshake(
 				bootID, hisRef, 0, hisRef.length, outgoingCipher, pn.outgoingKey, incommingCipher,
@@ -3214,9 +3235,9 @@ public class FNPPacketMangler implements OutgoingPacketMangler {
 	@Override
 	public int[] supportedNegTypes(boolean forPublic) {
 		if(forPublic)
-			return new int[] { 2, 4, 6, 7 };
+			return new int[] { 2, 4, 6, 7, 8 };
 		else
-			return new int[] { 2, 4, 6, 7 };
+			return new int[] { 2, 4, 6, 7, 8 };
 	}
 
 	@Override
-- 
1.7.5.4

