From e65c2e279b77d0c2c67f7b77c10a0cb30ea27e82 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Fri, 29 May 2009 10:00:06 +0000
Subject: [PATCH]     * Session Keys:       - Don't instantiate unused
 SessionKeyPersistenceHelper       - Use TransientSessionKeyManager instead of
 PersistentSessionKeyManager       - Add generics to
 TransientSessionKeyManager to help understand it       - Change initial
 session map size to 64 (was 1024)       - Prepare for per-destination
 SessionKeyManagers in ElGamalAESEngine

---
 core/java/src/net/i2p/I2PAppContext.java      |   5 +-
 .../src/net/i2p/crypto/ElGamalAESEngine.java  |  15 +-
 .../crypto/PersistentSessionKeyManager.java   | 190 ------------------
 .../src/net/i2p/crypto/SessionKeyManager.java |   6 +-
 .../crypto/TransientSessionKeyManager.java    | 137 +++++++------
 router/java/src/net/i2p/router/Router.java    |   8 +-
 .../router/SessionKeyPersistenceHelper.java   | 115 -----------
 7 files changed, 97 insertions(+), 379 deletions(-)
 delete mode 100644 core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java
 delete mode 100644 router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java

diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java
index f26f74ab7b..3f44146b43 100644
--- a/core/java/src/net/i2p/I2PAppContext.java
+++ b/core/java/src/net/i2p/I2PAppContext.java
@@ -17,9 +17,9 @@ import net.i2p.crypto.ElGamalEngine;
 import net.i2p.crypto.HMAC256Generator;
 import net.i2p.crypto.HMACGenerator;
 import net.i2p.crypto.KeyGenerator;
-import net.i2p.crypto.PersistentSessionKeyManager;
 import net.i2p.crypto.SHA256Generator;
 import net.i2p.crypto.SessionKeyManager;
+import net.i2p.crypto.TransientSessionKeyManager;
 import net.i2p.data.RoutingKeyGenerator;
 import net.i2p.stat.StatManager;
 import net.i2p.util.Clock;
