From 525d909d0830a4071774187038ebf338681b8c3e Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Thu, 11 Apr 2013 12:09:35 +0100
Subject: [PATCH] Avoid redundant derivation from dead secrets.

Find the newest dead secret for each endpoint, erase any others and
derive from the newest.
---
 .../sf/briar/transport/KeyManagerImpl.java    | 24 +++++++++++++++++--
 .../briar/transport/KeyManagerImplTest.java   | 21 ++--------------
 .../transport/KeyRotationIntegrationTest.java | 11 +--------
 3 files changed, 25 insertions(+), 31 deletions(-)

diff --git a/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java b/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java
index 9e7629108c..eb0ee7a6da 100644
--- a/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java
+++ b/briar-core/src/net/sf/briar/transport/KeyManagerImpl.java
@@ -10,6 +10,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.TimerTask;
 import java.util.logging.Logger;
 
@@ -144,8 +145,27 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 	// Locking: this
 	private Collection<TemporarySecret> replaceDeadSecrets(long now,
 			Collection<TemporarySecret> dead) {
-		Collection<TemporarySecret> created = new ArrayList<TemporarySecret>();
+		// If there are several dead secrets for an endpoint, use the newest
+		Map<EndpointKey, TemporarySecret> newest =
+				new HashMap<EndpointKey, TemporarySecret>();
 		for(TemporarySecret s : dead) {
+			EndpointKey k = new EndpointKey(s);
+			TemporarySecret exists = newest.get(k);
+			if(exists == null) {
+				// There's no other secret for this endpoint
+				newest.put(k, s);
+			} else if(exists.getPeriod() < s.getPeriod()) {
+				// There's an older secret - erase it and use this one instead
+				ByteUtils.erase(exists.getSecret());
+				newest.put(k, s);
+			} else {
+				// There's a newer secret - erase this one
+				ByteUtils.erase(s.getSecret());
+			}
+		}
+		Collection<TemporarySecret> created = new ArrayList<TemporarySecret>();
+		for(Entry<EndpointKey, TemporarySecret> e : newest.entrySet()) {
+			TemporarySecret s = e.getValue();
 			Long maxLatency = maxLatencies.get(s.getTransportId());
 			if(maxLatency == null) throw new IllegalStateException();
 			// Work out which rotation period we're in
@@ -167,7 +187,7 @@ class KeyManagerImpl extends TimerTask implements KeyManager, DatabaseListener {
 			// Add the secrets to their respective maps - copies may already
 			// exist, in which case erase the new copies (the old copies are
 			// referenced by the connection recogniser)
-			EndpointKey k = new EndpointKey(s);
+			EndpointKey k = e.getKey();
 			if(oldSecrets.containsKey(k)) {
 				ByteUtils.erase(b1);
 			} else {
diff --git a/briar-tests/src/net/sf/briar/transport/KeyManagerImplTest.java b/briar-tests/src/net/sf/briar/transport/KeyManagerImplTest.java
index 93c05d567b..0f7bed504b 100644
--- a/briar-tests/src/net/sf/briar/transport/KeyManagerImplTest.java
+++ b/briar-tests/src/net/sf/briar/transport/KeyManagerImplTest.java
@@ -355,15 +355,6 @@ public class KeyManagerImplTest extends BriarTestCase {
 			// The current time is the end of period 3
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH + 3 * ROTATION_PERIOD_LENGTH - 1));
-			// The secrets for periods 3 and 4 should be derived from secret 0
-			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
-			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
-			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
-			oneOf(crypto).deriveNextSecret(secret3, 4);
-			will(returnValue(secret4.clone()));
 			// The secrets for periods 3 and 4 should be derived from secret 1
 			oneOf(crypto).deriveNextSecret(secret1, 2);
 			will(returnValue(secret2.clone()));
@@ -371,9 +362,9 @@ public class KeyManagerImplTest extends BriarTestCase {
 			will(returnValue(secret3.clone()));
 			oneOf(crypto).deriveNextSecret(secret3, 4);
 			will(returnValue(secret4.clone()));
-			// One copy of each of the new secrets should be stored
+			// The new secrets should be stored
 			oneOf(db).addSecrets(Arrays.asList(s3, s4));
-			// The secrets for periods 2 - 3 should be added to the recogniser
+			// The secrets for periods 2 - 4 should be added to the recogniser
 			oneOf(connectionRecogniser).addSecret(s2);
 			oneOf(connectionRecogniser).addSecret(s3);
 			oneOf(connectionRecogniser).addSecret(s4);
@@ -570,14 +561,6 @@ public class KeyManagerImplTest extends BriarTestCase {
 			// run() during period 3 (late): the secrets should be rotated
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH + 2 * ROTATION_PERIOD_LENGTH + 1));
-			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
-			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
-			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
-			oneOf(crypto).deriveNextSecret(secret3, 4);
-			will(returnValue(secret4.clone()));
 			oneOf(crypto).deriveNextSecret(secret1, 2);
 			will(returnValue(secret2.clone()));
 			oneOf(crypto).deriveNextSecret(secret2, 3);
diff --git a/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java b/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java
index ed5230b833..380c95c1ed 100644
--- a/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/transport/KeyRotationIntegrationTest.java
@@ -848,15 +848,6 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			// The current time is the end of period 3
 			oneOf(clock).currentTimeMillis();
 			will(returnValue(EPOCH + 3 * ROTATION_PERIOD_LENGTH - 1));
-			// The secrets for periods 3 and 4 should be derived from secret 0
-			oneOf(crypto).deriveNextSecret(secret0, 1);
-			will(returnValue(secret1.clone()));
-			oneOf(crypto).deriveNextSecret(secret1, 2);
-			will(returnValue(secret2.clone()));
-			oneOf(crypto).deriveNextSecret(secret2, 3);
-			will(returnValue(secret3.clone()));
-			oneOf(crypto).deriveNextSecret(secret3, 4);
-			will(returnValue(secret4.clone()));
 			// The secrets for periods 3 and 4 should be derived from secret 1
 			oneOf(crypto).deriveNextSecret(secret1, 2);
 			will(returnValue(secret2.clone()));
@@ -864,7 +855,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
 			will(returnValue(secret3.clone()));
 			oneOf(crypto).deriveNextSecret(secret3, 4);
 			will(returnValue(secret4.clone()));
-			// One copy of each of the new secrets should be stored
+			// The new secrets should be stored
 			oneOf(db).addSecrets(Arrays.asList(s3, s4));
 			// The recogniser should derive the tags for period 2
 			oneOf(crypto).getTagCipher();
-- 
GitLab