[freenet-cvs] r15132 - in branches/freenet-jfk/src/freenet: crypt node

kryptos at freenetproject.org kryptos at freenetproject.org
Thu Sep 13 06:19:00 UTC 2007


Author: kryptos
Date: 2007-09-13 06:19:00 +0000 (Thu, 13 Sep 2007)
New Revision: 15132

Modified:
   branches/freenet-jfk/src/freenet/crypt/DiffieHellmanContext.java
   branches/freenet-jfk/src/freenet/node/FNPPacketMangler.java
Log:
Sign the params for message3

Modified: branches/freenet-jfk/src/freenet/crypt/DiffieHellmanContext.java
===================================================================
--- branches/freenet-jfk/src/freenet/crypt/DiffieHellmanContext.java	2007-09-12 19:35:02 UTC (rev 15131)
+++ branches/freenet-jfk/src/freenet/crypt/DiffieHellmanContext.java	2007-09-13 06:19:00 UTC (rev 15132)
@@ -63,7 +63,7 @@
             Logger.minor(this, "Key="+HexUtil.bytesToHex(key));
         return key;
     }
-    
+        
     public synchronized void setOtherSideExponential(NativeBigInteger a) {
         lastUsedTime = System.currentTimeMillis();
         if(peerExponential != null) {

Modified: branches/freenet-jfk/src/freenet/node/FNPPacketMangler.java
===================================================================
--- branches/freenet-jfk/src/freenet/node/FNPPacketMangler.java	2007-09-12 19:35:02 UTC (rev 15131)
+++ branches/freenet-jfk/src/freenet/node/FNPPacketMangler.java	2007-09-13 06:19:00 UTC (rev 15132)
@@ -420,7 +420,7 @@
 				 * cached by the Responder.Receiving a duplicate message simply causes
 				 * the responder to Re-transmit the corresponding message4
 				 */
-				ProcessMessage3(payload, pn, replyTo);
+				//ProcessMessage3(payload, pn, replyTo);
 			}
 			else if(packetType==3){
 				/*
@@ -428,7 +428,7 @@
 				 * using the same keys as in the previous message.
 				 * The signature is non-message recovering
 				 */
-				ProcessMessage4(payload,pn,replyTo);
+				//ProcessMessage4(payload,pn,replyTo);
 			}
 		}
 		else {
@@ -536,8 +536,10 @@
 		DiffieHellmanLightContext dhContext = getLightDiffieHellmanContext();
 		byte[] idR = new byte[0];
 		byte[] myDHGroup = stripBigIntegerToNetworkFormat(dhContext.group.p);
-		byte[] myNonce = new byte[NONCE_SIZE];
-		byte[] myExponential = stripBigIntegerToNetworkFormat(dhContext.myExponential);
+		// g^r
+                byte[] myExponential = stripBigIntegerToNetworkFormat(dhContext.myExponential);
+                // Nr
+                byte[] myNonce = new byte[NONCE_SIZE];
 		node.random.nextBytes(myNonce);
 		// FIXME: can we do that ? is it (mod p) as well ?
 		byte[] r = dhContext.signature.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH);
@@ -604,7 +606,6 @@
 	 * Send an authenticator which is a hash of Ni,Nr,g^r calculated over the transient key HKr
          * Format of JFK(2) as specified above
          * @param Payload
-	 * @param The packet phase number
 	 * @param The peer to which we need to send the packet
 	 * @param The peerNode we are talking to
 	 */
@@ -675,8 +676,8 @@
 		long t2=System.currentTimeMillis();
 		if((t2-t1)>500)
 			Logger.error(this,"Message1 timeout error:Sending packet for"+pn.getPeer());
+        }        
 
