Author: nextgens Date: 2009-01-30 18:35:33 +0000 (Fri, 30 Jan 2009) New Revision: 25406
Modified: trunk/freenet/src/freenet/crypt/HMAC.java trunk/freenet/src/freenet/node/FNPPacketMangler.java trunk/freenet/src/freenet/node/FailureTable.java trunk/freenet/src/freenet/node/NodeDispatcher.java trunk/freenet/src/freenet/node/PeerNode.java Log: Get rid of some of our home-grown crypto (HMAC)... more refactoring to come. It may be slower than the current implementation. Modified: trunk/freenet/src/freenet/crypt/HMAC.java =================================================================== --- trunk/freenet/src/freenet/crypt/HMAC.java 2009-01-30 18:13:09 UTC (rev 25405) +++ trunk/freenet/src/freenet/crypt/HMAC.java 2009-01-30 18:35:33 UTC (rev 25406) @@ -3,150 +3,42 @@ * http://www.gnu.org/ for further details of the GPL. */ package freenet.crypt; -import java.io.UnsupportedEncodingException; +import freenet.support.Logger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import javax.crypto.Mac; +import javax.crypto.SecretKey; -import freenet.support.HexUtil; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - /** * Implements the HMAC Keyed Message Authentication function, as described * in the draft FIPS standard. + * + * Use a KeyGenerator to generate a key! */ public class HMAC { - protected static final int B = 64; - protected static byte[] ipad = new byte[B]; - protected static byte[] opad = new byte[B]; + public enum ALGORITHM { - static { - for(int i = 0; i < B; i++) { - ipad[i] = (byte) 0x36; - opad[i] = (byte) 0x5c; - } - } - protected MessageDigest d; + HmacSHA256, Hmac1, HmacMD5; + } - public HMAC(MessageDigest md) { - this.d = md; - } + public static byte[] mac(ALGORITHM algo, SecretKey key, byte[] input) throws InvalidKeyException { + try { + Mac mac = Mac.getInstance(algo.name()); + mac.init(key); - public boolean verify(byte[] K, byte[] text, byte[] mac) { - byte[] mac2 = mac(K, text, mac.length); - return Arrays.equals(mac, mac2); - } + return mac.doFinal(); + } catch (NoSuchAlgorithmException ex) { + Logger.error(HMAC.class, "Check your JVM settings especially the JCE!" + ex.getMessage(), ex); + System.err.println("Check your JVM settings especially the JCE!" + ex); + ex.printStackTrace(); + throw new Error("Check your JVM settings especially the JCE!", ex); + } + } - public byte[] mac(byte[] K, byte[] text, int macbytes) { - byte[] K0 = null; - - if(K.length == B) // Step 1 - K0 = K; - else { - // Step 2 - if(K.length > B) - K0 = K = Util.hashBytes(d, K); - - if(K.length < B) { // Step 3 - K0 = new byte[B]; - System.arraycopy(K, 0, K0, 0, K.length); - } - } - - // Step 4 - byte[] IS1 = Util.xor(K0, ipad); - - // Step 5/6 - d.update(IS1); - d.update(text); - IS1 = d.digest(); - - // Step 7 - byte[] IS2 = Util.xor(K0, opad); - - // Step 8/9 - d.update(IS2); - d.update(IS1); - IS1 = d.digest(); - - // Step 10 - if(macbytes == IS1.length) - return IS1; - else { - byte[] rv = new byte[macbytes]; - System.arraycopy(IS1, 0, rv, 0, Math.min(rv.length, IS1.length)); - return rv; - } - } - - public static void main(String[] args) throws UnsupportedEncodingException { - HMAC s = null; - try { - s = new HMAC(MessageDigest.getInstance("SHA1")); - } catch(NoSuchAlgorithmException e) { - } - byte[] key = new byte[20]; - System.err.println("20x0b, 'Hi There':"); - byte[] text; - text = "Hi There".getBytes("UTF-8"); - - for(int i = 0; i < key.length; i++) - key[i] = (byte) 0x0b; - - byte[] mv = s.mac(key, text, 20); - System.out.println(HexUtil.bytesToHex(mv, 0, mv.length)); - - System.err.println("20xaa, 50xdd:"); - for(int i = 0; i < key.length; i++) - key[i] = (byte) 0xaa; - text = new byte[50]; - for(int i = 0; i < text.length; i++) - text[i] = (byte) 0xdd; - mv = s.mac(key, text, 20); - System.out.println(HexUtil.bytesToHex(mv, 0, mv.length)); - - key = new byte[25]; - System.err.println("25x[i+1], 50xcd:"); - for(int i = 0; i < key.length; i++) - key[i] = (byte) (i + 1); - for(int i = 0; i < text.length; i++) - text[i] = (byte) 0xcd; - mv = s.mac(key, text, 20); - System.out.println(HexUtil.bytesToHex(mv, 0, mv.length)); - - key = new byte[20]; - System.err.println("20x0c, 'Test With Truncation':"); - for(int i = 0; i < key.length; i++) - key[i] = (byte) 0x0c; - text = "Test With Truncation".getBytes("UTF-8"); - mv = s.mac(key, text, 20); - System.out.println(HexUtil.bytesToHex(mv, 0, mv.length)); - mv = s.mac(key, text, 12); - System.out.println(HexUtil.bytesToHex(mv, 0, mv.length)); - - } - - public static byte[] macWithSHA256(byte[] K, byte[] text, int macbytes) { - MessageDigest sha256 = null; - try { - sha256 = SHA256.getMessageDigest(); - HMAC hash = new HMAC(sha256); - return hash.mac(K, text, macbytes); - } finally { - if(sha256 != null) - SHA256.returnMessageDigest(sha256); - } - } - - public static boolean verifyWithSHA256(byte[] K, byte[] text, byte[] mac) { - MessageDigest sha256 = null; - try { - sha256 = SHA256.getMessageDigest(); - HMAC hash = new HMAC(sha256); - return hash.verify(K, text, mac); - } finally { - if(sha256 != null) - SHA256.returnMessageDigest(sha256); - } - } -} + public static boolean verify(ALGORITHM algo, SecretKey key, byte[] input, byte[] mac) throws InvalidKeyException { + return Arrays.equals(mac, mac(algo, key, input)); + } +} \ No newline at end of file Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java =================================================================== --- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2009-01-30 18:13:09 UTC (rev 25405) +++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2009-01-30 18:35:33 UTC (rev 25406) @@ -52,6 +52,9 @@ import freenet.support.TimeUtil; import freenet.support.WouldBlockException; import freenet.support.io.NativeThread; +import java.security.InvalidKeyException; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; /** * @author amphibian @@ -129,7 +132,7 @@ /** The size of the key used to authenticate the hmac */ private static final int TRANSIENT_KEY_SIZE = HASH_LENGTH; /** The key used to authenticate the hmac */ - private final byte[] transientKey = new byte[TRANSIENT_KEY_SIZE]; + private SecretKey transientKey; public static final int TRANSIENT_KEY_REKEYING_MIN_INTERVAL = 30*60*1000; /** The rekeying interval for the session key (keytrackers) */ public static final int SESSION_KEY_REKEYING_INTERVAL = 60*60*1000; @@ -231,7 +234,7 @@ opn = null; } PeerNode pn; - + try { if(opn != null) { if(logMINOR) Logger.minor(this, "Trying exact match"); if(length > HEADERS_LENGTH_MINIMUM) { @@ -249,7 +252,7 @@ if(tryProcessAuth(buf, offset, length, opn, peer, false, now)) return; // Might be a reply to an anon auth packet if(tryProcessAuthAnonReply(buf, offset, length, opn, peer, now)) return; - } + } } PeerNode[] peers = crypto.getPeerNodes(); // Existing connection, changed IP address? @@ -306,7 +309,6 @@ } } } - OpennetManager opennet = node.getOpennet(); if(opennet != null) { // Try old opennet connections. @@ -322,6 +324,10 @@ if(node.wantAnonAuth()) { if(tryProcessAuthAnon(buf, offset, length, peer)) return; } + } catch (InvalidKeyException e) { + Logger.error(this, "Huh! " + e.getMessage(), e); + return; + } if(LOG_UNMATCHABLE_ERROR) System.err.println("Unmatchable packet from "+peer+" on "+node.getDarknetPortNumber()); Logger.normal(this,"Unmatchable packet from "+peer); @@ -337,7 +343,7 @@ * @param now The time at which the packet was received * @return True if we handled a negotiation packet, false otherwise. */ - private boolean tryProcessAuth(byte[] buf, int offset, int length, PeerNode pn, Peer peer, boolean oldOpennetPeer, long now) { + private boolean tryProcessAuth(byte[] buf, int offset, int length, PeerNode pn, Peer peer, boolean oldOpennetPeer, long now) throws InvalidKeyException { BlockCipher authKey = pn.incomingSetupCipher; if(logMINOR) Logger.minor(this, "Decrypt key: "+HexUtil.bytesToHex(pn.incomingSetupKey)+" for "+peer+" : "+pn+" in tryProcessAuth"); // Does the packet match IV E( H(data) data ) ? @@ -406,7 +412,7 @@ * @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) { + private boolean tryProcessAuthAnon(byte[] buf, int offset, int length, Peer peer) throws InvalidKeyException { BlockCipher authKey = crypto.getAnonSetupCipher(); // Does the packet match IV E( H(data) data ) ? PCFBMode pcfb = PCFBMode.create(authKey); @@ -471,7 +477,7 @@ * @param now The time at which the packet was received * @return True if we handled a negotiation packet, false otherwise. */ - private boolean tryProcessAuthAnonReply(byte[] buf, int offset, int length, PeerNode pn, Peer peer, long now) { + private boolean tryProcessAuthAnonReply(byte[] buf, int offset, int length, PeerNode pn, Peer peer, long now) throws InvalidKeyException { BlockCipher authKey = pn.anonymousInitiatorSetupCipher; // Does the packet match IV E( H(data) data ) ? PCFBMode pcfb = PCFBMode.create(authKey); @@ -533,7 +539,7 @@ * @param payload The decrypted payload of the packet. * @param replyTo The address the packet came in from. */ - private void processDecryptedAuthAnon(byte[] payload, Peer replyTo) { + private void processDecryptedAuthAnon(byte[] payload, Peer replyTo) throws InvalidKeyException { if(logMINOR) Logger.minor(this, "Processing decrypted auth packet from "+replyTo+" length "+payload.length); /** Protocol version. Should be 1. */ @@ -583,7 +589,7 @@ } } - private void processDecryptedAuthAnonReply(byte[] payload, Peer replyTo, PeerNode pn) { + private void processDecryptedAuthAnonReply(byte[] payload, Peer replyTo, PeerNode pn) throws InvalidKeyException { if(logMINOR) Logger.minor(this, "Processing decrypted auth packet from "+replyTo+" for "+pn+" length "+payload.length); /** Protocol version. Should be 1. */ @@ -634,7 +640,7 @@ * Process a decrypted, authenticated auth packet. * @param payload The packet payload, after it has been decrypted. */ - private void processDecryptedAuth(byte[] payload, PeerNode pn, Peer replyTo, boolean oldOpennetPeer) { + private void processDecryptedAuth(byte[] payload, PeerNode pn, Peer replyTo, boolean oldOpennetPeer) throws InvalidKeyException { if(logMINOR) Logger.minor(this, "Processing decrypted auth packet from "+replyTo+" for "+pn); if(pn.isDisabled()) { if(logMINOR) Logger.minor(this, "Won't connect to a disabled peer ("+pn+ ')'); @@ -759,7 +765,7 @@ * ACM Transactions on Information and System Security, Vol 7 No 2, May 2004, Pages 1-30. * */ - private void processJFKMessage1(byte[] payload,int offset,PeerNode pn,Peer replyTo, boolean unknownInitiator, int setupType, int negType) + private void processJFKMessage1(byte[] payload,int offset,PeerNode pn,Peer replyTo, boolean unknownInitiator, int setupType, int negType) throws InvalidKeyException { long t1=System.currentTimeMillis(); if(logMINOR) Logger.minor(this, "Got a JFK(1) message, processing it - "+pn); @@ -854,7 +860,7 @@ * @param pn The node to encrypt the message for. CAN BE NULL if anonymous-initiator. * @param replyTo The peer to send the packet to. */ - private void sendJFKMessage2(byte[] nonceInitator, byte[] hisExponential, PeerNode pn, Peer replyTo, boolean unknownInitiator, int setupType, int negType) { + private void sendJFKMessage2(byte[] nonceInitator, byte[] hisExponential, PeerNode pn, Peer replyTo, boolean unknownInitiator, int setupType, int negType) throws InvalidKeyException { if(logMINOR) Logger.minor(this, "Sending a JFK(2) message to "+pn); DiffieHellmanLightContext ctx = getLightDiffieHellmanContext(); // g^r @@ -864,7 +870,7 @@ node.random.nextBytes(myNonce); byte[] r = ctx.signature.getRBytes(Node.SIGNATURE_PARAMETER_LENGTH); byte[] s = ctx.signature.getSBytes(Node.SIGNATURE_PARAMETER_LENGTH); - byte[] authenticator = HMAC.macWithSHA256(getTransientKey(),assembleJFKAuthenticator(myExponential, hisExponential, myNonce, nonceInitator, replyTo.getAddress().getAddress()), HASH_LENGTH); + byte[] authenticator = HMAC.mac(HMAC.ALGORITHM.HmacSHA256, getTransientKey(), assembleJFKAuthenticator(myExponential, hisExponential, myNonce, nonceInitator, replyTo.getAddress().getAddress())); if(logMINOR) Logger.minor(this, "We are using the following HMAC : " + HexUtil.bytesToHex(authenticator)); byte[] message2 = new byte[NONCE_SIZE*2+DiffieHellman.modulusLengthInBytes()+ @@ -926,7 +932,7 @@ * @param pn The peerNode we are talking to. Cannot be null as we are the initiator. */ - private void processJFKMessage2(byte[] payload,int inputOffset,PeerNode pn,Peer replyTo, boolean unknownInitiator, int setupType, int negType) + private void processJFKMessage2(byte[] payload,int inputOffset,PeerNode pn,Peer replyTo, boolean unknownInitiator, int setupType, int negType) throws InvalidKeyException { long t1=System.currentTimeMillis(); if(logMINOR) Logger.minor(this, "Got a JFK(2) message, processing it - "+pn.getPeer()); @@ -1038,7 +1044,7 @@ * responder. * @return byte Message3 */ - private void processJFKMessage3(byte[] payload, int inputOffset, PeerNode pn,Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator, int setupType, int negType) + private void processJFKMessage3(byte[] payload, int inputOffset, PeerNode pn,Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator, int setupType, int negType) throws InvalidKeyException { final long t1 = System.currentTimeMillis(); if(logMINOR) Logger.minor(this, "Got a JFK(3) message, processing it - "+pn); @@ -1085,7 +1091,7 @@ // We *WANT* to check the hmac before we do the lookup on the hashmap // @see https://bugs.freenetproject.org/view.php?id=1604 - if(!HMAC.verifyWithSHA256(getTransientKey(), assembleJFKAuthenticator(responderExponential, initiatorExponential, nonceResponder, nonceInitiator, replyTo.getAddress().getAddress()) , authenticator)) { + if(!HMAC.verify(HMAC.ALGORITHM.HmacSHA256, getTransientKey(), assembleJFKAuthenticator(responderExponential, initiatorExponential, nonceResponder, nonceInitiator, replyTo.getAddress().getAddress()) , authenticator)) { if(shouldLogErrorInHandshake(t1)) Logger.normal(this, "The HMAC doesn't match; let's discard the packet (either we rekeyed or we are victim of forgery) - JFK3 - "+pn); return; @@ -1123,10 +1129,10 @@ return; } BigInteger computedExponential = ctx.getHMACKey(_hisExponential, Global.DHgroupA); - byte[] Ks = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "0"); - byte[] Ke = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "1"); - byte[] Ka = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "2"); - c.initialize(Ke); + SecretKey Ks = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "0"); + SecretKey Ke = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "1"); + SecretKey Ka = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "2"); + c.initialize(Ke.getEncoded()); final PCFBMode pk = PCFBMode.create(c); int ivLength = pk.lengthIV(); int decypheredPayloadOffset = 0; @@ -1135,7 +1141,7 @@ System.arraycopy(JFK_PREFIX_INITIATOR, 0, decypheredPayload, decypheredPayloadOffset, JFK_PREFIX_INITIATOR.length); decypheredPayloadOffset += JFK_PREFIX_INITIATOR.length; System.arraycopy(payload, inputOffset, decypheredPayload, decypheredPayloadOffset, decypheredPayload.length-decypheredPayloadOffset); - if(!HMAC.verifyWithSHA256(Ka, decypheredPayload, hmac)) { + if(!HMAC.verify(HMAC.ALGORITHM.HmacSHA256 ,Ka, decypheredPayload, hmac)) { Logger.error(this, "The inner-HMAC doesn't match; let's discard the packet JFK(3) - "+pn); return; } @@ -1197,7 +1203,7 @@ BlockCipher cs = null; try { cs = new Rijndael(256, 256); } catch (UnsupportedCipherException e) {} - cs.initialize(Ks); + cs.initialize(Ks.getEncoded()); // Promote if necessary boolean dontWant = false; @@ -1292,7 +1298,7 @@ * @param pn The PeerNode we are talking to. Cannot be null as we are the initiator. * @param replyTo The Peer we are replying to. */ - private boolean processJFKMessage4(byte[] payload, int inputOffset, PeerNode pn, Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator, int setupType, int negType) + private boolean processJFKMessage4(byte[] payload, int inputOffset, PeerNode pn, Peer replyTo, boolean oldOpennetPeer, boolean unknownInitiator, int setupType, int negType) throws InvalidKeyException { final long t1 = System.currentTimeMillis(); if(logMINOR) Logger.minor(this, "Got a JFK(4) message, processing it - "+pn.getPeer()); @@ -1328,7 +1334,7 @@ System.arraycopy(payload, inputOffset, hmac, 0, HASH_LENGTH); inputOffset += HASH_LENGTH; - c.initialize(pn.jfkKe); + c.initialize(pn.jfkKe.getEncoded()); final PCFBMode pk = PCFBMode.create(c); int ivLength = pk.lengthIV(); int decypheredPayloadOffset = 0; @@ -1337,7 +1343,7 @@ System.arraycopy(JFK_PREFIX_RESPONDER, 0, decypheredPayload, decypheredPayloadOffset, JFK_PREFIX_RESPONDER.length); decypheredPayloadOffset += JFK_PREFIX_RESPONDER.length; System.arraycopy(payload, inputOffset, decypheredPayload, decypheredPayloadOffset, payload.length-inputOffset); - if(!HMAC.verifyWithSHA256(pn.jfkKa, decypheredPayload, hmac)) { + if(!HMAC.verify(HMAC.ALGORITHM.HmacSHA256, pn.jfkKa, decypheredPayload, hmac)) { Logger.normal(this, "The digest-HMAC doesn't match; let's discard the packet - "+pn.getPeer()); return false; } @@ -1436,7 +1442,7 @@ } // We change the key - c.initialize(pn.jfkKs); + c.initialize(pn.jfkKs.getEncoded()); if(pn.completedHandshake(bootID, hisRef, 0, hisRef.length, c, pn.jfkKs, replyTo, false, negType, trackerID, true, reusedTracker) >= 0) { if(dontWant) node.peers.disconnect(pn, true, true, true); @@ -1478,7 +1484,7 @@ * @param replyTo The Peer to send the packet to. */ - private void sendJFKMessage3(int version,final int negType,int phase,byte[] nonceInitiator,byte[] nonceResponder,byte[] hisExponential, byte[] authenticator, final PeerNode pn, final Peer replyTo, final boolean unknownInitiator, final int setupType) + private void sendJFKMessage3(int version,final int negType,int phase,byte[] nonceInitiator,byte[] nonceResponder,byte[] hisExponential, byte[] authenticator, final PeerNode pn, final Peer replyTo, final boolean unknownInitiator, final int setupType) throws InvalidKeyException { if(logMINOR) Logger.minor(this, "Sending a JFK(3) message to "+pn.getPeer()); long t1=System.currentTimeMillis(); @@ -1543,7 +1549,7 @@ pn.jfkKs = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "0"); pn.jfkKe = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "1"); pn.jfkKa = computeJFKSharedKey(computedExponential, nonceInitiator, nonceResponder, "2"); - c.initialize(pn.jfkKe); + c.initialize(pn.jfkKe.getEncoded()); PCFBMode pcfb = PCFBMode.create(c); int ivLength = pcfb.lengthIV(); byte[] iv = new byte[ivLength]; @@ -1566,7 +1572,7 @@ pcfb.blockEncipher(cleartext, cleartextToEncypherOffset, cleartext.length-cleartextToEncypherOffset); // We compute the HMAC of (prefix + cyphertext) Includes the IV! - byte[] hmac = HMAC.macWithSHA256(pn.jfkKa, cleartext, HASH_LENGTH); + byte[] hmac = HMAC.mac(HMAC.ALGORITHM.HmacSHA256, pn.jfkKa, cleartext); // copy stuffs back to the message System.arraycopy(hmac, 0, message3, offset, HASH_LENGTH); @@ -1611,7 +1617,7 @@ * @param pn The PeerNode to encrypt the auth packet to. Cannot be null, because even in anonymous initiator, * we will have created one before calling this method. */ - private void sendJFKMessage4(int version,int negType,int phase,byte[] nonceInitiator,byte[] nonceResponder,byte[] initiatorExponential,byte[] responderExponential, BlockCipher c, byte[] Ke, byte[] Ka, byte[] authenticator, byte[] hisRef, PeerNode pn, Peer replyTo, boolean unknownInitiator, int setupType, long newTrackerID, boolean sameAsOldTrackerID) + private void sendJFKMessage4(int version,int negType,int phase,byte[] nonceInitiator,byte[] nonceResponder,byte[] initiatorExponential,byte[] responderExponential, BlockCipher c, SecretKey Ke, SecretKey Ka, byte[] authenticator, byte[] hisRef, PeerNode pn, Peer replyTo, boolean unknownInitiator, int setupType, long newTrackerID, boolean sameAsOldTrackerID) throws InvalidKeyException { if(logMINOR) Logger.minor(this, "Sending a JFK(4) message to "+pn.getPeer()); @@ -1667,7 +1673,7 @@ pk.blockEncipher(cyphertext, cleartextToEncypherOffset, cyphertext.length - cleartextToEncypherOffset); // We compute the HMAC of (prefix + iv + signature) - byte[] hmac = HMAC.macWithSHA256(Ka, cyphertext, HASH_LENGTH); + byte[] hmac = HMAC.mac(HMAC.ALGORITHM.HmacSHA256, Ka, cyphertext); // Message4 = hmac + IV + encryptedSignature byte[] message4 = new byte[HASH_LENGTH + ivLength + (cyphertext.length - cleartextToEncypherOffset)]; @@ -3032,13 +3038,13 @@ return result; } - private byte[] getTransientKey() { + private SecretKey getTransientKey() { synchronized (authenticatorCache) { return transientKey; } } - private byte[] computeJFKSharedKey(BigInteger exponential, byte[] nI, byte[] nR, String what) { + private SecretKey computeJFKSharedKey(BigInteger exponential, byte[] nI, byte[] nR, String what) throws InvalidKeyException { assert("0".equals(what) || "1".equals(what) || "2".equals(what)); byte[] number = null; try { @@ -3055,7 +3061,7 @@ offset += NONCE_SIZE; System.arraycopy(number, 0, toHash, offset, number.length); - return HMAC.macWithSHA256(exponential.toByteArray(), toHash, HASH_LENGTH); + return new SecretKeySpec(HMAC.mac(HMAC.ALGORITHM.HmacSHA256, new SecretKeySpec(exponential.toByteArray(), "RAW"), toHash), "RAW"); } private long timeLastReset = -1; @@ -3080,7 +3086,10 @@ } timeLastReset = now; - node.random.nextBytes(transientKey); + // FIXME: Use the KeyGenerator! + byte[] trKey = new byte[TRANSIENT_KEY_SIZE]; + node.random.nextBytes(trKey); + transientKey = new SecretKeySpec(trKey, "RAW"); // reset the authenticator cache authenticatorCache.clear(); Modified: trunk/freenet/src/freenet/node/FailureTable.java =================================================================== --- trunk/freenet/src/freenet/node/FailureTable.java 2009-01-30 18:13:09 UTC (rev 25405) +++ trunk/freenet/src/freenet/node/FailureTable.java 2009-01-30 18:35:33 UTC (rev 25406) @@ -27,6 +27,8 @@ import freenet.support.io.NativeThread; // FIXME it is ESSENTIAL that we delete the ULPR data on requestors etc once we have found the key. +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; // Otherwise it will be much too easy to trace a request if an attacker busts the node afterwards. // We can use an HMAC or something to authenticate offers. @@ -59,7 +61,7 @@ /** Offers expire after 10 minutes */ static final int OFFER_EXPIRY_TIME = 10*60*1000; /** HMAC key for the offer authenticator */ - final byte[] offerAuthenticatorKey; + final SecretKey offerAuthenticatorKey; /** Clean up old data every 30 minutes to save memory and improve privacy */ static final int CLEANUP_PERIOD = 30*60*1000; @@ -70,8 +72,10 @@ entriesByKey = new LRUHashtable<Key,FailureTableEntry>(); blockOfferListByKey = new LRUHashtable<Key,BlockOfferList>(); this.node = node; - offerAuthenticatorKey = new byte[32]; - node.random.nextBytes(offerAuthenticatorKey); + // FIXME: use KeyGenerator!! + byte[] offerAuthenticatorKey2 = new byte[32]; + node.random.nextBytes(offerAuthenticatorKey2); + offerAuthenticatorKey = new SecretKeySpec(offerAuthenticatorKey2, "RAW"); logMINOR = Logger.shouldLog(Logger.MINOR, this); logDEBUG = Logger.shouldLog(Logger.DEBUG, this); offerExecutor = new SerialExecutor(NativeThread.HIGH_PRIORITY); Modified: trunk/freenet/src/freenet/node/NodeDispatcher.java =================================================================== --- trunk/freenet/src/freenet/node/NodeDispatcher.java 2009-01-30 18:13:09 UTC (rev 25405) +++ trunk/freenet/src/freenet/node/NodeDispatcher.java 2009-01-30 18:35:33 UTC (rev 25406) @@ -21,6 +21,7 @@ import freenet.support.Logger; import freenet.support.LogThresholdCallback; import freenet.support.ShortBuffer; +import java.security.InvalidKeyException; /** * @author amphibian @@ -258,7 +259,8 @@ Key key = (Key) m.getObject(DMT.KEY); byte[] authenticator = ((ShortBuffer) m.getObject(DMT.OFFER_AUTHENTICATOR)).getData(); long uid = m.getLong(DMT.UID); - if(!HMAC.verifyWithSHA256(node.failureTable.offerAuthenticatorKey, key.getFullKey(), authenticator)) { + try{ + if(!HMAC.verify(HMAC.ALGORITHM.HmacSHA256, node.failureTable.offerAuthenticatorKey, key.getFullKey(), authenticator)) { Logger.error(this, "Invalid offer request from "+source+" : authenticator did not verify"); try { source.sendAsync(DMT.createFNPGetOfferedKeyInvalid(uid, DMT.GET_OFFERED_KEY_REJECTED_BAD_AUTHENTICATOR), null, node.failureTable.senderCounter); @@ -267,6 +269,10 @@ } return true; } + } catch (InvalidKeyException e) { + Logger.error(this, e.getMessage(), e); + return true; + } if(logMINOR) Logger.minor(this, "Valid GetOfferedKey for "+key+" from "+source); // Do we want it? We can RejectOverload if we don't have the bandwidth... Modified: trunk/freenet/src/freenet/node/PeerNode.java =================================================================== --- trunk/freenet/src/freenet/node/PeerNode.java 2009-01-30 18:13:09 UTC (rev 25405) +++ trunk/freenet/src/freenet/node/PeerNode.java 2009-01-30 18:35:33 UTC (rev 25406) @@ -72,6 +72,8 @@ import freenet.support.math.TimeDecayingRunningAverage; import freenet.support.transport.ip.HostnameSyntaxException; import freenet.support.transport.ip.IPUtil; +import java.security.InvalidKeyException; +import javax.crypto.SecretKey; /** * @author amphibian @@ -105,9 +107,9 @@ private byte[] jfkBuffer; //TODO: sync ? - protected byte[] jfkKa; - protected byte[] jfkKe; - protected byte[] jfkKs; + protected SecretKey jfkKa; + protected SecretKey jfkKe; + protected SecretKey jfkKs; protected byte[] jfkMyRef; // The following is used only if we are the initiator @@ -1836,7 +1838,7 @@ * @return The ID of the new PacketTracker. If this is different to the passed-in trackerID, then * it's a new tracker. -1 to indicate failure. */ - public long completedHandshake(long thisBootID, byte[] data, int offset, int length, BlockCipher encCipher, byte[] encKey, Peer replyTo, boolean unverified, int negType, long trackerID, boolean isJFK4, boolean jfk4SameAsOld) { + public long completedHandshake(long thisBootID, byte[] data, int offset, int length, BlockCipher encCipher, SecretKey encKey, Peer replyTo, boolean unverified, int negType, long trackerID, boolean isJFK4, boolean jfk4SameAsOld) { long now = System.currentTimeMillis(); if(logMINOR) Logger.minor(this, "Tracker ID "+trackerID+" isJFK4="+isJFK4+" jfk4SameAsOld="+jfk4SameAsOld); @@ -1966,7 +1968,7 @@ } else { // else it's a rekey } - newTracker = new SessionKey(this, packets, encCipher, encKey); + newTracker = new SessionKey(this, packets, encCipher, encKey.getEncoded()); if(logMINOR) Logger.minor(this, "New key tracker in completedHandshake: "+newTracker+" for "+packets+" for "+shortToString()+" neg type "+negType); if(unverified) { if(unverifiedTracker != null) { @@ -3478,13 +3480,18 @@ public void offer(Key key) { byte[] keyBytes = key.getFullKey(); // FIXME maybe the authenticator should be shorter than 32 bytes to save memory? - byte[] authenticator = HMAC.macWithSHA256(node.failureTable.offerAuthenticatorKey, keyBytes, 32); - Message msg = DMT.createFNPOfferKey(key, authenticator); - try { - sendAsync(msg, null, node.nodeStats.sendOffersCtr); - } catch(NotConnectedException e) { - // Ignore - } + byte[] authenticator = null; + try { + authenticator = HMAC.mac(HMAC.ALGORITHM.HmacSHA256, node.failureTable.offerAuthenticatorKey, keyBytes); + Message msg = DMT.createFNPOfferKey(key, authenticator); + try { + sendAsync(msg, null, node.nodeStats.sendOffersCtr); + } catch (NotConnectedException e) { + // Ignore + } + } catch (InvalidKeyException k) { + Logger.error(this, "Invalid Key!", k); + } } public OutgoingPacketMangler getOutgoingMangler() { _______________________________________________ cvs mailing list [email protected] http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs
