Author: toad
Date: 2007-12-04 23:46:56 +0000 (Tue, 04 Dec 2007)
New Revision: 16291
Modified:
trunk/freenet/src/freenet/node/FNPPacketMangler.java
trunk/freenet/src/freenet/node/NodeCrypto.java
Log:
beginnings of unknown-initiator link crypto
Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-12-04
23:44:49 UTC (rev 16290)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-12-04
23:46:56 UTC (rev 16291)
@@ -269,6 +269,7 @@
}
}
}
+ if(tryProcessAuthAnon(buf, offset, length, peer, now)) return;
Logger.normal(this,"Unmatchable packet from "+peer);
}
@@ -336,6 +337,111 @@
}
/**
+ * Might be an anonymous-initiator negotiation packet.
+ * Anonymous initiator is used for seednode connections,
+ * and will in future be used for other things for example
+ * one-side-only invites, password based invites etc.
+ * @param buf The buffer to read bytes from
+ * @param offset The offset at which to start reading
+ * @param length The number of bytes to read
+ * @param pn The PeerNode we think is responsible
+ * @param peer The Peer to send a reply to
+ * @param now The time at which the packet was received
+ * @return True if we handled a negotiation packet, false otherwise.
+ */
+ private boolean tryProcessAuthAnon(byte[] buf, int offset, int length,
Peer peer, long now) {
+ BlockCipher authKey = crypto.getAnonSetupCipher();
+ // Does the packet match IV E( H(data) data ) ?
+ PCFBMode pcfb = PCFBMode.create(authKey);
+ int ivLength = pcfb.lengthIV();
+ MessageDigest md = SHA256.getMessageDigest();
+ int digestLength = HASH_LENGTH;
+ if(length < digestLength + ivLength + 4) {
+ if(logMINOR) Logger.minor(this, "Too short: "+length+"
should be at least "+(digestLength + ivLength + 4));
+ SHA256.returnMessageDigest(md);
+ return false;
+ }
+ // IV at the beginning
+ pcfb.reset(buf, offset);
+ // Then the hash, then the data
+ // => Data starts at ivLength + digestLength
+ // Decrypt the hash
+ byte[] hash = new byte[digestLength];
+ System.arraycopy(buf, offset+ivLength, hash, 0, digestLength);
+ pcfb.blockDecipher(hash, 0, hash.length);
+
+ int dataStart = ivLength + digestLength + offset+2;
+
+ int byte1 = ((pcfb.decipher(buf[dataStart-2])) & 0xff);
+ int byte2 = ((pcfb.decipher(buf[dataStart-1])) & 0xff);
+ int dataLength = (byte1 << 8) + byte2;
+ if(logMINOR) Logger.minor(this, "Data length: "+dataLength+" (1
= "+byte1+" 2 = "+byte2+ ')');
+ if(dataLength > length - (ivLength+hash.length+2)) {
+ if(logMINOR) Logger.minor(this, "Invalid data length
"+dataLength+" ("+(length - (ivLength+hash.length+2))+") in tryProcessAuth");
+ SHA256.returnMessageDigest(md);
+ return false;
+ }
+ // Decrypt the data
+ byte[] payload = new byte[dataLength];
+ System.arraycopy(buf, dataStart, payload, 0, dataLength);
+ pcfb.blockDecipher(payload, 0, payload.length);
+
+ md.update(payload);
+ byte[] realHash = md.digest();
+ SHA256.returnMessageDigest(md); md = null;
+
+ if(Arrays.equals(realHash, hash)) {
+ // Got one
+ processDecryptedAuthAnon(payload, peer);
+ return true;
+ } else {
+ if(logMINOR) Logger.minor(this, "Incorrect hash in
tryProcessAuth for "+peer+" (length="+dataLength+"): \nreal
hash="+HexUtil.bytesToHex(realHash)+"\n bad hash="+HexUtil.bytesToHex(hash));
+ return false;
+ }
+ }
+
+ // Anonymous-initiator setup types
+ /** Connect to a node hoping it will act as a seednode for us */
+ static final byte SETUP_OPENNET_SEEDNODE = 1;
+
+ private void processDecryptedAuthAnon(byte[] payload, Peer replyTo) {
+ if(logMINOR) Logger.minor(this, "Processing decrypted auth
packet from "+replyTo);
+
+ long now = System.currentTimeMillis();
+
+ /** Protocol version. Should be 1. */
+ int version = payload[0];
+ /** Negotiation type. 2 = JFK. Other types might indicate other
DH variants,
+ * or even non-DH-based algorithms such as password based key
setup. */
+ int negType = payload[1];
+ /** Packet phase. */
+ int packetType = payload[2];
+ /** Setup type. See above. */
+ int setupType = payload[3];
+
+ if(logMINOR) Logger.minor(this, "Received anonymous auth packet
(phase="+packetType+", v="+version+", nt="+negType+", setup type="+setupType+")
from "+replyTo+"");
+
+ if(version != 1) {
+ Logger.error(this, "Decrypted auth packet but invalid
version: "+version);
+ return;
+ }
+ if(negType != 2) {
+ Logger.error(this, "Unknown neg type: "+negType);
+ return;
+ }
+
+ // Known setup types
+ if(setupType != SETUP_OPENNET_SEEDNODE) {
+ Logger.error(this, "Unknown setup type "+negType);
+ return;
+ }
+
+
+ // TODO Auto-generated method stub
+
+ }
+
+ /**
* Process a decrypted, authenticated auth packet.
* @param payload The packet payload, after it has been decrypted.
*/
Modified: trunk/freenet/src/freenet/node/NodeCrypto.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeCrypto.java 2007-12-04 23:44:49 UTC
(rev 16290)
+++ trunk/freenet/src/freenet/node/NodeCrypto.java 2007-12-04 23:46:56 UTC
(rev 16291)
@@ -12,6 +12,7 @@
import java.util.zip.DeflaterOutputStream;
import net.i2p.util.NativeBigInteger;
+import freenet.crypt.BlockCipher;
import freenet.crypt.DSA;
import freenet.crypt.DSAGroup;
import freenet.crypt.DSAPrivateKey;
@@ -20,6 +21,8 @@
import freenet.crypt.Global;
import freenet.crypt.RandomSource;
import freenet.crypt.SHA256;
+import freenet.crypt.UnsupportedCipherException;
+import freenet.crypt.ciphers.Rijndael;
import freenet.io.PortForwardBrokenDetector;
import freenet.io.comm.FreenetInetAddress;
import freenet.io.comm.Peer;
@@ -66,6 +69,7 @@
static boolean logMINOR;
final NodeCryptoConfig config;
final NodeIPPortDetector detector;
+ final BlockCipher anonSetupCipher;
// Noderef related
/** An ordered version of the noderef FieldSet, without the signature */
@@ -152,6 +156,11 @@
detector = new NodeIPPortDetector(node, node.ipDetector, this);
+ anonSetupCipher = new Rijndael(256,256);
+ anonSetupCipher.initialize(identityHash);
+
+ } catch (UnsupportedCipherException e) {
+ throw new Error(e);
} catch (NodeInitException e) {
config.stopping(this);
throw e;
@@ -438,4 +447,11 @@
DSAGroup getCryptoGroup() {
return cryptoGroup;
}
+
+ /**
+ * Get the cipher for connection attempts for e.g. seednode connections
from nodes we don't know.
+ */
+ public BlockCipher getAnonSetupCipher() {
+ return anonSetupCipher;
+ }
}