-	}
 	/*
 	 * Initiator Method:Message3
 	 * Process Message3
@@ -685,7 +686,7 @@
 	 * Send the authenticator which allows the responder to verify the legality of the message
 	 * Compute the signature of the unVerifiedData and encrypt it using a shared key
 	 * which is derived from DHExponentials and the nonces
-	 * @param The packet phase number
+	 * @param Payload
 	 * @param The peer to which we need to send the packet
 	 * @param The peerNode we are talking to
 	 * @return byte Message3
@@ -695,17 +696,20 @@
 		long t1 = System.currentTimeMillis();
 		if(logMINOR) Logger.minor(this, "Got a JFK(3) message, processing it");
 		int inputOffset=3;
-		
+		// Ni
 		byte[] nonceInitiator = new byte[NONCE_SIZE];
 		System.arraycopy(payload, inputOffset, nonceInitiator, 0, NONCE_SIZE);
 		inputOffset += NONCE_SIZE;
-		byte[] nonceResponder = new byte[NONCE_SIZE];
+		// Nr
+                byte[] nonceResponder = new byte[NONCE_SIZE];
 		System.arraycopy(payload, inputOffset, nonceResponder, 0, NONCE_SIZE);
 		inputOffset += NONCE_SIZE;
-		byte[] initiatorExponential = new byte[DiffieHellman.modulusLengthInBytes()];
+		// g^i
+                byte[] initiatorExponential = new byte[DiffieHellman.modulusLengthInBytes()];
 		System.arraycopy(payload, inputOffset, initiatorExponential, 0, DiffieHellman.modulusLengthInBytes());
 		inputOffset += DiffieHellman.modulusLengthInBytes();
-		byte[] responderExponential = new byte[DiffieHellman.modulusLengthInBytes()];
+		// g^r
+                byte[] responderExponential = new byte[DiffieHellman.modulusLengthInBytes()];
 		System.arraycopy(payload, inputOffset, responderExponential, 0, DiffieHellman.modulusLengthInBytes());
 		inputOffset += DiffieHellman.modulusLengthInBytes();
 		byte[] authenticator = new byte[HASH_LENGTH];
@@ -718,7 +722,9 @@
 			Logger.error(this, "The HMAC doesn't match; let's discard the packet (either we rekeyed or we are victim of forgery)");
 			return;
 		}
-		// Check try to find the authenticator in the cache.
+                // Check try to find the authenticator in the cache.
+                // If authenticator is already present, indicates duplicate/replayed message3
+                // Now simply transmit the corresponding message4
 		Object message4 = null;
 		synchronized (authenticatorCache) {
 			message4 = authenticatorCache.get(authenticator);
@@ -740,74 +746,29 @@
 			Logger.error(this, "We can't accept the exponential "+pn+" sent us; it's smaller than 1!! (our exponential?!?)");
 			return;
 		}
+		// Now verify signature
+                byte[] r = new byte[Node.SIGNATURE_PARAMETER_LENGTH];
+		System.arraycopy(payload, inputOffset, r, 0, Node.SIGNATURE_PARAMETER_LENGTH);
+		inputOffset += Node.SIGNATURE_PARAMETER_LENGTH;
+		byte[] s = new byte[Node.SIGNATURE_PARAMETER_LENGTH];
+		System.arraycopy(payload, inputOffset, s, 0, Node.SIGNATURE_PARAMETER_LENGTH);
+		inputOffset += Node.SIGNATURE_PARAMETER_LENGTH;
+		DSASignature remoteSignature = new DSASignature(new NativeBigInteger(1,r), new NativeBigInteger(1,s));
+		if(logMINOR)
+                    Logger.minor(this, "Remote sent us the following sig :"+remoteSignature.toLongString());
+		byte[] locallyExpectedExponentials = assembleDHParams(nonceInitiator,nonceResponder,_ourExponential,_hisExponential);
 		
-		sendMessage4Packet(1, 2, 3, nonceInitiator, nonceResponder,initiatorExponential, initiatorIdentity, authenticator, pn, replyTo);
+		if(!DSA.verify(pn.peerPubKey, remoteSignature, new NativeBigInteger(1, locallyExpectedExponentials), false)) {
+			Logger.error(this, "The signature verification has failed!!");
+			return;
+		}
+		sendMessage4Packet(1, 2, 3, nonceInitiator, nonceResponder,initiatorExponential, responderExponential,initiatorIdentity, pn, replyTo);
 		long t2=System.currentTimeMillis();
 		if((t2-t1)>500)
 			Logger.error(this,"Message1 timeout error:Sending packet for"+pn.getPeer());
 	}
 
 	/*
-	 * Responder Method:Message4
-	 * Process Message4
-	 * Encrypted message of the signature on both nonces, both exponentials using the same
-	 * keys as in the previous message.The Initiator can verify that the Responder is present
-	 * and participating in the session, by decrypting the message and verifying the enclosed
-	 * signature.
-	 * @param The packet phase number
-	 * @param The peer to which we need to send the packet
-	 * @param The peerNode we are talking to
-	 */
-
-	private void ProcessMessage4(byte[] payload,PeerNode pn,Peer replyTo)
-	{
-		if(logMINOR) Logger.minor(this, "Got a JFK(4) message, processing it");
-		long t1=System.currentTimeMillis();
-//		byte[] Ni = iNonce();
-//		byte[] Nr = rNonce();
-//		byte[] DHExpi = Gi(pn);
-//		byte[] DHExpr = Gr(pn);
-//		byte[] Data=new byte[Ni.length+Nr.length+DHExpr.length+DHExpi.length+1];
-//		System.arraycopy(Ni,0,Data,0,Ni.length);
-//		System.arraycopy(Nr,0,Data,Ni.length+1,Nr.length);
-//		System.arraycopy(DHExpi,0,Data,Ni.length+Nr.length+1,DHExpi.length);
-//		System.arraycopy(DHExpr,0,Data,Ni.length+Nr.length+DHExpi.length+1,DHExpr.length);
-//		DSASignature sig = crypto.sign(Data,g,PKR,r);
-//		byte[] r = sig.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH);
-//		byte[] s = sig.getSBytes(Node.SIGNATURE_PARAMETER_LENGTH);
-//		Logger.minor(this, " r="+HexUtil.bytesToHex(sig.getR().toByteArray())+" s="+HexUtil.bytesToHex(sig.getS().toByteArray()));
-//		BlockCipher c=pn.outgoingSetupCipher;
-//		if(logMINOR)
-//			Logger.minor(this,"Cipher"+HexUtil.bytesToHex(pn.outgoingSetupKey));
-//		/*
-//		 * Initializes the cipher context with the given key
-//		 * This would avoid the computation of key using the Rijndael key schedule(S boxes,Rcon etc)
-//		 * The key used is generated from Hash of Message:(Ni, Nr, 1) over the shared key of DH
-//		 */
-//		c.initialize(encryptionKey.getEncKey(sharedSecretKey(pn),iNonce(),rNonce()));
-//		PCFBMode pk=PCFBMode.create(c);
-//		byte[] iv=new byte[pk.lengthIV()];
-//		int message4Length = r.length + s.length + 2;
-//		byte[] message4 = new byte[message4Length];
-//		System.arraycopy(iv, 0, message4, 0, iv.length);
-//		int count = iv.length;
-//		if(r.length > 255 || s.length > 255)
-//			throw new IllegalStateException("R or S is too long: r.length="+r.length+" s.length="+s.length);
-//		message4[count++] = (byte) r.length;
-//		System.arraycopy(r, 0, message4, count, r.length);
-//		count += r.length;
-//		message4[count++] = (byte) s.length;
-//		System.arraycopy(s, 0, message4, count, s.length);
-//		count += s.length;
-//		pk.blockEncipher(message4, 0, message4.length);
-//		//Send params:Version,negType,phase,data,peernode,peer 
-		
-		long t2=System.currentTimeMillis();
-		if((t2-t1)>500)
-			Logger.error(this,"Message4 timeout error:Sending packet for"+pn.getPeer());
-	}	
-
-	/*
 	 * Convert Object to byteArray
 	 */
 	private byte[] getBytes(Object o) throws IOException
@@ -843,12 +804,16 @@
 		byte[] ourExponential = dhContext.myExponential.toByteArray();
 		byte[] unVerifiedData=new byte[NONCE_SIZE*2+DiffieHellman.modulusLengthInBytes()*2];
 		int offset = 0;
-		System.arraycopy(nonceInitiator, 0, unVerifiedData, offset, NONCE_SIZE);
+		// Ni
+                System.arraycopy(nonceInitiator, 0, unVerifiedData, offset, NONCE_SIZE);
 		offset += NONCE_SIZE;
-		System.arraycopy(nonceResponder, 0, unVerifiedData, offset, NONCE_SIZE);
+		// Nr
+                System.arraycopy(nonceResponder, 0, unVerifiedData, offset, NONCE_SIZE);
 		offset += NONCE_SIZE;
-		System.arraycopy(ourExponential, 0,unVerifiedData, offset, ourExponential.length);
+		// g^i
+                System.arraycopy(ourExponential, 0,unVerifiedData, offset, ourExponential.length);
 		offset += ourExponential.length;
+                // g^r
                 System.arraycopy(hisExponential, 0,unVerifiedData, offset, hisExponential.length);
 		offset += hisExponential.length;
 		/*
@@ -857,13 +822,10 @@
 		 */
 		//FIXME: is this the correct way of generating Signatures?
                 //FIXME: IDr not signed?