@@ -256,7 +256,8 @@ public class I2PAppContext {
     private void initializeSessionKeyManager() {
         synchronized (this) {
             if (_sessionKeyManager == null) 
-                _sessionKeyManager = new PersistentSessionKeyManager(this);
+                //_sessionKeyManager = new PersistentSessionKeyManager(this);
+                _sessionKeyManager = new TransientSessionKeyManager(this);
             _sessionKeyManagerInitialized = true;
         }
     }
diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java
index 1d67918f78..3e191faaa4 100644
--- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java
+++ b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java
@@ -58,12 +58,19 @@ public class ElGamalAESEngine {
                                                    new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
     }
 
+    /**
+     * Decrypt the message using the given private key using tags from the given key manager.
+     */
+    public byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException {
+        return decrypt(data, targetPrivateKey, _context.sessionKeyManager());
+    }
+
     /**
      * Decrypt the message using the given private key.  This works according to the
      * ElGamal+AES algorithm in the data structure spec.
      *
      */
-    public byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException {
+    public byte[] decrypt(byte data[], PrivateKey targetPrivateKey, SessionKeyManager keyManager) throws DataFormatException {
         if (data == null) {
             if (_log.shouldLog(Log.ERROR)) _log.error("Null data being decrypted?");
             return null;
@@ -76,7 +83,7 @@ public class ElGamalAESEngine {
         byte tag[] = new byte[32];
         System.arraycopy(data, 0, tag, 0, tag.length);
         SessionTag st = new SessionTag(tag);
-        SessionKey key = _context.sessionKeyManager().consumeTag(st);
+        SessionKey key = keyManager.consumeTag(st);
         SessionKey foundKey = new SessionKey();
         foundKey.setData(null);
         SessionKey usedKey = new SessionKey();
@@ -124,11 +131,11 @@ public class ElGamalAESEngine {
             if (foundKey.getData() != null) {
                 if (_log.shouldLog(Log.DEBUG)) 
                     _log.debug("Found key: " + foundKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
-                _context.sessionKeyManager().tagsReceived(foundKey, foundTags);
+                keyManager.tagsReceived(foundKey, foundTags);
             } else {
                 if (_log.shouldLog(Log.DEBUG)) 
                     _log.debug("Used key: " + usedKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
-                _context.sessionKeyManager().tagsReceived(usedKey, foundTags);
+                keyManager.tagsReceived(usedKey, foundTags);
             }
         }
         return decrypted;
diff --git a/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java b/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java
deleted file mode 100644
index 811e6e4121..0000000000
--- a/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package net.i2p.crypto;
-
-/*
- * free (adj.): unencumbered; not under the control of others
- * Written by jrandom in 2003 and released into the public domain 
- * with no warranty of any kind, either expressed or implied.  
- * It probably won't  make your computer catch on fire, or eat 
- * your children, but it might.  Use at your own risk.
- *
- */
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import net.i2p.I2PAppContext;
-import net.i2p.data.DataFormatException;
-import net.i2p.data.DataHelper;
-import net.i2p.data.PublicKey;
-import net.i2p.data.SessionKey;
-import net.i2p.data.SessionTag;
-import net.i2p.util.Log;
-
-/**
- * Expose the functionality to allow people to write out and read in the 
- * session key and session tag information via streams.  This implementation
- * does not write anywhere except where its told.
- *
- */
-public class PersistentSessionKeyManager extends TransientSessionKeyManager {
-    private Log _log;
-    private Object _yk = YKGenerator.class;
-
-    
-    /** 
-     * The session key manager should only be constructed and accessed through the 
-     * application context.  This constructor should only be used by the 
-     * appropriate application context itself.
-     *
-     */
-    public PersistentSessionKeyManager(I2PAppContext context) {
-        super(context);
-        _log = context.logManager().getLog(PersistentSessionKeyManager.class);
-    }
-    private PersistentSessionKeyManager() {
-        this(null);
-    }
-    /**
-     * Write the session key data to the given stream
-     *
-     */
-    public void saveState(OutputStream out) throws IOException, DataFormatException {
-        if (true) return;
-        
-        Set tagSets = getInboundTagSets();
-        Set sessions = getOutboundSessions();
-        if (_log.shouldLog(Log.INFO))
-            _log.info("Saving state with " + tagSets.size() + " inbound tagSets and " 
-                      + sessions.size() + " outbound sessions");
-
-        DataHelper.writeLong(out, 4, tagSets.size());
-        for (Iterator iter = tagSets.iterator(); iter.hasNext();) {
-            TagSet ts = (TagSet) iter.next();
-            writeTagSet(out, ts);
-        }
-        DataHelper.writeLong(out, 4, sessions.size());
-        for (Iterator iter = sessions.iterator(); iter.hasNext();) {
-            OutboundSession sess = (OutboundSession) iter.next();
-            writeOutboundSession(out, sess);
-        }
-    }
-
-    /**
-     * Load the session key data from the given stream
-     *
-     */
-    public void loadState(InputStream in) throws IOException, DataFormatException {
-        int inboundSets = (int) DataHelper.readLong(in, 4);
-        Set tagSets = new HashSet(inboundSets);
-        for (int i = 0; i < inboundSets; i++) {
-            TagSet ts = readTagSet(in);
-            tagSets.add(ts);
-        }
-        int outboundSessions = (int) DataHelper.readLong(in, 4);
-        Set sessions = new HashSet(outboundSessions);
-        for (int i = 0; i < outboundSessions; i++) {
-            OutboundSession sess = readOutboundSession(in);
-            sessions.add(sess);
-        }
-
-        if (_log.shouldLog(Log.INFO))
-            _log.info("Loading state with " + tagSets.size() + " inbound tagSets and " 
-                      + sessions.size() + " outbound sessions");
-        setData(tagSets, sessions);
-    }
-
-    private void writeOutboundSession(OutputStream out, OutboundSession sess) throws IOException, DataFormatException {
-        sess.getTarget().writeBytes(out);
-        sess.getCurrentKey().writeBytes(out);
-        DataHelper.writeDate(out, new Date(sess.getEstablishedDate()));
-        DataHelper.writeDate(out, new Date(sess.getLastUsedDate()));
-        List sets = sess.getTagSets();
-        DataHelper.writeLong(out, 2, sets.size());
-        for (Iterator iter = sets.iterator(); iter.hasNext();) {
-            TagSet set = (TagSet) iter.next();
-            writeTagSet(out, set);
-        }
-    }
-
-    private void writeTagSet(OutputStream out, TagSet ts) throws IOException, DataFormatException {
-        ts.getAssociatedKey().writeBytes(out);
-        DataHelper.writeDate(out, new Date(ts.getDate()));
-        DataHelper.writeLong(out, 2, ts.getTags().size());
-        for (Iterator iter = ts.getTags().iterator(); iter.hasNext();) {
-            SessionTag tag = (SessionTag) iter.next();
-            out.write(tag.getData());
-        }
-    }
-
-    private OutboundSession readOutboundSession(InputStream in) throws IOException, DataFormatException {
-        PublicKey key = new PublicKey();
-        key.readBytes(in);
-        SessionKey skey = new SessionKey();
-        skey.readBytes(in);
-        Date established = DataHelper.readDate(in);
-        Date lastUsed = DataHelper.readDate(in);
-        int tagSets = (int) DataHelper.readLong(in, 2);
-        ArrayList sets = new ArrayList(tagSets);
-        for (int i = 0; i < tagSets; i++) {
-            TagSet ts = readTagSet(in);
-            sets.add(ts);
-        }
-
-        return new OutboundSession(key, skey, established.getTime(), lastUsed.getTime(), sets);
-    }
-
-    private TagSet readTagSet(InputStream in) throws IOException, DataFormatException {
-        SessionKey key = new SessionKey();
-        key.readBytes(in);
-        Date date = DataHelper.readDate(in);
-        int numTags = (int) DataHelper.readLong(in, 2);
-        Set tags = new HashSet(numTags);
-        for (int i = 0; i < numTags; i++) {
-            SessionTag tag = new SessionTag();
-            byte val[] = new byte[SessionTag.BYTE_LENGTH];
-            int read = DataHelper.read(in, val);
-            if (read != SessionTag.BYTE_LENGTH)
-                throw new IOException("Unable to fully read a session tag [" + read + " not " + SessionTag.BYTE_LENGTH
-                                      + ")");
-            tag.setData(val);
-            tags.add(tag);
-        }
-        TagSet ts = new TagSet(tags, key, _context.clock().now());
-        ts.setDate(date.getTime());
-        return ts;
-    }
-
-    public static void main(String args[]) {
-        I2PAppContext ctx = new I2PAppContext();
-        Log log = ctx.logManager().getLog(PersistentSessionKeyManager.class);
-        PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)ctx.sessionKeyManager();
-        try {
-            mgr.loadState(new FileInputStream("sessionKeys.dat"));
-            String state = mgr.renderStatusHTML();
-            FileOutputStream fos = new FileOutputStream("sessionKeysBeforeExpire.html");
-            fos.write(state.getBytes());
-            fos.close();
-            int expired = mgr.aggressiveExpire();
-            log.error("Expired: " + expired);
-            String stateAfter = mgr.renderStatusHTML();
-            FileOutputStream fos2 = new FileOutputStream("sessionKeysAfterExpire.html");
-            fos2.write(stateAfter.getBytes());
-            fos2.close();
-        } catch (Throwable t) {
-            log.error("Error loading/storing sessionKeys", t);
-        }
-        try {
-            Thread.sleep(3000);
-        } catch (Throwable t) { // nop
-        }
-    }
-}
\ No newline at end of file
diff --git a/core/java/src/net/i2p/crypto/SessionKeyManager.java b/core/java/src/net/i2p/crypto/SessionKeyManager.java
index 5b609347bb..b1547864cd 100644
--- a/core/java/src/net/i2p/crypto/SessionKeyManager.java
+++ b/core/java/src/net/i2p/crypto/SessionKeyManager.java
@@ -93,7 +93,7 @@ public class SessionKeyManager {
      * method after receiving an ack to a message delivering them)
      *
      */
-    public void tagsDelivered(PublicKey target, SessionKey key, Set sessionTags) { // nop
+    public void tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) { // nop
     }
 
     /**
@@ -109,7 +109,7 @@ public class SessionKeyManager {
      * Accept the given tags and associate them with the given key for decryption
      *
      */
-    public void tagsReceived(SessionKey key, Set sessionTags) { // nop
+    public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) { // nop
     }
 
     /**
@@ -130,4 +130,4 @@ public class SessionKeyManager {
      */
     public void shutdown() { // nop
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java
index 80cd18ac8b..7c496c62d0 100644
--- a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java
+++ b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java
@@ -33,12 +33,12 @@ import net.i2p.util.SimpleTimer;
  * out to disk so this should not be considered secure in that sense.
  *
  */
-class TransientSessionKeyManager extends SessionKeyManager {
+public class TransientSessionKeyManager extends SessionKeyManager {
     private Log _log;
     /** Map allowing us to go from the targeted PublicKey to the OutboundSession used */
-    private Map _outboundSessions;
+    private Map<PublicKey, OutboundSession> _outboundSessions;
     /** Map allowing us to go from a SessionTag to the containing TagSet */
-    private Map _inboundTagSets;
+    private Map<SessionTag, TagSet> _inboundTagSets;
     protected I2PAppContext _context;
 
     /** 
@@ -55,6 +55,10 @@ class TransientSessionKeyManager extends SessionKeyManager {
      *
      */
     public final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 5 * 60 * 1000;
+    /**
+     * a few MB? how about 16MB!
+     * This is the max size of _inboundTagSets.
+     */
     public final static int MAX_INBOUND_SESSION_TAGS = 500 * 1000; // this will consume at most a few MB
 
     /** 
@@ -67,7 +71,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
         super(context);
         _log = context.logManager().getLog(TransientSessionKeyManager.class);
         _context = context;
-        _outboundSessions = new HashMap(1024);
+        _outboundSessions = new HashMap(64);
         _inboundTagSets = new HashMap(1024);
         context.statManager().createRateStat("crypto.sessionTagsExpired", "How many tags/sessions are expired?", "Encryption", new long[] { 10*60*1000, 60*60*1000, 3*60*60*1000 });
         context.statManager().createRateStat("crypto.sessionTagsRemaining", "How many tags/sessions are remaining after a cleanup?", "Encryption", new long[] { 10*60*1000, 60*60*1000, 3*60*60*1000 });
@@ -85,28 +89,28 @@ class TransientSessionKeyManager extends SessionKeyManager {
     }
 
     /** TagSet */
-    protected Set getInboundTagSets() {
+    protected Set<TagSet> getInboundTagSets() {
         synchronized (_inboundTagSets) {
             return new HashSet(_inboundTagSets.values());
         }
     }
 
     /** OutboundSession */
-    protected Set getOutboundSessions() {
+    protected Set<OutboundSession> getOutboundSessions() {
         synchronized (_outboundSessions) {
             return new HashSet(_outboundSessions.values());
         }
     }
 
-    protected void setData(Set inboundTagSets, Set outboundSessions) {
+    protected void setData(Set<TagSet> inboundTagSets, Set<OutboundSession> outboundSessions) {
         if (_log.shouldLog(Log.INFO))
             _log.info("Loading " + inboundTagSets.size() + " inbound tag sets, and " 
                       + outboundSessions.size() + " outbound sessions");
-        Map tagSets = new HashMap(inboundTagSets.size());
-        for (Iterator iter = inboundTagSets.iterator(); iter.hasNext();) {
-            TagSet ts = (TagSet) iter.next();
-            for (Iterator tsIter = ts.getTags().iterator(); tsIter.hasNext();) {
-                SessionTag tag = (SessionTag) tsIter.next();
+        Map<SessionTag, TagSet> tagSets = new HashMap(inboundTagSets.size());
+        for (Iterator<TagSet> iter = inboundTagSets.iterator(); iter.hasNext();) {
+            TagSet ts = iter.next();
+            for (Iterator<SessionTag> tsIter = ts.getTags().iterator(); tsIter.hasNext();) {
+                SessionTag tag = tsIter.next();
                 tagSets.put(tag, ts);
             }
         }
@@ -114,9 +118,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
             _inboundTagSets.clear();
             _inboundTagSets.putAll(tagSets);
         }
-        Map sessions = new HashMap(outboundSessions.size());
-        for (Iterator iter = outboundSessions.iterator(); iter.hasNext();) {
-            OutboundSession sess = (OutboundSession) iter.next();
+        Map<PublicKey, OutboundSession> sessions = new HashMap(outboundSessions.size());
+        for (Iterator<OutboundSession> iter = outboundSessions.iterator(); iter.hasNext();) {
+            OutboundSession sess = iter.next();
             sessions.put(sess.getTarget(), sess);
         }
         synchronized (_outboundSessions) {
@@ -151,6 +155,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
      * Associate a new session key with the specified target.  Metrics to determine
      * when to expire that key begin with this call.
      *
+     * Unused except in tests?
      */
     @Override
     public void createSession(PublicKey target, SessionKey key) {
@@ -159,6 +164,18 @@ class TransientSessionKeyManager extends SessionKeyManager {
         addSession(sess);
     }
 
+    /**
+     * Same as above but for internal use, returns OutboundSession so we don't have
+     * to do a subsequent getSession()
+     *
+     */
+    private OutboundSession createAndReturnSession(PublicKey target, SessionKey key) {
+        OutboundSession sess = new OutboundSession(target);
+        sess.setCurrentKey(key);
+        addSession(sess);
+        return sess;
+    }
+
     /**
      * Retrieve the next available session tag for identifying the use of the given
      * key when communicating with the target.  If this returns null, no tags are
@@ -232,10 +249,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
                 _log.debug("Tags delivered: " + sessionTags.size() + " for key: " + key.toBase64() + ": " + sessionTags);
         }
         OutboundSession sess = getSession(target);
-        if (sess == null) {
-            createSession(target, key);
-            sess = getSession(target);
-        }
+        if (sess == null)
+            sess = createAndReturnSession(target, key);
         sess.setCurrentKey(key);
         TagSet set = new TagSet(sessionTags, key, _context.clock().now());
         sess.addTags(set);
@@ -257,13 +272,13 @@ class TransientSessionKeyManager extends SessionKeyManager {
      *
      */
     @Override
-    public void tagsReceived(SessionKey key, Set sessionTags) {
+    public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags) {
         int overage = 0;
         TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now());
         TagSet old = null;
         SessionTag dupTag = null;
-        for (Iterator iter = sessionTags.iterator(); iter.hasNext();) {
-            SessionTag tag = (SessionTag) iter.next();
+        for (Iterator<SessionTag> iter = sessionTags.iterator(); iter.hasNext();) {
+            SessionTag tag = iter.next();
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Receiving tag " + tag + " for key " + key.toBase64() + " / " + key.toString() + ": tagSet: " + tagSet);
             synchronized (_inboundTagSets) {
@@ -284,12 +299,12 @@ class TransientSessionKeyManager extends SessionKeyManager {
         if (old != null) {
             // drop both old and tagSet tags
             synchronized (_inboundTagSets) {
-                for (Iterator iter = old.getTags().iterator(); iter.hasNext(); ) {
-                    SessionTag tag = (SessionTag)iter.next();
+                for (Iterator<SessionTag> iter = old.getTags().iterator(); iter.hasNext(); ) {
+                    SessionTag tag = iter.next();
                     _inboundTagSets.remove(tag);
                 }
-                for (Iterator iter = sessionTags.iterator(); iter.hasNext(); ) {
-                    SessionTag tag = (SessionTag)iter.next();
+                for (Iterator<SessionTag> iter = sessionTags.iterator(); iter.hasNext(); ) {
+                    SessionTag tag = iter.next();
                     _inboundTagSets.remove(tag);
                 }
             }
@@ -326,10 +341,10 @@ class TransientSessionKeyManager extends SessionKeyManager {
         int tags = 0;
         int toRemove = overage * 2;
         _log.log(Log.CRIT, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
-        List removed = new ArrayList(toRemove);
+        List<TagSet> removed = new ArrayList(toRemove);
         synchronized (_inboundTagSets) {
-            for (Iterator iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
-                TagSet set = (TagSet)iter.next();
+            for (Iterator<TagSet> iter = _inboundTagSets.values().iterator(); iter.hasNext(); ) {
+                TagSet set = iter.next();
                 int size = set.getTags().size();
                 if (size > 1000)
                     absurd++;
@@ -345,8 +360,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
             }
             for (int i = 0; i < removed.size(); i++) {
                 TagSet cur = (TagSet)removed.get(i);
-                for (Iterator iter = cur.getTags().iterator(); iter.hasNext(); ) {
-                    SessionTag tag = (SessionTag)iter.next();
+                for (Iterator<SessionTag> iter = cur.getTags().iterator(); iter.hasNext(); ) {
+                    SessionTag tag = iter.next();
                     _inboundTagSets.remove(tag);
                     tags++;
                 }
@@ -429,9 +444,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
             bufSummary = new StringBuffer(1024);
         }
         synchronized (_inboundTagSets) {
-            for (Iterator iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
-                SessionTag tag = (SessionTag) iter.next();
-                TagSet ts = (TagSet) _inboundTagSets.get(tag);
+            for (Iterator<SessionTag> iter = _inboundTagSets.keySet().iterator(); iter.hasNext();) {
+                SessionTag tag = iter.next();
+                TagSet ts = _inboundTagSets.get(tag);
                 long age = now - ts.getDate();
                 if (age > SESSION_LIFETIME_MAX_MS) {
                 //if (ts.getDate() < now - SESSION_LIFETIME_MAX_MS) {
@@ -455,9 +470,9 @@ class TransientSessionKeyManager extends SessionKeyManager {
         //_log.warn("Expiring tags: [" + tagsToDrop + "]");
 
         synchronized (_outboundSessions) {
-            for (Iterator iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
-                PublicKey key = (PublicKey) iter.next();
-                OutboundSession sess = (OutboundSession) _outboundSessions.get(key);
+            for (Iterator<PublicKey> iter = _outboundSessions.keySet().iterator(); iter.hasNext();) {
+                PublicKey key = iter.next();
+                OutboundSession sess = _outboundSessions.get(key);
                 removed += sess.expireTags();
                 if (sess.availableTags() <= 0) {
                     iter.remove();
@@ -472,22 +487,22 @@ class TransientSessionKeyManager extends SessionKeyManager {
         StringBuffer buf = new StringBuffer(1024);
         buf.append("<h2>Inbound sessions</h2>");
         buf.append("<table border=\"1\">");
-        Set inbound = getInboundTagSets();
-        Map inboundSets = new HashMap(inbound.size());
-        for (Iterator iter = inbound.iterator(); iter.hasNext();) {
-            TagSet ts = (TagSet) iter.next();
+        Set<TagSet> inbound = getInboundTagSets();
+        Map<SessionKey, Set<TagSet>> inboundSets = new HashMap(inbound.size());
+        for (Iterator<TagSet> iter = inbound.iterator(); iter.hasNext();) {
+            TagSet ts = iter.next();
             if (!inboundSets.containsKey(ts.getAssociatedKey())) inboundSets.put(ts.getAssociatedKey(), new HashSet());
-            Set sets = (Set) inboundSets.get(ts.getAssociatedKey());
+            Set<TagSet> sets = inboundSets.get(ts.getAssociatedKey());
             sets.add(ts);
         }
-        for (Iterator iter = inboundSets.keySet().iterator(); iter.hasNext();) {
-            SessionKey skey = (SessionKey) iter.next();
-            Set sets = (Set) inboundSets.get(skey);
+        for (Iterator<SessionKey> iter = inboundSets.keySet().iterator(); iter.hasNext();) {
+            SessionKey skey = iter.next();
+            Set<TagSet> sets = inboundSets.get(skey);
             buf.append("<tr><td><b>Session key</b>: ").append(skey.toBase64()).append("</td>");
             buf.append("<td><b># Sets:</b> ").append(sets.size()).append("</td></tr>");
             buf.append("<tr><td colspan=\"2\"><ul>");
-            for (Iterator siter = sets.iterator(); siter.hasNext();) {
-                TagSet ts = (TagSet) siter.next();
+            for (Iterator<TagSet> siter = sets.iterator(); siter.hasNext();) {
+                TagSet ts = siter.next();
                 buf.append("<li><b>Received on:</b> ").append(new Date(ts.getDate())).append(" with ")
                    .append(ts.getTags().size()).append(" tags remaining</li>");
             }
@@ -498,17 +513,17 @@ class TransientSessionKeyManager extends SessionKeyManager {
         buf.append("<h2><b>Outbound sessions</b></h2>");
 
         buf.append("<table border=\"1\">");
-        Set outbound = getOutboundSessions();
-        for (Iterator iter = outbound.iterator(); iter.hasNext();) {
-            OutboundSession sess = (OutboundSession) iter.next();
+        Set<OutboundSession> outbound = getOutboundSessions();
+        for (Iterator<OutboundSession> iter = outbound.iterator(); iter.hasNext();) {
+            OutboundSession sess = iter.next();
             buf.append("<tr><td><b>Target key:</b> ").append(sess.getTarget().toString()).append("<br />");
             buf.append("<b>Established:</b> ").append(new Date(sess.getEstablishedDate())).append("<br />");
             buf.append("<b>Last Used:</b> ").append(new Date(sess.getLastUsedDate())).append("<br />");
             buf.append("<b># Sets:</b> ").append(sess.getTagSets().size()).append("</td></tr>");
             buf.append("<tr><td><b>Session key:</b> ").append(sess.getCurrentKey().toBase64()).append("</td></tr>");
             buf.append("<tr><td><ul>");
-            for (Iterator siter = sess.getTagSets().iterator(); siter.hasNext();) {
-                TagSet ts = (TagSet) siter.next();
+            for (Iterator<TagSet> siter = sess.getTagSets().iterator(); siter.hasNext();) {
+                TagSet ts = siter.next();
                 buf.append("<li><b>Sent on:</b> ").append(new Date(ts.getDate())).append(" with ").append(
                                                                                                           ts.getTags()
                                                                                                             .size())
@@ -526,13 +541,13 @@ class TransientSessionKeyManager extends SessionKeyManager {
         private SessionKey _currentKey;
         private long _established;
         private long _lastUsed;
-        private List _tagSets;
+        private List<TagSet> _tagSets;
 
         public OutboundSession(PublicKey target) {
             this(target, null, _context.clock().now(), _context.clock().now(), new ArrayList());
         }
 
-        OutboundSession(PublicKey target, SessionKey curKey, long established, long lastUsed, List tagSets) {
+        OutboundSession(PublicKey target, SessionKey curKey, long established, long lastUsed, List<TagSet> tagSets) {
             _target = target;
             _currentKey = curKey;
             _established = established;
@@ -541,7 +556,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
         }
 
         /** list of TagSet objects */
-        List getTagSets() {
+        List<TagSet> getTagSets() {
             synchronized (_tagSets) {
                 return new ArrayList(_tagSets);
             }
@@ -560,7 +575,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
             if (_currentKey != null) {
                 if (!_currentKey.equals(key)) {
                     int dropped = 0;
-                    List sets = _tagSets;
+                    List<TagSet> sets = _tagSets;
                     _tagSets = new ArrayList();
                     for (int i = 0; i < sets.size(); i++) {
                         TagSet set = (TagSet) sets.get(i);
@@ -642,8 +657,8 @@ class TransientSessionKeyManager extends SessionKeyManager {
         public long getLastExpirationDate() {
             long last = 0;
             synchronized (_tagSets) {
-                for (Iterator iter = _tagSets.iterator(); iter.hasNext();) {
-                    TagSet set = (TagSet) iter.next();
+                for (Iterator<TagSet> iter = _tagSets.iterator(); iter.hasNext();) {
+                    TagSet set = iter.next();
                     if ( (set.getDate() > last) && (set.getTags().size() > 0) ) 
                         last = set.getDate();
                 }
@@ -663,12 +678,12 @@ class TransientSessionKeyManager extends SessionKeyManager {
     }
 
     static class TagSet {
-        private Set _sessionTags;
+        private Set<SessionTag> _sessionTags;
         private SessionKey _key;
         private long _date;
         private Exception _createdBy;
 
-        public TagSet(Set tags, SessionKey key, long date) {
+        public TagSet(Set<SessionTag> tags, SessionKey key, long date) {
             if (key == null) throw new IllegalArgumentException("Missing key");
             if (tags == null) throw new IllegalArgumentException("Missing tags");
             _sessionTags = tags;
@@ -692,7 +707,7 @@ class TransientSessionKeyManager extends SessionKeyManager {
         }
 
         /** tags still available */
-        public Set getTags() {
+        public Set<SessionTag> getTags() {
             return _sessionTags;
         }
 
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index d2fb6f19d9..1e8e905528 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -57,7 +57,7 @@ public class Router {
     private RouterInfo _routerInfo;
     private long _started;
     private boolean _higherVersionSeen;
-    private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
+    //private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
     private boolean _killVMOnEnd;
     private boolean _isAlive;
     private int _gracefulExitCode;
@@ -144,7 +144,7 @@ public class Router {
         _higherVersionSeen = false;
         _log = _context.logManager().getLog(Router.class);
         _log.info("New router created with config file " + _configFilename);
-        _sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context);
+        //_sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context);
         _killVMOnEnd = true;
         _oomListener = new I2PThread.OOMEventListener() { 
             public void outOfMemory(OutOfMemoryError oom) { 
@@ -261,7 +261,7 @@ public class Router {
         SimpleScheduler.getInstance().addPeriodicEvent(new CoalesceStatsEvent(_context), 20*1000);
         _context.jobQueue().addJob(new UpdateRoutingKeyModifierJob(_context));
         warmupCrypto();
-        _sessionKeyPersistenceHelper.startup();
+        //_sessionKeyPersistenceHelper.startup();
         //_context.adminManager().startup();
         _context.blocklist().startup();
         
@@ -813,7 +813,7 @@ public class Router {
         try { _context.messageRegistry().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message registry", t); }
         try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); }
         try { _context.inNetMessagePool().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the inbound net pool", t); }
-        try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
+        //try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
         RouterContext.listContexts().remove(_context);
         dumpStats();
         finalShutdown(exitCode);
diff --git a/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java b/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java
deleted file mode 100644
index 57db42bb42..0000000000
--- a/router/java/src/net/i2p/router/SessionKeyPersistenceHelper.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package net.i2p.router;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.Writer;
-
-import net.i2p.crypto.PersistentSessionKeyManager;
-import net.i2p.crypto.SessionKeyManager;
-import net.i2p.util.Log;
-
-/**
- * Centralize the sessionKeyManager persistence (rather than leave it to a private
- * job in the startup job)
- *
- */
-public class SessionKeyPersistenceHelper implements Service {
-    private Log _log;
-    private RouterContext _context;
-    private SessionKeyWriterJob _writerJob;
-    private final static long PERSIST_DELAY = 3*60*1000;
-    private final static String PROP_SESSION_KEY_FILE = "router.sessionKeys.location";
-    private final static String DEFAULT_SESSION_KEY_FILE = "sessionKeys.dat";
-    
-    public SessionKeyPersistenceHelper(RouterContext context) {
-        _context = context;
-        _log = _context.logManager().getLog(SessionKeyPersistenceHelper.class);
-        _writerJob = new SessionKeyWriterJob();
-    }
-    
-    public void shutdown() {
-        writeState();
-    }
-    
-    public void restart() {
-        writeState();
-        startup();
-    }
-    
-    private String getKeyFile() {
-        String val = _context.router().getConfigSetting(PROP_SESSION_KEY_FILE);
-        if (val == null)
-            val = DEFAULT_SESSION_KEY_FILE;
-        return val;
-    }
-            
-    public void startup() {
-        SessionKeyManager mgr = _context.sessionKeyManager();
-        if (mgr instanceof PersistentSessionKeyManager) {
-            PersistentSessionKeyManager manager = (PersistentSessionKeyManager)mgr;
-            File f = new File(getKeyFile());
-            if (f.exists()) {
-                FileInputStream fin = null;
-                try {
-                    fin = new FileInputStream(f);
-                    manager.loadState(fin);
-                    int expired = manager.aggressiveExpire();
-                    if (_log.shouldLog(Log.DEBUG))
-                        _log.debug("Session keys loaded [not error] with " + expired 
-                                   + " sets immediately expired");
-                } catch (Throwable t) {
-                    _log.error("Error reading in session key data", t);
-                } finally {
-                    if (fin != null) try { fin.close(); } catch (IOException ioe) {}
-                }
-            }
-            _context.jobQueue().addJob(_writerJob);
-        }
-    }
-    
-    private void writeState() {
-        if (true) return;
-        
-        Object o = _context.sessionKeyManager();
-        if (!(o instanceof PersistentSessionKeyManager)) {
-            _log.error("Unable to persist the session key state - manager is " + o.getClass().getName());
-            return;
-        }
-        PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)o;
-
-        // only need for synchronization is during shutdown()
-        synchronized (mgr) {
-            FileOutputStream fos = null;
-            try {
-                int expired = mgr.aggressiveExpire();
-                if (expired > 0) {
-                    _log.info("Agressive expired " + expired + " tag sets");
-                }
-                fos = new FileOutputStream(getKeyFile());
-                mgr.saveState(fos);
-                fos.flush();
-                _log.debug("Session keys written");
-            } catch (Throwable t) {
-                _log.debug("Error writing session key state", t);
-            } finally { 
-                if (fos != null) try { fos.close(); } catch (IOException ioe) {}
-            }
-        }
-    }
-    
-    public void renderStatusHTML(Writer out) { }
-    
-    private class SessionKeyWriterJob extends JobImpl {
-        public SessionKeyWriterJob() {
-            super(SessionKeyPersistenceHelper.this._context);
-            getTiming().setStartAfter(PERSIST_DELAY);
-        }
-        public String getName() { return "Write Session Keys"; }
-        public void runJob() { 
-            writeState();
-            requeue(PERSIST_DELAY);
-        }
-    }
-}
-- 
GitLab