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;
+       }
 }


Reply via email to