-                byte[] signature;
-		try {
-			signature = dhContext.signature.toString().getBytes("UTF-8");
-		} catch (UnsupportedEncodingException e) {
-			Logger.error(this, "HUH ??, please report it :"+ e.getMessage(),e);
-			return;
-		}
+                byte[] r = dhContext.signature.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH);
+		byte[] s = dhContext.signature.getSBytes(Node.SIGNATURE_PARAMETER_LENGTH);
+                if(r.length > 255 || s.length > 255)
+			throw new IllegalStateException("R or S is too long: r.length="+r.length+" s.length="+s.length);
 		BlockCipher c=pn.outgoingSetupCipher;
 		if(logMINOR)
 			Logger.minor(this,"Cipher"+HexUtil.bytesToHex(pn.outgoingSetupKey));
@@ -875,72 +837,29 @@
 		c.initialize(encryptionKey.getEncKey(sharedSecretKey(pn),nonceInitiator,nonceResponder));
 		PCFBMode pk=PCFBMode.create(c);
 		byte[] iv=new byte[pk.lengthIV()];
-		int encryptedDataLength = iv.length + signature.length + 2;
+		int encryptedDataLength = iv.length + r.length + s.length + 2;
 		/*
 		 * Data sent in the clear is signed and encrypted using PCFB and rijndael
 		 */
 		byte[] encryptedData = new byte[encryptedDataLength];
 		System.arraycopy(iv, 0, encryptedData, 0, iv.length);
 		int count = iv.length;
-		encryptedData[count++] = (byte) signature.length;
-		System.arraycopy(signature, 0, encryptedData, count, signature.length);
-		count += signature.length;
+                encryptedData[count++] = (byte) r.length;
+		System.arraycopy(r, 0, encryptedData, count, r.length);
+		count += r.length;
+		encryptedData[count++] = (byte) s.length;
+		System.arraycopy(s, 0, encryptedData, count, s.length);
+		count += s.length;
 		pk.blockEncipher(encryptedData, 0, encryptedData.length);
 		byte[] message3=new byte[unVerifiedData.length+hashedAuthenticator.length+encryptedData.length];
 		System.arraycopy(unVerifiedData,0,message3,0,unVerifiedData.length);
 		System.arraycopy(hashedAuthenticator,0,message3,encryptedData.length,hashedAuthenticator.length);
 		System.arraycopy(encryptedData,0,message3,unVerifiedData.length+hashedAuthenticator.length,encryptedData.length);
