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) {