-		byte[] output = new byte[message3.length+3];
-		if((message3.length+3) > sock.getMaxPacketSize())
-			throw new IllegalStateException("Packet length too long");
-		/*
-		 * The key for looking up messages in the cache is the authenticator
-		 * This prevents DOS attacks where the attacker randomly tries to replace encrypted blocks 
-		 * of a valid message causing a cache miss
-		 * This would result in increased processing on the Responder side->CPU exhaustion attacks
-		 */
-		Object result;
-		//All recent messages 3 and 4 are cached
-		if(phase==2){
-			// Intrinsic lock provided by the object message3Cache
-			synchronized(message3Cache) {
-				result = message3Cache.get(hashedAuthenticator);
-			}
-			if(result != null) {
-				synchronized(message3Cache) {
-					message3Cache.put(message3,hashedAuthenticator);
-				}
-				// We don't want to keep the lock while sending
-				try
-				{
-					sendAuthPacket(1,2,2,getBytes(message4Cache.get(hashedAuthenticator)),pn,replyTo);
-				}
-				catch(IOException e){
-					Logger.error(this,"Error getting bytes");
-				}
-			}
-			sendAuthPacket(version, negType, 4, null, pn, replyTo);
-		}
 		
-		else{ 
-			Logger.error(this,"Wrong message");
-
-		}   
-		output[0] = (byte) version;
-		output[1] = (byte) negType;
-		output[2] = (byte) phase;
-		System.arraycopy(message3, 0, output, 3, message3.length);
-		if(logMINOR) Logger.minor(this, "Sending auth packet for "+pn.getPeer()+" (phase="+phase+", ver="+version+", nt="+negType+") (last packet sent "+TimeUtil.formatTime(delta, 2, true)+" ago) to "+replyTo+" data.length="+nonceInitiator.length);
-		try
-		{
-			sendPacket(output,replyTo,pn,0);
-		}catch(LocalAddressException e) {
-			Logger.error(this, "Tried to send auth packet to local address: "+replyTo+" for "+pn.getPeer());
-		}
-
+		sendAuthPacket(1,2,1,message3,pn,replyTo);
 	}
-
-	/*
+       
+        /*
 	 * Send Message4 packet
 	 * @param version
 	 * @param negType
@@ -2235,12 +2154,32 @@
 		
 		return SHA256.digest(toSign);
 	}
+        /*
+         * Prepare params for signing in Message3
+         */
+        private byte[] assembleDHParams(byte[] nonceInitiator,byte[] nonceResponder,BigInteger myExponential, BigInteger hisExponential) {
+		byte[] _myExponential = stripBigIntegerToNetworkFormat(myExponential);
+		byte[] _hisExponential = stripBigIntegerToNetworkFormat(hisExponential);
+		byte[] toSign = new byte[nonceInitiator.length + nonceResponder.length + _myExponential.length + _hisExponential.length];
+		System.arraycopy(nonceInitiator, 0,toSign,0,nonceInitiator.length);
+                System.arraycopy(nonceResponder,0 ,toSign,nonceInitiator.length,nonceResponder.length);
+		System.arraycopy(_myExponential, 0, toSign,nonceInitiator.length+nonceResponder.length, _myExponential.length);
+		System.arraycopy(_hisExponential, 0, toSign, nonceInitiator.length+nonceResponder.length+_myExponential.length, _hisExponential.length);
+		// Why is the hash returned?
+		return SHA256.digest(toSign);
+	}
 	/*
 	 * Actually sign the DH parameters for message2
 	 */
 	private DSASignature signDHParams(BigInteger exponential, BigInteger group) {
 		return crypto.sign(assembleDHParams(exponential, group));
 	}
+        /*
+         * Sign the params for message3
+         */
+        private DSASignature signDHParams(byte[] nonceInitiator,byte[] nonceResponder,BigInteger myExponential, BigInteger hisExponential) {
+		return crypto.sign(assembleDHParams(nonceInitiator,nonceResponder,myExponential,hisExponential));
+	}
 	
 	private byte[] getTransientKey() {
 		synchronized (authenticatorCache) {




More information about the cvs mailing list