diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index efe9f4f819..7f13242d3d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -5,7 +5,7 @@ import java.util.HashSet; import java.util.Set; import net.i2p.data.DataHelper; -import net.i2p.data.RouterAddress; +import net.i2p.data.router.RouterAddress; import net.i2p.router.CommSystemFacade; import net.i2p.router.Router; import net.i2p.router.transport.TransportManager; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java index 9fae3ab935..b669f1447c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -29,8 +29,8 @@ import net.i2p.data.Destination; import net.i2p.data.Hash; import net.i2p.data.Lease; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.util.HashDistance; // debug @@ -415,7 +415,9 @@ public class NetDbRenderer { // shouldnt happen buf.append("" + _("Published") + ": in ").append(DataHelper.formatDuration2(0-age)).append("???
\n"); } - buf.append("" + _("Address(es)") + ": "); + buf.append("").append(_("Signing Key")).append(": ") + .append(info.getIdentity().getSigningPublicKey().getType().toString()); + buf.append("
\n" + _("Address(es)") + ": "); String country = _context.commSystem().getCountry(info.getIdentity().getHash()); if(country != null) { buf.append("\"").append(country.toUpperCase(Locale.US)).append('\"'); - + diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index f4cb8ead12..2ae88007ff 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -24,20 +24,15 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.MessageDigest; import java.text.DecimalFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; @@ -633,13 +628,17 @@ public class DataHelper { * Integers are a fixed number of bytes (numBytes), stored as unsigned integers in network byte order. * @param value value to write out, non-negative * @param rawStream stream to write to - * @param numBytes number of bytes to write the number into (padding as necessary) - * @throws DataFormatException if value is negative + * @param numBytes number of bytes to write the number into, 1-8 (padding as necessary) + * @throws DataFormatException if value is negative or if numBytes not 1-8 * @throws IOException if there is an IO error writing to the stream */ public static void writeLong(OutputStream rawStream, int numBytes, long value) throws DataFormatException, IOException { - if (value < 0) throw new DataFormatException("Value is negative (" + value + ")"); + if (numBytes <= 0 || numBytes > 8) + // probably got the args backwards + throw new DataFormatException("Bad byte count " + numBytes); + if (value < 0) + throw new DataFormatException("Value is negative (" + value + ")"); for (int i = (numBytes - 1) * 8; i >= 0; i -= 8) { byte cur = (byte) (value >> i); rawStream.write(cur); @@ -1420,58 +1419,6 @@ public class DataHelper { out.write(data); } - /** - * Sort based on the Hash of the DataStructure. - * Warning - relatively slow. - * WARNING - this sort order must be consistent network-wide, so while the order is arbitrary, - * it cannot be changed. - * Why? Just because it has to be consistent so signing will work. - * How to spec as returning the same type as the param? - * DEPRECATED - Only used by RouterInfo. - * - * @return a new list - */ - public static List sortStructures(Collection dataStructures) { - if (dataStructures == null) return Collections.emptyList(); - - // This used to use Hash.toString(), which is insane, since a change to toString() - // would break the whole network. Now use Hash.toBase64(). - // Note that the Base64 sort order is NOT the same as the raw byte sort order, - // despite what you may read elsewhere. - - //ArrayList rv = new ArrayList(dataStructures.size()); - //TreeMap tm = new TreeMap(); - //for (DataStructure struct : dataStructures) { - // tm.put(struct.calculateHash().toString(), struct); - //} - //for (DataStructure struct : tm.values()) { - // rv.add(struct); - //} - ArrayList rv = new ArrayList(dataStructures); - sortStructureList(rv); - return rv; - } - - /** - * See above. - * DEPRECATED - Only used by RouterInfo. - * - * @since 0.9 - */ - static void sortStructureList(List dataStructures) { - Collections.sort(dataStructures, new DataStructureComparator()); - } - - /** - * See sortStructures() comments. - * @since 0.8.3 - */ - private static class DataStructureComparator implements Comparator, Serializable { - public int compare(DataStructure l, DataStructure r) { - return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64()); - } - } - /** * NOTE: formatDuration2() recommended in most cases for readability */ diff --git a/core/java/src/net/i2p/data/KeysAndCert.java b/core/java/src/net/i2p/data/KeysAndCert.java index b0a8a845b7..e5b56bc868 100644 --- a/core/java/src/net/i2p/data/KeysAndCert.java +++ b/core/java/src/net/i2p/data/KeysAndCert.java @@ -114,6 +114,8 @@ public class KeysAndCert extends DataStructureImpl { _publicKey.writeBytes(out); if (_padding != null) out.write(_padding); + else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES) + throw new DataFormatException("No padding set"); _signingKey.writeTruncatedBytes(out); _certificate.writeBytes(out); } diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java index 012310b9fe..e0bcb5043f 100644 --- a/core/java/src/net/i2p/data/PrivateKeyFile.java +++ b/core/java/src/net/i2p/data/PrivateKeyFile.java @@ -1,11 +1,13 @@ package net.i2p.data; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.InputStream; import java.io.IOException; +import java.io.OutputStream; import java.security.GeneralSecurityException; import java.util.Locale; import java.util.Map; @@ -24,6 +26,7 @@ import net.i2p.crypto.DSAEngine; import net.i2p.crypto.KeyGenerator; import net.i2p.crypto.SigType; import net.i2p.util.RandomSource; +import net.i2p.util.SecureFileOutputStream; /** * This helper class reads and writes files in the @@ -48,11 +51,11 @@ public class PrivateKeyFile { private static final int HASH_EFFORT = VerifiedDestination.MIN_HASHCASH_EFFORT; - private final File file; + protected final File file; private final I2PClient client; private Destination dest; - private PrivateKey privKey; - private SigningPrivateKey signingPrivKey; + protected PrivateKey privKey; + protected SigningPrivateKey signingPrivKey; /** * Create a new PrivateKeyFile, or modify an existing one, with various @@ -224,6 +227,16 @@ public class PrivateKeyFile { */ public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert, PrivateKey pk, SigningPrivateKey spk) { + this(file, pubkey, spubkey, cert, pk, spk, null); + } + + /** + * @param padding null OK, must be non-null if spubkey length < 128 + * @throws IllegalArgumentException on mismatch of spubkey and spk types + * @since 0.9.16 + */ + public PrivateKeyFile(File file, PublicKey pubkey, SigningPublicKey spubkey, Certificate cert, + PrivateKey pk, SigningPrivateKey spk, byte[] padding) { if (spubkey.getType() != spk.getType()) throw new IllegalArgumentException("Signing key type mismatch"); this.file = file; @@ -232,6 +245,8 @@ public class PrivateKeyFile { this.dest.setPublicKey(pubkey); this.dest.setSigningPublicKey(spubkey); this.dest.setCertificate(cert); + if (padding != null) + this.dest.setPadding(padding); this.privKey = pk; this.signingPrivKey = spk; } @@ -241,9 +256,9 @@ public class PrivateKeyFile { */ public Destination createIfAbsent() throws I2PException, IOException, DataFormatException { if(!this.file.exists()) { - FileOutputStream out = null; + OutputStream out = null; try { - out = new FileOutputStream(this.file); + out = new SecureFileOutputStream(this.file); if (this.client != null) this.client.createDestination(out); else @@ -257,7 +272,10 @@ public class PrivateKeyFile { return getDestination(); } - /** Also sets the local privKey and signingPrivKey */ + /** + * If the destination is not set, read it in from the file. + * Also sets the local privKey and signingPrivKey. + */ public Destination getDestination() throws I2PSessionException, IOException, DataFormatException { if (dest == null) { I2PSession s = open(); @@ -408,9 +426,9 @@ public class PrivateKeyFile { } public I2PSession open(Properties opts) throws I2PSessionException, IOException { - FileInputStream in = null; + InputStream in = null; try { - in = new FileInputStream(this.file); + in = new BufferedInputStream(new FileInputStream(this.file)); I2PSession s = this.client.createSession(in, opts); return s; } finally { @@ -424,13 +442,12 @@ public class PrivateKeyFile { * Copied from I2PClientImpl.createDestination() */ public void write() throws IOException, DataFormatException { - FileOutputStream out = null; + OutputStream out = null; try { - out = new FileOutputStream(this.file); + out = new SecureFileOutputStream(this.file); this.dest.writeBytes(out); this.privKey.writeBytes(out); this.signingPrivKey.writeBytes(out); - out.flush(); } finally { if (out != null) { try { out.close(); } catch (IOException ioe) {} diff --git a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java index 37ff20186c..790e376227 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java @@ -17,7 +17,7 @@ import java.util.Set; import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; import net.i2p.data.TunnelId; diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index 8e48a74399..b34912e8d8 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -18,7 +18,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; /** diff --git a/core/java/src/net/i2p/data/RouterAddress.java b/router/java/src/net/i2p/data/router/RouterAddress.java similarity index 98% rename from core/java/src/net/i2p/data/RouterAddress.java rename to router/java/src/net/i2p/data/router/RouterAddress.java index 960e495faf..ca0f94d08a 100644 --- a/core/java/src/net/i2p/data/RouterAddress.java +++ b/router/java/src/net/i2p/data/router/RouterAddress.java @@ -1,4 +1,4 @@ -package net.i2p.data; +package net.i2p.data.router; /* * free (adj.): unencumbered; not under the control of others @@ -17,6 +17,9 @@ import java.util.Date; import java.util.Map; import java.util.Properties; +import net.i2p.data.DataFormatException; +import net.i2p.data.DataHelper; +import net.i2p.data.DataStructureImpl; import net.i2p.util.Addresses; import net.i2p.util.OrderedProperties; @@ -36,6 +39,7 @@ import net.i2p.util.OrderedProperties; * several releases for the change to propagate as it is backwards-incompatible. * Restored as of 0.9.12. * + * @since 0.9.16 moved from net.i2p.data * @author jrandom */ public class RouterAddress extends DataStructureImpl { diff --git a/core/java/src/net/i2p/data/RouterIdentity.java b/router/java/src/net/i2p/data/router/RouterIdentity.java similarity index 89% rename from core/java/src/net/i2p/data/RouterIdentity.java rename to router/java/src/net/i2p/data/router/RouterIdentity.java index 346bb5f8d9..6dc7ca2d75 100644 --- a/core/java/src/net/i2p/data/RouterIdentity.java +++ b/router/java/src/net/i2p/data/router/RouterIdentity.java @@ -1,4 +1,7 @@ -package net.i2p.data; +package net.i2p.data.router; + +import net.i2p.data.Certificate; +import net.i2p.data.KeysAndCert; /* * free (adj.): unencumbered; not under the control of others @@ -16,6 +19,7 @@ package net.i2p.data; * As of 0.9.9 this data structure is immutable after the two keys and the certificate * are set; attempts to change them will throw an IllegalStateException. * + * @since 0.9.16 moved from net.i2p.data * @author jrandom */ public class RouterIdentity extends KeysAndCert { diff --git a/core/java/src/net/i2p/data/RouterInfo.java b/router/java/src/net/i2p/data/router/RouterInfo.java similarity index 96% rename from core/java/src/net/i2p/data/RouterInfo.java rename to router/java/src/net/i2p/data/router/RouterInfo.java index 4900a4e9ee..71a1157fab 100644 --- a/core/java/src/net/i2p/data/RouterInfo.java +++ b/router/java/src/net/i2p/data/router/RouterInfo.java @@ -1,4 +1,4 @@ -package net.i2p.data; +package net.i2p.data.router; /* * free (adj.): unencumbered; not under the control of others @@ -30,6 +30,13 @@ import net.i2p.crypto.DSAEngine; import net.i2p.crypto.SHA1; import net.i2p.crypto.SHA1Hash; import net.i2p.crypto.SHA256Generator; +import net.i2p.data.DatabaseEntry; +import net.i2p.data.DataFormatException; +import net.i2p.data.DataHelper; +import net.i2p.data.Hash; +import net.i2p.data.KeysAndCert; +import net.i2p.data.Signature; +import net.i2p.data.SimpleDataStructure; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.OrderedProperties; @@ -46,6 +53,7 @@ import net.i2p.util.SystemVersion; * To ensure integrity of the RouterInfo, methods that change an element of the * RouterInfo will throw an IllegalStateException after the RouterInfo is signed. * + * @since 0.9.16 moved from net.i2p.data * @author jrandom */ public class RouterInfo extends DatabaseEntry { @@ -189,7 +197,7 @@ public class RouterInfo extends DatabaseEntry { // WARNING this sort algorithm cannot be changed, as it must be consistent // network-wide. The signature is not checked at readin time, but only // later, and the addresses are stored in a Set, not a List. - DataHelper.sortStructureList(_addresses); + SortHelper.sortStructureList(_addresses); } } } @@ -307,7 +315,7 @@ public class RouterInfo extends DatabaseEntry { // WARNING this sort algorithm cannot be changed, as it must be consistent // network-wide. The signature is not checked at readin time, but only // later, and the hashes are stored in a Set, not a List. - peers = (Collection) DataHelper.sortStructures(peers); + peers = (Collection) SortHelper.sortStructures(peers); for (Hash peerHash : peers) { peerHash.writeBytes(out); } @@ -518,17 +526,20 @@ public class RouterInfo extends DatabaseEntry { public void readBytes(InputStream in, boolean verifySig) throws DataFormatException, IOException { if (_signature != null) throw new IllegalStateException(); + _identity = new RouterIdentity(); + _identity.readBytes(in); + // can't set the digest until we know the sig type InputStream din; MessageDigest digest; if (verifySig) { - digest = SHA1.getInstance(); + digest = _identity.getSigningPublicKey().getType().getDigestInstance(); + // TODO any better way? + digest.update(_identity.toByteArray()); din = new DigestInputStream(in, digest); } else { digest = null; din = in; } - _identity = new RouterIdentity(); - _identity.readBytes(din); // avoid thrashing objects //Date when = DataHelper.readDate(in); //if (when == null) @@ -558,7 +569,8 @@ public class RouterInfo extends DatabaseEntry { _signature.readBytes(in); if (verifySig) { - SHA1Hash hash = new SHA1Hash(digest.digest()); + SimpleDataStructure hash = _identity.getSigningPublicKey().getType().getHashInstance(); + hash.setData(digest.digest()); _isValid = DSAEngine.getInstance().verifySignature(_signature, hash, _identity.getSigningPublicKey()); _validated = true; if (!_isValid) { diff --git a/router/java/src/net/i2p/data/router/RouterPrivateKeyFile.java b/router/java/src/net/i2p/data/router/RouterPrivateKeyFile.java new file mode 100644 index 0000000000..db06d48dd8 --- /dev/null +++ b/router/java/src/net/i2p/data/router/RouterPrivateKeyFile.java @@ -0,0 +1,52 @@ +package net.i2p.data.router; + + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; + +import net.i2p.crypto.SigType; +import net.i2p.data.DataFormatException; +import net.i2p.data.PrivateKey; +import net.i2p.data.PrivateKeyFile; +import net.i2p.data.SigningPrivateKey; + +/** + * Same format as super, simply adds a method to + * treat it as a RouterIdentity instead of a Destination. + * + * @since 0.9.16 + */ +public class RouterPrivateKeyFile extends PrivateKeyFile { + + public RouterPrivateKeyFile(File file) { + super(file); + } + + /** + * Read it in from the file. + * Also sets the local privKey and signingPrivKey. + */ + public RouterIdentity getRouterIdentity() throws IOException, DataFormatException { + InputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(this.file)); + RouterIdentity ri = new RouterIdentity(); + ri.readBytes(in); + privKey = new PrivateKey(); + privKey.readBytes(in); + SigType type = ri.getSigningPublicKey().getType(); + if (type == null) + throw new DataFormatException("Unknown sig type"); + signingPrivKey = new SigningPrivateKey(type); + signingPrivKey.readBytes(in); + return ri; + } finally { + if (in != null) { + try { in.close(); } catch (IOException ioe) {} + } + } + } +} diff --git a/router/java/src/net/i2p/data/router/SortHelper.java b/router/java/src/net/i2p/data/router/SortHelper.java new file mode 100644 index 0000000000..0c40fa3eda --- /dev/null +++ b/router/java/src/net/i2p/data/router/SortHelper.java @@ -0,0 +1,79 @@ +package net.i2p.data.router; + +/* + * 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.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import net.i2p.data.DataStructure; + +/** + * The sorting of addresses in RIs + * + * @since 0.9.16 moved from DataHelper + */ +class SortHelper { + + /** + * Sort based on the Hash of the DataStructure. + * Warning - relatively slow. + * WARNING - this sort order must be consistent network-wide, so while the order is arbitrary, + * it cannot be changed. + * Why? Just because it has to be consistent so signing will work. + * How to spec as returning the same type as the param? + * DEPRECATED - Only used by RouterInfo. + * + * @return a new list + */ + public static List sortStructures(Collection dataStructures) { + if (dataStructures == null) return Collections.emptyList(); + + // This used to use Hash.toString(), which is insane, since a change to toString() + // would break the whole network. Now use Hash.toBase64(). + // Note that the Base64 sort order is NOT the same as the raw byte sort order, + // despite what you may read elsewhere. + + //ArrayList rv = new ArrayList(dataStructures.size()); + //TreeMap tm = new TreeMap(); + //for (DataStructure struct : dataStructures) { + // tm.put(struct.calculateHash().toString(), struct); + //} + //for (DataStructure struct : tm.values()) { + // rv.add(struct); + //} + ArrayList rv = new ArrayList(dataStructures); + sortStructureList(rv); + return rv; + } + + /** + * See above. + * DEPRECATED - Only used by RouterInfo. + * + * @since 0.9 + */ + static void sortStructureList(List dataStructures) { + Collections.sort(dataStructures, new DataStructureComparator()); + } + + /** + * See sortStructures() comments. + * @since 0.8.3 + */ + private static class DataStructureComparator implements Comparator, Serializable { + public int compare(DataStructure l, DataStructure r) { + return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64()); + } + } +} diff --git a/router/java/src/net/i2p/data/router/package.html b/router/java/src/net/i2p/data/router/package.html new file mode 100644 index 0000000000..fac87d4981 --- /dev/null +++ b/router/java/src/net/i2p/data/router/package.html @@ -0,0 +1,7 @@ + + +

+Classes formerly in net.i2p.data but moved here as they are only used by the router. +

+ + diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index 093a6fdc5a..a6fe1d2093 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -28,8 +28,8 @@ import java.util.TreeSet; import net.i2p.data.Base64; import net.i2p.data.DataHelper; import net.i2p.data.Hash; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.util.Addresses; import net.i2p.util.ConcurrentHashSet; diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java index 9c7d92338d..59a22eb9ca 100644 --- a/router/java/src/net/i2p/router/CommSystemFacade.java +++ b/router/java/src/net/i2p/router/CommSystemFacade.java @@ -13,7 +13,7 @@ import java.io.Writer; import java.util.Collections; import java.util.List; import net.i2p.data.Hash; -import net.i2p.data.RouterAddress; +import net.i2p.data.router.RouterAddress; /** * Manages the communication subsystem between peers, including connections, diff --git a/router/java/src/net/i2p/router/HandlerJobBuilder.java b/router/java/src/net/i2p/router/HandlerJobBuilder.java index c1c9832cdc..62e2074a5f 100644 --- a/router/java/src/net/i2p/router/HandlerJobBuilder.java +++ b/router/java/src/net/i2p/router/HandlerJobBuilder.java @@ -9,7 +9,7 @@ package net.i2p.router; */ import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.i2np.I2NPMessage; /** diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java index 28296cebba..fb4c2a632c 100644 --- a/router/java/src/net/i2p/router/InNetMessagePool.java +++ b/router/java/src/net/i2p/router/InNetMessagePool.java @@ -14,7 +14,7 @@ import java.util.Date; import java.util.List; import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DeliveryStatusMessage; diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java index ce4992f8bd..2807e8fe7f 100644 --- a/router/java/src/net/i2p/router/KeyManager.java +++ b/router/java/src/net/i2p/router/KeyManager.java @@ -18,6 +18,7 @@ import java.io.OutputStream; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import net.i2p.crypto.SigType; import net.i2p.data.DataFormatException; import net.i2p.data.DataStructure; import net.i2p.data.Destination; @@ -26,6 +27,7 @@ import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; +import net.i2p.router.startup.CreateRouterInfoJob; import net.i2p.util.Log; import net.i2p.util.SecureDirectory; import net.i2p.util.SecureFileOutputStream; @@ -47,10 +49,10 @@ public class KeyManager { public final static String PROP_KEYDIR = "router.keyBackupDir"; public final static String DEFAULT_KEYDIR = "keyBackup"; - private final static String KEYFILE_PRIVATE_ENC = "privateEncryption.key"; - private final static String KEYFILE_PUBLIC_ENC = "publicEncryption.key"; - private final static String KEYFILE_PRIVATE_SIGNING = "privateSigning.key"; - private final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key"; + public final static String KEYFILE_PRIVATE_ENC = "privateEncryption.key"; + public final static String KEYFILE_PUBLIC_ENC = "publicEncryption.key"; + public final static String KEYFILE_PRIVATE_SIGNING = "privateSigning.key"; + public final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key"; public KeyManager(RouterContext context) { _context = context; @@ -151,8 +153,9 @@ public class KeyManager { private void syncKeys(File keyDir) { syncPrivateKey(keyDir); syncPublicKey(keyDir); - syncSigningKey(keyDir); - syncVerificationKey(keyDir); + SigType type = CreateRouterInfoJob.getSigTypeConfig(getContext()); + syncSigningKey(keyDir, type); + syncVerificationKey(keyDir, type); } private void syncPrivateKey(File keyDir) { @@ -181,27 +184,33 @@ public class KeyManager { _publicKey = (PublicKey) readin; } - private void syncSigningKey(File keyDir) { + /** + * @param type the SigType to expect on read-in, ignored on write + */ + private void syncSigningKey(File keyDir, SigType type) { DataStructure ds; File keyFile = new File(keyDir, KEYFILE_PRIVATE_SIGNING); boolean exists = (_signingPrivateKey != null); if (exists) ds = _signingPrivateKey; else - ds = new SigningPrivateKey(); + ds = new SigningPrivateKey(type); DataStructure readin = syncKey(keyFile, ds, exists); if (readin != null && !exists) _signingPrivateKey = (SigningPrivateKey) readin; } - private void syncVerificationKey(File keyDir) { + /** + * @param type the SigType to expect on read-in, ignored on write + */ + private void syncVerificationKey(File keyDir, SigType type) { DataStructure ds; File keyFile = new File(keyDir, KEYFILE_PUBLIC_SIGNING); boolean exists = (_signingPublicKey != null); if (exists) ds = _signingPublicKey; else - ds = new SigningPublicKey(); + ds = new SigningPublicKey(type); DataStructure readin = syncKey(keyFile, ds, exists); if (readin != null && !exists) _signingPublicKey = (SigningPublicKey) readin; diff --git a/router/java/src/net/i2p/router/MultiRouter.java b/router/java/src/net/i2p/router/MultiRouter.java index 5e8cb47608..abcd32e3d0 100644 --- a/router/java/src/net/i2p/router/MultiRouter.java +++ b/router/java/src/net/i2p/router/MultiRouter.java @@ -10,7 +10,7 @@ import java.util.Scanner; import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.Router; /** diff --git a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java index 7fc3c50826..2e4ee3c150 100644 --- a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java @@ -16,7 +16,7 @@ import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.networkdb.reseed.ReseedChecker; /** diff --git a/router/java/src/net/i2p/router/OutNetMessage.java b/router/java/src/net/i2p/router/OutNetMessage.java index 633416640c..54434ac4b7 100644 --- a/router/java/src/net/i2p/router/OutNetMessage.java +++ b/router/java/src/net/i2p/router/OutNetMessage.java @@ -18,7 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.util.CDPQEntry; import net.i2p.util.Log; diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index f6eb8a907e..c199aca2b4 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -29,11 +29,12 @@ import net.i2p.data.Certificate; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SigningPrivateKey; import net.i2p.data.i2np.GarlicMessage; import net.i2p.router.message.GarlicMessageHandler; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; +import net.i2p.router.startup.CreateRouterInfoJob; import net.i2p.router.startup.StartupJob; import net.i2p.router.startup.WorkingDir; import net.i2p.router.tasks.*; @@ -98,10 +99,6 @@ public class Router implements RouterClock.ClockShiftListener { /** this does not put an 'H' in your routerInfo **/ public final static String PROP_HIDDEN_HIDDEN = "router.isHidden"; public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys"; - public final static String PROP_INFO_FILENAME = "router.info.location"; - public final static String PROP_INFO_FILENAME_DEFAULT = "router.info"; - public final static String PROP_KEYS_FILENAME = "router.keys.location"; - public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys"; public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress"; public final static String DNS_CACHE_TIME = "" + (5*60); private static final String EVENTLOG = "eventlog.txt"; @@ -671,20 +668,6 @@ public class Router implements RouterClock.ClockShiftListener { return Boolean.parseBoolean(h); return _context.commSystem().isInBadCountry(); } - - /** - * Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob. - * Not called by periodic RepublishLocalRouterInfoJob. - * We don't want to change the cert on the fly as it changes the router hash. - * RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert. - * There's no reason to ever add a hidden cert? - * @return the certificate for a new RouterInfo - probably a null cert. - */ - public Certificate createCertificate() { - if (_context.getBooleanProperty(PROP_HIDDEN)) - return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null); - return Certificate.NULL_CERT; - } /** * @since 0.9.3 @@ -697,16 +680,18 @@ public class Router implements RouterClock.ClockShiftListener { * Ugly list of files that we need to kill if we are building a new identity * */ - private static final String _rebuildFiles[] = new String[] { "router.info", - "router.keys", - "netDb/my.info", // no longer used - "connectionTag.keys", // never used? - "keyBackup/privateEncryption.key", - "keyBackup/privateSigning.key", - "keyBackup/publicEncryption.key", - "keyBackup/publicSigning.key", - "sessionKeys.dat" // no longer used - }; + private static final String _rebuildFiles[] = new String[] { + CreateRouterInfoJob.INFO_FILENAME, + CreateRouterInfoJob.KEYS_FILENAME, + CreateRouterInfoJob.KEYS2_FILENAME, + "netDb/my.info", // no longer used + "connectionTag.keys", // never used? + KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PRIVATE_ENC, + KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PUBLIC_ENC, + KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PRIVATE_SIGNING, + KeyManager.DEFAULT_KEYDIR + '/' + KeyManager.KEYFILE_PUBLIC_SIGNING, + "sessionKeys.dat" // no longer used + }; public void killKeys() { //new Exception("Clearing identity files").printStackTrace(); diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index 1f8a38af68..20b2fe9b7d 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -10,7 +10,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import net.i2p.I2PAppContext; import net.i2p.app.ClientAppManager; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.internal.InternalClientManager; import net.i2p.router.client.ClientManagerFacadeImpl; import net.i2p.router.crypto.TransientSessionKeyManager; diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java index 805e7bbbc3..275e4d85a4 100644 --- a/router/java/src/net/i2p/router/RouterThrottleImpl.java +++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java @@ -1,7 +1,7 @@ package net.i2p.router; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.peermanager.TunnelHistory; import net.i2p.stat.Rate; import net.i2p.stat.RateAverages; diff --git a/router/java/src/net/i2p/router/dummy/DummyNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/dummy/DummyNetworkDatabaseFacade.java index 11b9419f38..6c99bb90b3 100644 --- a/router/java/src/net/i2p/router/dummy/DummyNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/dummy/DummyNetworkDatabaseFacade.java @@ -17,7 +17,7 @@ import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.Job; import net.i2p.router.NetworkDatabaseFacade; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/message/GarlicConfig.java b/router/java/src/net/i2p/router/message/GarlicConfig.java index 9fe299e0c3..4970a589f9 100644 --- a/router/java/src/net/i2p/router/message/GarlicConfig.java +++ b/router/java/src/net/i2p/router/message/GarlicConfig.java @@ -14,7 +14,7 @@ import java.util.List; import net.i2p.data.Certificate; import net.i2p.data.PublicKey; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DeliveryInstructions; /** diff --git a/router/java/src/net/i2p/router/message/GarlicMessageHandler.java b/router/java/src/net/i2p/router/message/GarlicMessageHandler.java index c44ec2f055..3a762b6fd7 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageHandler.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageHandler.java @@ -9,7 +9,7 @@ package net.i2p.router.message; */ import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.i2np.GarlicMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.HandlerJobBuilder; diff --git a/router/java/src/net/i2p/router/message/HandleGarlicMessageJob.java b/router/java/src/net/i2p/router/message/HandleGarlicMessageJob.java index 9392526b3f..9a22ec6e84 100644 --- a/router/java/src/net/i2p/router/message/HandleGarlicMessageJob.java +++ b/router/java/src/net/i2p/router/message/HandleGarlicMessageJob.java @@ -9,7 +9,7 @@ package net.i2p.router.message; */ import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.i2np.DeliveryInstructions; import net.i2p.data.i2np.GarlicMessage; import net.i2p.data.i2np.I2NPMessage; diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java index 5040606e8d..7da54172ce 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java @@ -18,7 +18,7 @@ import net.i2p.data.Lease; import net.i2p.data.LeaseSet; import net.i2p.data.Payload; import net.i2p.data.PublicKey; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; import net.i2p.data.i2cp.MessageId; diff --git a/router/java/src/net/i2p/router/message/SendMessageDirectJob.java b/router/java/src/net/i2p/router/message/SendMessageDirectJob.java index 6d0cfdbcf2..cc7a337cc5 100644 --- a/router/java/src/net/i2p/router/message/SendMessageDirectJob.java +++ b/router/java/src/net/i2p/router/message/SendMessageDirectJob.java @@ -11,7 +11,7 @@ package net.i2p.router.message; import java.util.Date; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.Job; import net.i2p.router.JobImpl; diff --git a/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java b/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java index 685e18512c..9931444aaf 100644 --- a/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/HandleDatabaseLookupMessageJob.java @@ -14,8 +14,8 @@ import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterIdentity; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterIdentity; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SessionKey; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DatabaseLookupMessage; diff --git a/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java b/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java index f6a29355b7..8b235260e3 100644 --- a/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java +++ b/router/java/src/net/i2p/router/networkdb/PublishLocalRouterInfoJob.java @@ -12,7 +12,7 @@ import java.util.Date; import java.util.Properties; import net.i2p.data.DataFormatException; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SigningPrivateKey; import net.i2p.router.JobImpl; import net.i2p.router.Router; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/ExpireRoutersJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/ExpireRoutersJob.java index c2ea790a5a..b52df8e179 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/ExpireRoutersJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/ExpireRoutersJob.java @@ -12,7 +12,7 @@ import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.CommSystemFacade; import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java index 8f3a193a5a..0de6c6504f 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlyLookupMatchJob.java @@ -2,7 +2,7 @@ package net.i2p.router.networkdb.kademlia; import net.i2p.data.DatabaseEntry; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseLookupMessageHandler.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseLookupMessageHandler.java index 8ef121d060..a07ac8c708 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseLookupMessageHandler.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseLookupMessageHandler.java @@ -9,7 +9,7 @@ package net.i2p.router.networkdb.kademlia; */ import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.HandlerJobBuilder; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseStoreMessageHandler.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseStoreMessageHandler.java index e4c6ce71af..99d8c62658 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseStoreMessageHandler.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillDatabaseStoreMessageHandler.java @@ -9,7 +9,7 @@ package net.i2p.router.networkdb.kademlia; */ import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; +import net.i2p.data.router.RouterIdentity; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.HandlerJobBuilder; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java index 99c4beda29..de634943cb 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillMonitorJob.java @@ -3,8 +3,8 @@ package net.i2p.router.networkdb.kademlia; import java.util.List; import net.i2p.data.Hash; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; import net.i2p.router.JobImpl; import net.i2p.router.Router; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java index 24a7bc40a1..22d51249a2 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -8,7 +8,7 @@ import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseStoreMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java index fdf47bf3cc..6870edcd58 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java @@ -18,8 +18,8 @@ import java.util.Set; import java.util.TreeSet; import net.i2p.data.Hash; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; import net.i2p.kademlia.KBucketSet; import net.i2p.kademlia.SelectionCollector; import net.i2p.kademlia.XORComparator; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index f66b50020a..85d0bc974d 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -8,7 +8,7 @@ import net.i2p.data.Certificate; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java index 0d03d7d4fe..eceb4b576e 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java @@ -11,8 +11,8 @@ package net.i2p.router.networkdb.kademlia; import java.util.Set; import net.i2p.data.Hash; -import net.i2p.data.RouterIdentity; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterIdentity; +import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.DatabaseLookupMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java index f623022ca7..57d1ee57bc 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java @@ -14,9 +14,9 @@ import java.util.Date; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterIdentity; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterIdentity; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.DeliveryStatusMessage; import net.i2p.router.JobImpl; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HarvesterJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HarvesterJob.java index a69a2bc906..6bd687185c 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/HarvesterJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/HarvesterJob.java @@ -7,7 +7,7 @@ import java.util.Set; import java.util.TreeMap; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.router.JobImpl; import net.i2p.router.OutNetMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/IterativeLookupJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/IterativeLookupJob.java index 13d7636887..ac283109ca 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/IterativeLookupJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/IterativeLookupJob.java @@ -1,7 +1,7 @@ package net.i2p.router.networkdb.kademlia; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.util.Log; import net.i2p.router.JobImpl; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java index 7a2fa77709..023b6a8731 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java @@ -13,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.Base64; import net.i2p.data.DataHelper; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.kademlia.KBucketSet; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java index b4d108d024..ba52e5d611 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java @@ -23,8 +23,8 @@ import net.i2p.data.DatabaseEntry; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.kademlia.KBucketSet; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java index 15ae87a8bc..ff9d3d5011 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java @@ -8,7 +8,7 @@ import net.i2p.crypto.TagSetHandle; import net.i2p.data.Certificate; import net.i2p.data.Hash; import net.i2p.data.PublicKey; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; import net.i2p.data.i2np.DeliveryInstructions; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/PeerSelector.java index f73eb00fef..4eb23e13cb 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/PeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/PeerSelector.java @@ -16,7 +16,7 @@ import java.util.Set; import java.util.TreeMap; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.kademlia.KBucketSet; import net.i2p.kademlia.SelectionCollector; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java index 27435d5b56..2a7713cffd 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java @@ -29,7 +29,7 @@ import net.i2p.data.Base64; import net.i2p.data.DatabaseEntry; import net.i2p.data.DataFormatException; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.JobImpl; import net.i2p.router.Router; import net.i2p.router.RouterContext; @@ -524,6 +524,11 @@ class PersistentDataStore extends TransientDataStore { if (_log.shouldLog(Log.INFO)) _log.info("Unable to read the router reference in " + _routerFile.getName(), ioe); corrupt = true; + } catch (Exception e) { + // key certificate problems, etc., don't let one bad RI kill the whole thing + if (_log.shouldLog(Log.INFO)) + _log.info("Unable to read the router reference in " + _routerFile.getName(), e); + corrupt = true; } finally { if (fis != null) try { fis.close(); } catch (IOException ioe) {} } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/RefreshRoutersJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/RefreshRoutersJob.java index 852a5c7920..20dd2a0754 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/RefreshRoutersJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/RefreshRoutersJob.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.Set; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; import net.i2p.util.Log; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java index 54a9383196..9f2313f8eb 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java @@ -17,7 +17,7 @@ import net.i2p.data.DatabaseEntry; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DatabaseLookupMessage; import net.i2p.data.i2np.DatabaseSearchReplyMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchMessageSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchMessageSelector.java index 3d756529d8..30e8e4b18a 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchMessageSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchMessageSelector.java @@ -3,7 +3,7 @@ package net.i2p.router.networkdb.kademlia; import java.util.concurrent.atomic.AtomicInteger; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchReplyJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchReplyJob.java index 8d8e5f19d9..a8354b096f 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchReplyJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchReplyJob.java @@ -2,7 +2,7 @@ package net.i2p.router.networkdb.kademlia; import net.i2p.data.Hash; import net.i2p.data.i2np.DatabaseSearchReplyMessage; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; import net.i2p.util.Log; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java index 22602b497a..a67ae2fd83 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SearchUpdateReplyFoundJob.java @@ -5,7 +5,7 @@ import java.util.Date; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java index 711510fb4d..62a878d6de 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java @@ -1,7 +1,7 @@ package net.i2p.router.networkdb.kademlia; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StartExplorersJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StartExplorersJob.java index cced2f5466..7938ab072c 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StartExplorersJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StartExplorersJob.java @@ -12,7 +12,7 @@ import java.util.HashSet; import java.util.Set; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.JobImpl; import net.i2p.router.Router; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index 311f2ba8f1..81bef6950a 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -18,7 +18,7 @@ import net.i2p.data.DatabaseEntry; import net.i2p.data.DataFormatException; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreMessageSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreMessageSelector.java index 6901f0afa6..352c19cd71 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreMessageSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreMessageSelector.java @@ -1,7 +1,7 @@ package net.i2p.router.networkdb.kademlia; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DeliveryStatusMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.MessageSelector; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java index 2a7318d25f..11603efb98 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/TransientDataStore.java @@ -18,7 +18,7 @@ import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.RouterContext; import net.i2p.util.Log; diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index ef7b1de349..d2de16d9ba 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -19,7 +19,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.router.PeerSelectionCriteria; import net.i2p.router.Router; import net.i2p.router.RouterContext; diff --git a/router/java/src/net/i2p/router/peermanager/PeerTestJob.java b/router/java/src/net/i2p/router/peermanager/PeerTestJob.java index 24176a2088..466c63ec19 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerTestJob.java +++ b/router/java/src/net/i2p/router/peermanager/PeerTestJob.java @@ -5,7 +5,7 @@ import java.util.List; import java.util.Set; import net.i2p.data.Hash; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.DeliveryStatusMessage; diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index a224f576ac..7e89cab255 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -19,8 +19,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import net.i2p.crypto.SHA256Generator; import net.i2p.data.Hash; -import net.i2p.data.RouterAddress; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterAddress; +import net.i2p.data.router.RouterInfo; import net.i2p.router.NetworkDatabaseFacade; import net.i2p.router.RouterContext; import net.i2p.router.tunnel.pool.TunnelPeerSelector; diff --git a/router/java/src/net/i2p/router/startup/BootCommSystemJob.java b/router/java/src/net/i2p/router/startup/BootCommSystemJob.java index 3af4164b5e..305869bada 100644 --- a/router/java/src/net/i2p/router/startup/BootCommSystemJob.java +++ b/router/java/src/net/i2p/router/startup/BootCommSystemJob.java @@ -16,7 +16,7 @@ import net.i2p.router.tasks.ReadConfigJob; import net.i2p.util.Log; /** This actually boots almost everything */ -public class BootCommSystemJob extends JobImpl { +class BootCommSystemJob extends JobImpl { private Log _log; public static final String PROP_USE_TRUSTED_LINKS = "router.trustedLinks"; diff --git a/router/java/src/net/i2p/router/startup/BootNetworkDbJob.java b/router/java/src/net/i2p/router/startup/BootNetworkDbJob.java index bf8d36a772..e512f9ea38 100644 --- a/router/java/src/net/i2p/router/startup/BootNetworkDbJob.java +++ b/router/java/src/net/i2p/router/startup/BootNetworkDbJob.java @@ -12,7 +12,7 @@ import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; /** start up the network database */ -public class BootNetworkDbJob extends JobImpl { +class BootNetworkDbJob extends JobImpl { public BootNetworkDbJob(RouterContext ctx) { super(ctx); diff --git a/router/java/src/net/i2p/router/startup/BootPeerManagerJob.java b/router/java/src/net/i2p/router/startup/BootPeerManagerJob.java index 7ac5254f0e..33f4010236 100644 --- a/router/java/src/net/i2p/router/startup/BootPeerManagerJob.java +++ b/router/java/src/net/i2p/router/startup/BootPeerManagerJob.java @@ -12,7 +12,7 @@ import net.i2p.router.JobImpl; import net.i2p.router.RouterContext; /** start up the peer manager */ -public class BootPeerManagerJob extends JobImpl { +class BootPeerManagerJob extends JobImpl { public BootPeerManagerJob(RouterContext ctx) { super(ctx); diff --git a/router/java/src/net/i2p/router/startup/BuildTrustedLinksJob.java b/router/java/src/net/i2p/router/startup/BuildTrustedLinksJob.java index 3b88a2d9cd..566204068b 100644 --- a/router/java/src/net/i2p/router/startup/BuildTrustedLinksJob.java +++ b/router/java/src/net/i2p/router/startup/BuildTrustedLinksJob.java @@ -15,7 +15,7 @@ import net.i2p.router.RouterContext; /** * For future restricted routes. Does nothing now. */ -public class BuildTrustedLinksJob extends JobImpl { +class BuildTrustedLinksJob extends JobImpl { private final Job _next; public BuildTrustedLinksJob(RouterContext context, Job next) { diff --git a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java index 498cbe6658..a343939f98 100644 --- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java @@ -12,16 +12,22 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.security.GeneralSecurityException; import java.util.Properties; +import net.i2p.crypto.SigType; import net.i2p.data.Certificate; import net.i2p.data.DataFormatException; +import net.i2p.data.DataHelper; +import net.i2p.data.KeyCertificate; import net.i2p.data.PrivateKey; +import net.i2p.data.PrivateKeyFile; import net.i2p.data.PublicKey; -import net.i2p.data.RouterIdentity; -import net.i2p.data.RouterInfo; +import net.i2p.data.router.RouterIdentity; +import net.i2p.data.router.RouterInfo; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; +import net.i2p.data.SimpleDataStructure; import net.i2p.router.Job; import net.i2p.router.JobImpl; import net.i2p.router.Router; @@ -40,7 +46,14 @@ public class CreateRouterInfoJob extends JobImpl { private final Log _log; private final Job _next; - public CreateRouterInfoJob(RouterContext ctx, Job next) { + public static final String INFO_FILENAME = "router.info"; + public static final String KEYS_FILENAME = "router.keys"; + public static final String KEYS2_FILENAME = "router.keys.dat"; + private static final String PROP_ROUTER_SIGTYPE = "router.sigType"; + /** TODO when changing, check isAvailable() and fallback to DSA_SHA1 */ + private static final SigType DEFAULT_SIGTYPE = SigType.DSA_SHA1; + + CreateRouterInfoJob(RouterContext ctx, Job next) { super(ctx); _next = next; _log = ctx.logManager().getLog(CreateRouterInfoJob.class); @@ -59,9 +72,13 @@ public class CreateRouterInfoJob extends JobImpl { /** * Writes 6 files: router.info (standard RI format), - * router,keys, and 4 individual key files under keyBackup/ + * router.keys2, and 4 individual key files under keyBackup/ * - * router.keys file format: Note that this is NOT the + * router.keys2 file format: This is the + * same "eepPriv.dat" format used by the client code, + * as documented in PrivateKeyFile. + * + * Old router.keys file format: Note that this is NOT the * same "eepPriv.dat" format used by the client code. *
      *   - Private key (256 bytes)
@@ -74,9 +91,9 @@ public class CreateRouterInfoJob extends JobImpl {
      *  Caller must hold Router.routerInfoFileLock.
      */
     RouterInfo createRouterInfo() {
+        SigType type = getSigTypeConfig(getContext());
         RouterInfo info = new RouterInfo();
         OutputStream fos1 = null;
-        OutputStream fos2 = null;
         try {
             info.setAddresses(getContext().commSystem().createAddresses());
             Properties stats = getContext().statPublisher().publishStatistics();
@@ -86,21 +103,26 @@ public class CreateRouterInfoJob extends JobImpl {
             // not necessary, in constructor
             //info.setPeers(new HashSet());
             info.setPublished(getCurrentPublishDate(getContext()));
-            RouterIdentity ident = new RouterIdentity();
-            Certificate cert = getContext().router().createCertificate();
-            ident.setCertificate(cert);
-            PublicKey pubkey = null;
-            PrivateKey privkey = null;
-            SigningPublicKey signingPubKey = null;
-            SigningPrivateKey signingPrivKey = null;
             Object keypair[] = getContext().keyGenerator().generatePKIKeypair();
-            pubkey = (PublicKey)keypair[0];
-            privkey = (PrivateKey)keypair[1];
-            Object signingKeypair[] = getContext().keyGenerator().generateSigningKeypair();
-            signingPubKey = (SigningPublicKey)signingKeypair[0];
-            signingPrivKey = (SigningPrivateKey)signingKeypair[1];
+            PublicKey pubkey = (PublicKey)keypair[0];
+            PrivateKey privkey = (PrivateKey)keypair[1];
+            SimpleDataStructure signingKeypair[] = getContext().keyGenerator().generateSigningKeys(type);
+            SigningPublicKey signingPubKey = (SigningPublicKey)signingKeypair[0];
+            SigningPrivateKey signingPrivKey = (SigningPrivateKey)signingKeypair[1];
+            RouterIdentity ident = new RouterIdentity();
+            Certificate cert = createCertificate(getContext(), signingPubKey);
+            ident.setCertificate(cert);
             ident.setPublicKey(pubkey);
             ident.setSigningPublicKey(signingPubKey);
+            byte[] padding;
+            int padLen = SigningPublicKey.KEYSIZE_BYTES - signingPubKey.length();
+            if (padLen > 0) {
+                padding = new byte[padLen];
+                getContext().random().nextBytes(padding);
+                ident.setPadding(padding);
+            } else {
+                padding = null;
+            }
             info.setIdentity(ident);
             
             info.sign(signingPrivKey);
@@ -108,34 +130,51 @@ public class CreateRouterInfoJob extends JobImpl {
             if (!info.isValid())
                 throw new DataFormatException("RouterInfo we just built is invalid: " + info);
             
-            String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
-            File ifile = new File(getContext().getRouterDir(), infoFilename);
+            // remove router.keys
+            (new File(getContext().getRouterDir(), KEYS_FILENAME)).delete();
+
+            // write router.info
+            File ifile = new File(getContext().getRouterDir(), INFO_FILENAME);
             fos1 = new BufferedOutputStream(new SecureFileOutputStream(ifile));
             info.writeBytes(fos1);
             
-            String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
-            File kfile = new File(getContext().getRouterDir(), keyFilename);
-            fos2 = new BufferedOutputStream(new SecureFileOutputStream(kfile));
-            privkey.writeBytes(fos2);
-            signingPrivKey.writeBytes(fos2);
-            pubkey.writeBytes(fos2);
-            signingPubKey.writeBytes(fos2);
+            // write router.keys.dat
+            File kfile = new File(getContext().getRouterDir(), KEYS2_FILENAME);
+            PrivateKeyFile pkf = new PrivateKeyFile(kfile, pubkey, signingPubKey, cert,
+                                                    privkey, signingPrivKey, padding);
+            pkf.write();
             
             getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
             
-            _log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
+            if (_log.shouldLog(Log.INFO))
+                _log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]");
             getContext().router().eventLog().addEvent(EventLog.REKEYED, ident.calculateHash().toBase64());
+        } catch (GeneralSecurityException gse) {
+            _log.log(Log.CRIT, "Error building the new router information", gse);
         } catch (DataFormatException dfe) {
             _log.log(Log.CRIT, "Error building the new router information", dfe);
         } catch (IOException ioe) {
             _log.log(Log.CRIT, "Error writing out the new router information", ioe);
         } finally {
             if (fos1 != null) try { fos1.close(); } catch (IOException ioe) {}
-            if (fos2 != null) try { fos2.close(); } catch (IOException ioe) {}
         }
         return info;
     }
     
+    /**
+     *  The configured SigType to expect on read-in
+     *  @since 0.9.16
+     */
+    public static SigType getSigTypeConfig(RouterContext ctx) {
+        SigType cstype = CreateRouterInfoJob.DEFAULT_SIGTYPE;
+        String sstype = ctx.getProperty(PROP_ROUTER_SIGTYPE);
+        if (sstype != null) {
+            SigType ntype = SigType.parseSigType(sstype);
+            if (ntype != null && ntype.isAvailable())
+                cstype = ntype;
+        }
+        return cstype;
+    }
     
     /**
      * We probably don't want to expose the exact time at which a router published its info.
@@ -146,4 +185,22 @@ public class CreateRouterInfoJob extends JobImpl {
         //_log.info("Setting published date to /now/");
         return context.clock().now();
     }
+
+    /**
+     *  Only called at startup via LoadRouterInfoJob and RebuildRouterInfoJob.
+     *  Not called by periodic RepublishLocalRouterInfoJob.
+     *  We don't want to change the cert on the fly as it changes the router hash.
+     *  RouterInfo.isHidden() checks the capability, but RouterIdentity.isHidden() checks the cert.
+     *  There's no reason to ever add a hidden cert?
+     *
+     *  @return the certificate for a new RouterInfo - probably a null cert.
+     *  @since 0.9.16 moved from Router
+     */
+    static Certificate createCertificate(RouterContext ctx, SigningPublicKey spk) {
+        if (spk.getType() != SigType.DSA_SHA1)
+            return new KeyCertificate(spk);
+        if (ctx.getBooleanProperty(Router.PROP_HIDDEN))
+            return new Certificate(Certificate.CERTIFICATE_TYPE_HIDDEN, null);
+        return Certificate.NULL_CERT;
+    }
 }
diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
index 9a560da5f4..51ca135ab7 100644
--- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
@@ -15,18 +15,27 @@ import java.io.InputStream;
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import net.i2p.crypto.SigType;
+import net.i2p.data.Certificate;
 import net.i2p.data.DataFormatException;
+import net.i2p.data.DataHelper;
 import net.i2p.data.PrivateKey;
 import net.i2p.data.PublicKey;
-import net.i2p.data.RouterInfo;
 import net.i2p.data.SigningPrivateKey;
 import net.i2p.data.SigningPublicKey;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
+import net.i2p.data.router.RouterPrivateKeyFile;
 import net.i2p.router.JobImpl;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.util.Log;
 
-public class LoadRouterInfoJob extends JobImpl {
+/**
+ *  Run once or twice at startup by StartupJob,
+ *  and then runs BootCommSystemJob
+ */
+class LoadRouterInfoJob extends JobImpl {
     private final Log _log;
     private RouterInfo _us;
     private static final AtomicBoolean _keyLengthChecked = new AtomicBoolean();
@@ -45,6 +54,7 @@ public class LoadRouterInfoJob extends JobImpl {
         if (_us == null) {
             RebuildRouterInfoJob r = new RebuildRouterInfoJob(getContext());
             r.rebuildRouterInfo(false);
+            // run a second time
             getContext().jobQueue().addJob(this);
             return;
         } else {
@@ -54,18 +64,21 @@ public class LoadRouterInfoJob extends JobImpl {
         }
     }
     
+    /**
+     *  Loads router.info and router.keys2 or router.keys.
+     *
+     *  See CreateRouterInfoJob for file formats
+     */
     private void loadRouterInfo() {
-        String routerInfoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
         RouterInfo info = null;
-        String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
-        
-        File rif = new File(getContext().getRouterDir(), routerInfoFile);
+        File rif = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
         boolean infoExists = rif.exists();
-        File rkf = new File(getContext().getRouterDir(), keyFilename);
+        File rkf = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
         boolean keysExist = rkf.exists();
+        File rkf2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
+        boolean keys2Exist = rkf2.exists();
         
         InputStream fis1 = null;
-        InputStream fis2 = null;
         try {
             // if we have a routerinfo but no keys, things go bad in a hurry:
             // CRIT   ...rkdb.PublishLocalRouterInfoJob: Internal error - signing private key not known?  rescheduling publish for 30s
@@ -73,7 +86,7 @@ public class LoadRouterInfoJob extends JobImpl {
             // CRIT   ...sport.udp.EstablishmentManager: Error in the establisher java.lang.NullPointerException
             // at net.i2p.router.transport.udp.PacketBuilder.buildSessionConfirmedPacket(PacketBuilder.java:574)
             // so pretend the RI isn't there if there is no keyfile
-            if (infoExists && keysExist) {
+            if (infoExists && (keys2Exist || keysExist)) {
                 fis1 = new BufferedInputStream(new FileInputStream(rif));
                 info = new RouterInfo();
                 info.readBytes(fis1);
@@ -85,29 +98,32 @@ public class LoadRouterInfoJob extends JobImpl {
                 _us = info;
             }
             
-            if (keysExist) {
-                fis2 = new BufferedInputStream(new FileInputStream(rkf));
-                PrivateKey privkey = new PrivateKey();
-                privkey.readBytes(fis2);
-                if (shouldRebuild(privkey)) {
+            if (keys2Exist || keysExist) {
+                KeyData kd = readKeyData(rkf, rkf2);
+                PublicKey pubkey = kd.routerIdentity.getPublicKey();
+                SigningPublicKey signingPubKey = kd.routerIdentity.getSigningPublicKey();
+                PrivateKey privkey = kd.privateKey;
+                SigningPrivateKey signingPrivKey = kd.signingPrivateKey;
+                SigType stype = signingPubKey.getType();
+
+                // check if the sigtype config changed
+                SigType cstype = CreateRouterInfoJob.getSigTypeConfig(getContext());
+                boolean sigTypeChanged = stype != cstype;
+
+                if (sigTypeChanged || shouldRebuild(privkey)) {
+                    if (sigTypeChanged)
+                        _log.logAlways(Log.WARN, "Rebuilding RouterInfo with new signature type " + cstype);
                     _us = null;
                     // windows... close before deleting
                     if (fis1 != null) {
                         try { fis1.close(); } catch (IOException ioe) {}
                         fis1 = null;
                     }
-                    try { fis2.close(); } catch (IOException ioe) {}
-                    fis2 = null;
                     rif.delete();
                     rkf.delete();
+                    rkf2.delete();
                     return;
                 }
-                SigningPrivateKey signingPrivKey = new SigningPrivateKey();
-                signingPrivKey.readBytes(fis2);
-                PublicKey pubkey = new PublicKey();
-                pubkey.readBytes(fis2);
-                SigningPublicKey signingPubKey = new SigningPublicKey();
-                signingPubKey.readBytes(fis2);
                 
                 getContext().keyManager().setKeys(pubkey, privkey, signingPubKey, signingPrivKey);
             }
@@ -119,12 +135,9 @@ public class LoadRouterInfoJob extends JobImpl {
                 try { fis1.close(); } catch (IOException ioe2) {}
                 fis1 = null;
             }
-            if (fis2 != null) {
-                try { fis2.close(); } catch (IOException ioe2) {}
-                fis2 = null;
-            }
             rif.delete();
             rkf.delete();
+            rkf2.delete();
         } catch (DataFormatException dfe) {
             _log.log(Log.CRIT, "Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe);
             _us = null;
@@ -133,15 +146,11 @@ public class LoadRouterInfoJob extends JobImpl {
                 try { fis1.close(); } catch (IOException ioe) {}
                 fis1 = null;
             }
-            if (fis2 != null) {
-                try { fis2.close(); } catch (IOException ioe) {}
-                fis2 = null;
-            }
             rif.delete();
             rkf.delete();
+            rkf2.delete();
         } finally {
             if (fis1 != null) try { fis1.close(); } catch (IOException ioe) {}
-            if (fis2 != null) try { fis2.close(); } catch (IOException ioe) {}
         }
     }
 
@@ -174,4 +183,55 @@ public class LoadRouterInfoJob extends JobImpl {
             _log.logAlways(Log.WARN, "Rebuilding RouterInfo with faster key");
         return uselong != haslong;
     }
+
+    /** @since 0.9.16 */
+    public static class KeyData {
+        public final RouterIdentity routerIdentity;
+        public final PrivateKey privateKey;
+        public final SigningPrivateKey signingPrivateKey;
+
+        public KeyData(RouterIdentity ri, PrivateKey pk, SigningPrivateKey spk) {
+            routerIdentity = ri;
+            privateKey = pk;
+            signingPrivateKey = spk;
+        }
+    }
+
+    /**
+     *  @param rkf1 in router.keys format, tried second
+     *  @param rkf2 in eepPriv.dat format, tried first
+     *  @return non-null, throws IOE if neither exisits
+     *  @since 0.9.16
+     */
+    public static KeyData readKeyData(File rkf1, File rkf2) throws DataFormatException, IOException {
+        RouterIdentity ri;
+        PrivateKey privkey;
+        SigningPrivateKey signingPrivKey;
+        if (rkf2.exists()) {
+            RouterPrivateKeyFile pkf = new RouterPrivateKeyFile(rkf2);
+            ri = pkf.getRouterIdentity();
+            privkey = pkf.getPrivKey();
+            signingPrivKey = pkf.getSigningPrivKey();
+        } else {
+            InputStream fis = null;
+            try {
+                fis = new BufferedInputStream(new FileInputStream(rkf1));
+                privkey = new PrivateKey();
+                privkey.readBytes(fis);
+                signingPrivKey = new SigningPrivateKey();
+                signingPrivKey.readBytes(fis);
+                PublicKey pubkey = new PublicKey();
+                pubkey.readBytes(fis);
+                SigningPublicKey signingPubKey = new SigningPublicKey();
+                signingPubKey.readBytes(fis);
+                ri = new RouterIdentity();
+                ri.setPublicKey(pubkey);
+                ri.setSigningPublicKey(signingPubKey);
+                ri.setCertificate(Certificate.NULL_CERT);
+            } finally {
+                if (fis != null) try { fis.close(); } catch (IOException ioe) {}
+            }
+        }
+        return new KeyData(ri, privkey, signingPrivKey);
+    }
 }
diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
index b611114d06..ef0826cf5f 100644
--- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
@@ -9,22 +9,24 @@ package net.i2p.router.startup;
  */
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Properties;
 
+import net.i2p.crypto.SigType;
 import net.i2p.data.Certificate;
 import net.i2p.data.DataFormatException;
+import net.i2p.data.DataHelper;
 import net.i2p.data.PrivateKey;
 import net.i2p.data.PublicKey;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SigningPrivateKey;
 import net.i2p.data.SigningPublicKey;
 import net.i2p.router.JobImpl;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
+import net.i2p.router.startup.LoadRouterInfoJob.KeyData;
 import net.i2p.util.Log;
 import net.i2p.util.SecureFileOutputStream;
 
@@ -44,7 +46,7 @@ import net.i2p.util.SecureFileOutputStream;
  * router.info.rebuild file is deleted
  *
  */
-public class RebuildRouterInfoJob extends JobImpl {
+class RebuildRouterInfoJob extends JobImpl {
     private final Log _log;
     
     private final static long REBUILD_DELAY = 45*1000; // every 30 seconds
@@ -57,11 +59,11 @@ public class RebuildRouterInfoJob extends JobImpl {
     public String getName() { return "Rebuild Router Info"; }
     
     public void runJob() {
+        throw new UnsupportedOperationException();
+/****
         _log.debug("Testing to rebuild router info");
-        String infoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
-        File info = new File(getContext().getRouterDir(), infoFile);
-        String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
-        File keyFile = new File(getContext().getRouterDir(), keyFilename);
+        File info = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
+        File keyFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
         
         if (!info.exists() || !keyFile.exists()) {
             _log.info("Router info file [" + info.getAbsolutePath() + "] or private key file [" + keyFile.getAbsolutePath() + "] deleted, rebuilding");
@@ -71,51 +73,37 @@ public class RebuildRouterInfoJob extends JobImpl {
         }
         getTiming().setStartAfter(getContext().clock().now() + REBUILD_DELAY);
         getContext().jobQueue().addJob(this);
+****/
     }
     
     void rebuildRouterInfo() {
         rebuildRouterInfo(true);
     }
 
+    /**
+     *  @param alreadyRunning unused
+     */
     void rebuildRouterInfo(boolean alreadyRunning) {
         _log.debug("Rebuilding the new router info");
         RouterInfo info = null;
-        String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
-        File infoFile = new File(getContext().getRouterDir(), infoFilename);
-        String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT);
-        File keyFile = new File(getContext().getRouterDir(), keyFilename);
+        File infoFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
+        File keyFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS_FILENAME);
+        File keyFile2 = new File(getContext().getRouterDir(), CreateRouterInfoJob.KEYS2_FILENAME);
         
-        if (keyFile.exists()) {
+        if (keyFile2.exists() || keyFile.exists()) {
             // ok, no need to rebuild a brand new identity, just update what we can
             RouterInfo oldinfo = getContext().router().getRouterInfo();
             if (oldinfo == null) {
-                info = new RouterInfo();
-                FileInputStream fis = null;
                 try {
-                    fis = new FileInputStream(keyFile);
-                    PrivateKey privkey = new PrivateKey();
-                    privkey.readBytes(fis);
-                    SigningPrivateKey signingPrivKey = new SigningPrivateKey();
-                    signingPrivKey.readBytes(fis);
-                    PublicKey pubkey = new PublicKey();
-                    pubkey.readBytes(fis);
-                    SigningPublicKey signingPubKey = new SigningPublicKey();
-                    signingPubKey.readBytes(fis);
-                    RouterIdentity ident = new RouterIdentity();
-                    Certificate cert = getContext().router().createCertificate();
-                    ident.setCertificate(cert);
-                    ident.setPublicKey(pubkey);
-                    ident.setSigningPublicKey(signingPubKey);
-                    info.setIdentity(ident);
+                    KeyData kd = LoadRouterInfoJob.readKeyData(keyFile, keyFile2);
+                    info = new RouterInfo();
+                    info.setIdentity(kd.routerIdentity);
                 } catch (Exception e) {
                     _log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e);
-                    if (fis != null) try { fis.close(); } catch (IOException ioe) {}
-                    fis = null;
                     keyFile.delete();
+                    keyFile2.delete();
                     rebuildRouterInfo(alreadyRunning);
                     return;
-                } finally {
-                    if (fis != null) try { fis.close(); } catch (IOException ioe) {}
                 }
             } else {
                 // Make a new RI from the old identity, or else info.setAddresses() will throw an ISE
@@ -160,12 +148,14 @@ public class RebuildRouterInfoJob extends JobImpl {
             _log.warn("Private key file " + keyFile.getAbsolutePath() + " deleted!  Rebuilding a brand new router identity!");
             // this proc writes the keys and info to the file as well as builds the latest and greatest info
             CreateRouterInfoJob j = new CreateRouterInfoJob(getContext(), null);
-            info = j.createRouterInfo();
+            synchronized (getContext().router().routerInfoFileLock) {
+                info = j.createRouterInfo();
+            }
         }
         
         //MessageHistory.initialize();
         getContext().router().setRouterInfo(info);
-        _log.info("Router info rebuilt and stored at " + infoFilename + " [" + info + "]");
+        _log.info("Router info rebuilt and stored at " + infoFile + " [" + info + "]");
     }
     
 }
diff --git a/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java b/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java
index 50d840d432..672bf702aa 100644
--- a/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java
+++ b/router/java/src/net/i2p/router/startup/StartAcceptingClientsJob.java
@@ -12,7 +12,7 @@ import net.i2p.router.JobImpl;
 import net.i2p.router.RouterContext;
 
 /** start I2CP interface */
-public class StartAcceptingClientsJob extends JobImpl {
+class StartAcceptingClientsJob extends JobImpl {
     
     public StartAcceptingClientsJob(RouterContext context) {
         super(context);
diff --git a/router/java/src/net/i2p/router/startup/WorkingDir.java b/router/java/src/net/i2p/router/startup/WorkingDir.java
index 3763f2e7a7..15a3e7fb44 100644
--- a/router/java/src/net/i2p/router/startup/WorkingDir.java
+++ b/router/java/src/net/i2p/router/startup/WorkingDir.java
@@ -147,7 +147,7 @@ public class WorkingDir {
         // Check for a router.keys file or logs dir, if either exists it's an old install,
         // and only migrate the data files if told to do so
         // (router.keys could be deleted later by a killkeys())
-        test = new File(oldDirf, "router.keys");
+        test = new File(oldDirf, CreateRouterInfoJob.KEYS_FILENAME);
         boolean oldInstall = test.exists();
         if (!oldInstall) {
             test = new File(oldDirf, "logs");
diff --git a/router/java/src/net/i2p/router/tasks/PersistRouterInfoJob.java b/router/java/src/net/i2p/router/tasks/PersistRouterInfoJob.java
index c29dd25772..6a14a51346 100644
--- a/router/java/src/net/i2p/router/tasks/PersistRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/tasks/PersistRouterInfoJob.java
@@ -13,10 +13,10 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 
 import net.i2p.data.DataFormatException;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.router.JobImpl;
-import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
+import net.i2p.router.startup.CreateRouterInfoJob;
 import net.i2p.util.Log;
 import net.i2p.util.SecureFileOutputStream;
 
@@ -37,8 +37,7 @@ public class PersistRouterInfoJob extends JobImpl {
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Persisting updated router info");
 
-        String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT);
-        File infoFile = new File(getContext().getRouterDir(), infoFilename);
+        File infoFile = new File(getContext().getRouterDir(), CreateRouterInfoJob.INFO_FILENAME);
 
         RouterInfo info = getContext().router().getRouterInfo();
 
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index bc3ad9543a..b9e38f9da3 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -17,8 +17,8 @@ import java.util.Locale;
 import java.util.Vector;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.RouterContext;
diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java
index e232fa7e46..459c846806 100644
--- a/router/java/src/net/i2p/router/transport/Transport.java
+++ b/router/java/src/net/i2p/router/transport/Transport.java
@@ -14,8 +14,8 @@ import java.util.List;
 import java.util.Vector;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.router.OutNetMessage;
 
 /**
diff --git a/router/java/src/net/i2p/router/transport/TransportEventListener.java b/router/java/src/net/i2p/router/transport/TransportEventListener.java
index 9a6d80d1ca..b8437efd1f 100644
--- a/router/java/src/net/i2p/router/transport/TransportEventListener.java
+++ b/router/java/src/net/i2p/router/transport/TransportEventListener.java
@@ -9,7 +9,7 @@ package net.i2p.router.transport;
  */
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.i2np.I2NPMessage;
 
 public interface TransportEventListener {
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index 194ae3016d..6dd93b4c59 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -30,9 +30,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
 
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.I2NPMessage;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.router.Job;
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index d9e0c37985..75e843707c 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -22,8 +22,8 @@ import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.i2np.I2NPMessage;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.router.OutNetMessage;
@@ -59,6 +59,7 @@ public class TransportManager implements TransportEventListener {
         _context = context;
         _log = _context.logManager().getLog(TransportManager.class);
         _context.statManager().createRateStat("transport.banlistOnUnreachable", "Add a peer to the banlist since none of the transports can reach them", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
+        _context.statManager().createRateStat("transport.banlistOnUsupportedSigType", "Add a peer to the banlist since signature type is unsupported", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
         _context.statManager().createRateStat("transport.noBidsYetNotAllUnreachable", "Add a peer to the banlist since none of the transports can reach them", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
         _context.statManager().createRateStat("transport.bidFailBanlisted", "Could not attempt to bid on message, as they were banlisted", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
         _context.statManager().createRateStat("transport.bidFailSelf", "Could not attempt to bid on message, as it targeted ourselves", "Transport", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
@@ -499,8 +500,11 @@ public class TransportManager implements TransportEventListener {
             }
         }
         if (unreachableTransports >= _transports.size()) {
-            // Don't banlist if we aren't talking to anybody, as we may have a network connection issue
-            if (unreachableTransports >= _transports.size() && countActivePeers() > 0) {
+            if (msg.getTarget().getIdentity().getSigningPublicKey().getType() == null) {
+                _context.statManager().addRateData("transport.banlistOnUnsupportedSigType", 1);
+                _context.banlist().banlistRouterForever(peer, _x("Unsupported signature type"));
+            } else if (unreachableTransports >= _transports.size() && countActivePeers() > 0) {
+                // Don't banlist if we aren't talking to anybody, as we may have a network connection issue
                 _context.statManager().addRateData("transport.banlistOnUnreachable", msg.getLifetime(), msg.getLifetime());
                 _context.banlist().banlistRouter(peer, _x("Unreachable on any transport"));
             }
diff --git a/router/java/src/net/i2p/router/transport/TransportUtil.java b/router/java/src/net/i2p/router/transport/TransportUtil.java
index 1682abd91c..648119f91d 100644
--- a/router/java/src/net/i2p/router/transport/TransportUtil.java
+++ b/router/java/src/net/i2p/router/transport/TransportUtil.java
@@ -13,7 +13,7 @@ import java.net.UnknownHostException;
 import java.util.HashMap;
 import java.util.Map;
 
-import net.i2p.data.RouterAddress;
+import net.i2p.data.router.RouterAddress;
 import net.i2p.router.RouterContext;
 
 /**
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
index bc6e37bc4d..b451d61544 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
@@ -11,7 +11,7 @@ import net.i2p.data.Base64;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.Signature;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
index d4fd7521ac..607234ae70 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
@@ -20,8 +20,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
 import net.i2p.I2PAppContext;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.router.RouterContext;
 import net.i2p.router.transport.FIFOBandwidthLimiter;
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
index 2b2ae6a442..acd5570e38 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java
@@ -17,9 +17,9 @@ import java.util.zip.Adler32;
 import net.i2p.data.Base64;
 import net.i2p.data.ByteArray;
 import net.i2p.data.DataHelper;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SessionKey;
 import net.i2p.data.i2np.DatabaseStoreMessage;
 import net.i2p.data.i2np.I2NPMessage;
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index 0ad8d88a94..c7e4703a4d 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -25,9 +25,9 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.DatabaseStoreMessage;
 import net.i2p.data.i2np.I2NPMessage;
 import net.i2p.router.CommSystemFacade;
@@ -362,6 +362,12 @@ public class NTCPTransport extends TransportImpl {
             return null;
         }
 
+        // Check for supported sig type
+        if (toAddress.getIdentity().getSigningPublicKey().getType() == null) {
+            markUnreachable(peer);
+            return null;
+        }
+
         if (!allowConnection()) {
             if (_log.shouldLog(Log.WARN))
                 _log.warn("no bid when trying to send to " + peer + ", max connection limit reached");
diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
index 267c4fc2a5..92696ff9ce 100644
--- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
@@ -10,9 +10,9 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SessionKey;
 import net.i2p.data.i2np.DatabaseStoreMessage;
 import net.i2p.data.i2np.DeliveryStatusMessage;
diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java
index abdd59e15d..6d1f177554 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java
@@ -5,11 +5,12 @@ import java.io.IOException;
 import java.util.Queue;
 import java.util.concurrent.LinkedBlockingQueue;
 
+import net.i2p.crypto.SigType;
 import net.i2p.data.Base64;
 import net.i2p.data.ByteArray;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.DataHelper;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.SessionKey;
 import net.i2p.data.Signature;
 import net.i2p.router.OutNetMessage;
@@ -47,6 +48,9 @@ class InboundEstablishState {
     private long _receivedSignedOnTime;
     private byte _receivedSignature[];
     private boolean _verificationAttempted;
+    // sig not verified
+    private RouterIdentity _receivedUnconfirmedIdentity;
+    // identical to uncomfirmed, but sig now verified
     private RouterIdentity _receivedConfirmedIdentity;
     // general status 
     private final long _establishBegin;
@@ -295,9 +299,28 @@ class InboundEstablishState {
         
         if (cur == _receivedIdentity.length-1) {
             _receivedSignedOnTime = conf.readFinalFragmentSignedOnTime();
-            if (_receivedSignature == null)
-                _receivedSignature = new byte[Signature.SIGNATURE_BYTES];
-            conf.readFinalSignature(_receivedSignature, 0);
+            // TODO verify time to prevent replay attacks
+            buildIdentity();
+            if (_receivedUnconfirmedIdentity != null) {
+                SigType type = _receivedUnconfirmedIdentity.getSigningPublicKey().getType();
+                if (type != null) {
+                    int sigLen = type.getSigLen();
+                    if (_receivedSignature == null)
+                        _receivedSignature = new byte[sigLen];
+                    conf.readFinalSignature(_receivedSignature, 0, sigLen);
+                } else {
+                    if (_log.shouldLog(Log.WARN))
+                        _log.warn("Unsupported sig type from: " + toString());
+                    // _x() in UDPTransport
+                    _context.banlist().banlistRouterForever(_receivedUnconfirmedIdentity.calculateHash(),
+                                                            "Unsupported signature type");
+                    fail();
+                }
+            } else {
+                if (_log.shouldLog(Log.WARN))
+                    _log.warn("Bad ident from: " + toString());
+                fail();
+            }
         }
         
         if ( (_currentState == InboundState.IB_STATE_UNKNOWN) || 
@@ -318,9 +341,10 @@ class InboundEstablishState {
      */
     private boolean confirmedFullyReceived() {
         if (_receivedIdentity != null) {
-            for (int i = 0; i < _receivedIdentity.length; i++)
+            for (int i = 0; i < _receivedIdentity.length; i++) {
                 if (_receivedIdentity[i] == null)
                     return false;
+            }
             return true;
         } else {
             return false;
@@ -339,7 +363,51 @@ class InboundEstablishState {
         }
         return _receivedConfirmedIdentity;
     }
-    
+
+    /**
+     *  Construct Alice's RouterIdentity.
+     *  Must have received all fragments.
+     *  Sets _receivedUnconfirmedIdentity, unless invalid.
+     *
+     *  Caller must synch on this.
+     *
+     *  @since 0.9.16 was in verifyIdentity()
+     */
+    private void buildIdentity() {
+        if (_receivedUnconfirmedIdentity != null)
+            return;   // dup pkt?
+        int frags = _receivedIdentity.length;
+        byte[] ident;
+        if (frags > 1) {
+            int identSize = 0;
+            for (int i = 0; i < _receivedIdentity.length; i++)
+                identSize += _receivedIdentity[i].length;
+            ident = new byte[identSize];
+            int off = 0;
+            for (int i = 0; i < _receivedIdentity.length; i++) {
+                int len = _receivedIdentity[i].length;
+                System.arraycopy(_receivedIdentity[i], 0, ident, off, len);
+                off += len;
+            }
+        } else {
+            // no need to copy
+            ident = _receivedIdentity[0];
+        }
+        ByteArrayInputStream in = new ByteArrayInputStream(ident); 
+        RouterIdentity peer = new RouterIdentity();
+        try {
+            peer.readBytes(in);
+            _receivedUnconfirmedIdentity = peer;
+        } catch (DataFormatException dfe) {
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Improperly formatted yet fully received ident", dfe);
+        } catch (IOException ioe) {
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Improperly formatted yet fully received ident", ioe);
+        }
+    }
+            
+
     /**
      * Determine if Alice sent us a valid confirmation packet.  The 
      * identity signs: Alice's IP + Alice's port + Bob's IP + Bob's port
@@ -351,21 +419,11 @@ class InboundEstablishState {
      * Caller must synch on this.
      */
     private void verifyIdentity() {
-        int identSize = 0;
-        for (int i = 0; i < _receivedIdentity.length; i++)
-            identSize += _receivedIdentity[i].length;
-        byte ident[] = new byte[identSize];
-        int off = 0;
-        for (int i = 0; i < _receivedIdentity.length; i++) {
-            int len = _receivedIdentity[i].length;
-            System.arraycopy(_receivedIdentity[i], 0, ident, off, len);
-            off += len;
-        }
-        ByteArrayInputStream in = new ByteArrayInputStream(ident); 
-        RouterIdentity peer = new RouterIdentity();
-        try {
-            peer.readBytes(in);
-            
+            if (_receivedUnconfirmedIdentity == null)
+                return;   // either not yet recvd or bad ident
+            if (_receivedSignature == null)
+                return;   // either not yet recvd or bad sig
+
             byte signed[] = new byte[256+256 // X + Y
                                      + _aliceIP.length + 2
                                      + _bobIP.length + 2
@@ -373,7 +431,7 @@ class InboundEstablishState {
                                      + 4 // signed on time
                                      ];
 
-            off = 0;
+            int off = 0;
             System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
             off += _receivedX.length;
             getSentY();
@@ -391,22 +449,15 @@ class InboundEstablishState {
             off += 4;
             DataHelper.toLong(signed, off, 4, _receivedSignedOnTime);
             Signature sig = new Signature(_receivedSignature);
-            boolean ok = _context.dsa().verifySignature(sig, signed, peer.getSigningPublicKey());
+            boolean ok = _context.dsa().verifySignature(sig, signed, _receivedUnconfirmedIdentity.getSigningPublicKey());
             if (ok) {
                 // todo partial spoof detection - get peer.calculateHash(),
                 // lookup in netdb locally, if not equal, fail?
-                _receivedConfirmedIdentity = peer;
+                _receivedConfirmedIdentity = _receivedUnconfirmedIdentity;
             } else {
                 if (_log.shouldLog(Log.WARN))
-                    _log.warn("Signature failed from " + peer);
+                    _log.warn("Signature failed from " + _receivedUnconfirmedIdentity);
             }
-        } catch (DataFormatException dfe) {
-            if (_log.shouldLog(Log.WARN))
-                _log.warn("Improperly formatted yet fully received ident", dfe);
-        } catch (IOException ioe) {
-            if (_log.shouldLog(Log.WARN))
-                _log.warn("Improperly formatted yet fully received ident", ioe);
-        }
     }
     
     private void packetReceived() {
diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java
index 37db458801..7e55cf1ce3 100644
--- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java
@@ -11,8 +11,8 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.data.Base64;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SessionKey;
 import net.i2p.router.RouterContext;
 import net.i2p.util.Addresses;
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java
index ba4375dbdb..ff94852559 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java
@@ -3,10 +3,11 @@ package net.i2p.router.transport.udp;
 import java.util.Queue;
 import java.util.concurrent.LinkedBlockingQueue;
 
+import net.i2p.crypto.SigType;
 import net.i2p.data.Base64;
 import net.i2p.data.ByteArray;
 import net.i2p.data.DataHelper;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.SessionKey;
 import net.i2p.data.Signature;
 import net.i2p.data.i2np.DatabaseStoreMessage;
@@ -41,6 +42,7 @@ class OutboundEstablishState {
     private SessionKey _sessionKey;
     private SessionKey _macKey;
     private Signature _receivedSignature;
+    // includes trailing padding to mod 16
     private byte[] _receivedEncryptedSignature;
     private byte[] _receivedIV;
     // SessionConfirmed messages
@@ -104,6 +106,7 @@ class OutboundEstablishState {
     /**
      *  @param claimedAddress an IP/port based RemoteHostId, or null if unknown
      *  @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect
+     *  @param remotePeer must have supported sig type
      *  @param introKey Bob's introduction key, as published in the netdb
      *  @param addr non-null
      */
@@ -247,8 +250,20 @@ class OutboundEstablishState {
         _alicePort = reader.readPort();
         _receivedRelayTag = reader.readRelayTag();
         _receivedSignedOnTime = reader.readSignedOnTime();
-        _receivedEncryptedSignature = new byte[Signature.SIGNATURE_BYTES + 8];
-        reader.readEncryptedSignature(_receivedEncryptedSignature, 0);
+        // handle variable signature size
+        SigType type = _remotePeer.getSigningPublicKey().getType();
+        if (type == null) {
+            // shouldn't happen, we only connect to supported peers
+            fail();
+            packetReceived();
+            return;
+        }
+        int sigLen = type.getSigLen();
+        int mod = sigLen % 16;
+        int pad = (mod == 0) ? 0 : (16 - mod);
+        int esigLen = sigLen + pad;
+        _receivedEncryptedSignature = new byte[esigLen];
+        reader.readEncryptedSignature(_receivedEncryptedSignature, 0, esigLen);
         _receivedIV = new byte[UDPPacket.IV_SIZE];
         reader.readIV(_receivedIV, 0);
         
@@ -353,7 +368,9 @@ class OutboundEstablishState {
      * decrypt the signature (and subsequent pad bytes) with the 
      * additional layer of encryption using the negotiated key along side
      * the packet's IV
+     *
      *  Caller must synch on this.
+     *  Only call this once! Decrypts in-place.
      */
     private void decryptSignature() {
         if (_receivedEncryptedSignature == null) throw new NullPointerException("encrypted signature is null! this=" + this.toString());
@@ -361,11 +378,20 @@ class OutboundEstablishState {
         if (_receivedIV == null) throw new NullPointerException("IV is null!");
         _context.aes().decrypt(_receivedEncryptedSignature, 0, _receivedEncryptedSignature, 0, 
                                _sessionKey, _receivedIV, _receivedEncryptedSignature.length);
-        byte signatureBytes[] = new byte[Signature.SIGNATURE_BYTES];
-        System.arraycopy(_receivedEncryptedSignature, 0, signatureBytes, 0, Signature.SIGNATURE_BYTES);
-        _receivedSignature = new Signature(signatureBytes);
+        // handle variable signature size
+        SigType type = _remotePeer.getSigningPublicKey().getType();
+        // if type == null throws NPE
+        int sigLen = type.getSigLen();
+        int mod = sigLen % 16;
+        if (mod != 0) {
+            byte signatureBytes[] = new byte[sigLen];
+            System.arraycopy(_receivedEncryptedSignature, 0, signatureBytes, 0, sigLen);
+            _receivedSignature = new Signature(type, signatureBytes);
+        } else {
+            _receivedSignature = new Signature(type, _receivedEncryptedSignature);
+        }
         if (_log.shouldLog(Log.DEBUG))
-            _log.debug("Decrypted received signature: " + Base64.encode(signatureBytes));
+            _log.debug("Decrypted received signature: " + Base64.encode(_receivedSignature.getData()));
     }
 
     /**
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
index 034f3e6054..2be5557744 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
@@ -6,7 +6,7 @@ import java.util.List;
 import java.util.Set;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.RouterContext;
 import net.i2p.util.ConcurrentHashSet;
diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
index 053703cb1c..d518a0b568 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
@@ -13,7 +13,7 @@ import net.i2p.I2PAppContext;
 import net.i2p.data.Base64;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterIdentity;
+import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.SessionKey;
 import net.i2p.data.Signature;
 import net.i2p.util.Addresses;
@@ -596,14 +596,22 @@ class PacketBuilder {
         off += 4;
         DataHelper.toLong(data, off, 4, state.getSentSignedOnTime());
         off += 4;
-        System.arraycopy(state.getSentSignature().getData(), 0, data, off, Signature.SIGNATURE_BYTES);
-        off += Signature.SIGNATURE_BYTES;
-        // ok, we need another 8 bytes of random padding
-        // (ok, this only gives us 63 bits, not 64)
-        long l = _context.random().nextLong();
-        if (l < 0) l = 0 - l;
-        DataHelper.toLong(data, off, 8, l);
-        off += 8;
+
+        // handle variable signature size
+        Signature sig = state.getSentSignature();
+        int siglen = sig.length();
+        System.arraycopy(sig.getData(), 0, data, off, siglen);
+        off += siglen;
+        // ok, we need another few bytes of random padding
+        int rem = siglen % 16;
+        int padding;
+        if (rem > 0) {
+            padding = 16 - rem;
+            _context.random().nextBytes(data, off, padding);
+            off += padding;
+        } else {
+            padding = 0;
+        }
         
         if (_log.shouldLog(Log.DEBUG)) {
             StringBuilder buf = new StringBuilder(128);
@@ -612,9 +620,9 @@ class PacketBuilder {
             buf.append(" Bob: ").append(Addresses.toString(state.getReceivedOurIP(), externalPort));
             buf.append(" RelayTag: ").append(state.getSentRelayTag());
             buf.append(" SignedOn: ").append(state.getSentSignedOnTime());
-            buf.append(" signature: ").append(Base64.encode(state.getSentSignature().getData()));
+            buf.append(" signature: ").append(Base64.encode(sig.getData()));
             buf.append("\nRawCreated: ").append(Base64.encode(data, 0, off)); 
-            buf.append("\nsignedTime: ").append(Base64.encode(data, off-8-Signature.SIGNATURE_BYTES-4, 4));
+            buf.append("\nsignedTime: ").append(Base64.encode(data, off - padding - siglen - 4, 4));
             _log.debug(buf.toString());
         }
         
@@ -623,7 +631,7 @@ class PacketBuilder {
         byte[] iv = SimpleByteCache.acquire(UDPPacket.IV_SIZE);
         _context.random().nextBytes(iv);
         
-        int encrWrite = Signature.SIGNATURE_BYTES + 8;
+        int encrWrite = siglen + padding;
         int sigBegin = off - encrWrite;
         _context.aes().encrypt(data, sigBegin, data, sigBegin, state.getCipherKey(), iv, encrWrite);
         
@@ -774,8 +782,11 @@ class PacketBuilder {
             DataHelper.toLong(data, off, 4, state.getSentSignedOnTime());
             off += 4;
             
+            // handle variable signature size
             // we need to pad this so we're at the encryption boundary
-            int mod = (off + Signature.SIGNATURE_BYTES) & 0x0f;
+            Signature sig = state.getSentSignature();
+            int siglen = sig.length();
+            int mod = (off + siglen) & 0x0f;
             if (mod != 0) {
                 int paddingRequired = 16 - mod;
                 // add an arbitrary number of 16byte pad blocks too ???
@@ -787,8 +798,8 @@ class PacketBuilder {
             // so trailing non-mod-16 data is ignored. That truncates the sig.
             
             // BUG: NPE here if null signature
-            System.arraycopy(state.getSentSignature().getData(), 0, data, off, Signature.SIGNATURE_BYTES);
-            off += Signature.SIGNATURE_BYTES;
+            System.arraycopy(sig.getData(), 0, data, off, siglen);
+            off += siglen;
         } else {
             // We never get here (see above)
 
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
index 48a5e08225..bc47fba87c 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
@@ -9,8 +9,8 @@ import java.util.concurrent.LinkedBlockingQueue;
 
 import net.i2p.data.Base64;
 import net.i2p.data.DataHelper;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SessionKey;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.router.RouterContext;
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPAddress.java b/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
index f05205582d..88551d588c 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPAddress.java
@@ -5,7 +5,7 @@ import java.net.UnknownHostException;
 import java.util.Map;
 
 import net.i2p.data.Base64;
-import net.i2p.data.RouterAddress;
+import net.i2p.data.router.RouterAddress;
 import net.i2p.data.SessionKey;
 import net.i2p.util.LHMCache;
 import net.i2p.util.SystemVersion;
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java
index affaf09df8..f7c89bb893 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java
@@ -203,9 +203,10 @@ class UDPPacketReader {
             return rv;
         }
         
-        public void readEncryptedSignature(byte target[], int targetOffset) {
+        /** @param size the amount to be copied, including padding to mod 16 */
+        public void readEncryptedSignature(byte target[], int targetOffset, int size) {
             int offset = readBodyOffset() + Y_LENGTH + 1 + readIPSize() + 2 + 4 + 4;
-            System.arraycopy(_message, offset, target, targetOffset, Signature.SIGNATURE_BYTES + 8);
+            System.arraycopy(_message, offset, target, targetOffset, size);
         }
         
         public void readIV(byte target[], int targetOffset) {
@@ -239,7 +240,11 @@ class UDPPacketReader {
             System.arraycopy(_message, readOffset, target, targetOffset, len);
         }
         
-        /** read the time at which the signature was generated */
+        /**
+         *  Read the time at which the signature was generated.
+         *  TODO must be completely in final fragment.
+         *  Time and sig cannot be split across fragments.
+         */
         public long readFinalFragmentSignedOnTime() {
             if (readCurrentFragmentNum() != readTotalFragmentNum()-1)
                 throw new IllegalStateException("This is not the final fragment");
@@ -247,12 +252,19 @@ class UDPPacketReader {
             return DataHelper.fromLong(_message, readOffset, 4);
         }
         
-        /** read the signature from the final sessionConfirmed packet */
-        public void readFinalSignature(byte target[], int targetOffset) {
+        /**
+         *  Read the signature from the final sessionConfirmed packet.
+         *  TODO must be completely in final fragment.
+         *  Time and sig cannot be split across fragments.
+         *  @param size not including padding
+         */
+        public void readFinalSignature(byte target[], int targetOffset, int size) {
             if (readCurrentFragmentNum() != readTotalFragmentNum()-1)
                 throw new IllegalStateException("This is not the final fragment");
-            int readOffset = _payloadBeginOffset + _payloadLength - Signature.SIGNATURE_BYTES;
-            System.arraycopy(_message, readOffset, target, targetOffset, Signature.SIGNATURE_BYTES);
+            int readOffset = _payloadBeginOffset + _payloadLength - size;
+            if (readOffset < readBodyOffset() + (1 + 2 + 4))
+                throw new IllegalStateException("Sig split across fragments");
+            System.arraycopy(_message, readOffset, target, targetOffset, size);
         }
     }
     
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
index b9c2ad8024..63fc957600 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -25,9 +25,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import net.i2p.data.DatabaseEntry;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterAddress;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterAddress;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.SessionKey;
 import net.i2p.data.i2np.DatabaseStoreMessage;
 import net.i2p.data.i2np.I2NPMessage;
@@ -1550,6 +1550,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 return null;
             }
 
+            // Check for supported sig type
+            if (toAddress.getIdentity().getSigningPublicKey().getType() == null) {
+                markUnreachable(to);
+                return null;
+            }
+
             if (!allowConnection())
                 return _cachedBid[TRANSIENT_FAIL_BID];
 
diff --git a/router/java/src/net/i2p/router/tunnel/InboundGatewayReceiver.java b/router/java/src/net/i2p/router/tunnel/InboundGatewayReceiver.java
index 3fa40c984e..bb18c44b22 100644
--- a/router/java/src/net/i2p/router/tunnel/InboundGatewayReceiver.java
+++ b/router/java/src/net/i2p/router/tunnel/InboundGatewayReceiver.java
@@ -1,7 +1,7 @@
 package net.i2p.router.tunnel;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.TunnelDataMessage;
 import net.i2p.router.JobImpl;
 import net.i2p.router.OutNetMessage;
diff --git a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
index ec3529b48f..660aedab81 100644
--- a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
+++ b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
@@ -4,7 +4,7 @@ import net.i2p.data.DatabaseEntry;
 import net.i2p.data.Hash;
 import net.i2p.data.LeaseSet;
 import net.i2p.data.Payload;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.DataMessage;
 import net.i2p.data.i2np.DatabaseSearchReplyMessage;
diff --git a/router/java/src/net/i2p/router/tunnel/OutboundMessageDistributor.java b/router/java/src/net/i2p/router/tunnel/OutboundMessageDistributor.java
index 364c5970ab..3961af80fc 100644
--- a/router/java/src/net/i2p/router/tunnel/OutboundMessageDistributor.java
+++ b/router/java/src/net/i2p/router/tunnel/OutboundMessageDistributor.java
@@ -4,7 +4,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.I2NPMessage;
 import net.i2p.data.i2np.TunnelGatewayMessage;
diff --git a/router/java/src/net/i2p/router/tunnel/OutboundReceiver.java b/router/java/src/net/i2p/router/tunnel/OutboundReceiver.java
index 03923ecfeb..4aef149028 100644
--- a/router/java/src/net/i2p/router/tunnel/OutboundReceiver.java
+++ b/router/java/src/net/i2p/router/tunnel/OutboundReceiver.java
@@ -1,7 +1,7 @@
 package net.i2p.router.tunnel;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.i2np.TunnelDataMessage;
 import net.i2p.router.JobImpl;
 import net.i2p.router.OutNetMessage;
diff --git a/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java b/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java
index b53d8a6430..d580602793 100644
--- a/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java
+++ b/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java
@@ -1,7 +1,7 @@
 package net.i2p.router.tunnel;
 
 import net.i2p.data.Hash;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.I2NPMessage;
 import net.i2p.data.i2np.TunnelDataMessage;
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java
index b771589a1f..42cff28c7a 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java
@@ -10,7 +10,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import net.i2p.data.Hash;
 import net.i2p.data.i2np.I2NPMessage;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.router.CommSystemFacade;
 import net.i2p.router.RouterContext;
 import net.i2p.router.TunnelManagerFacade;
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
index afe3940bff..3522e5c4ed 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
@@ -9,8 +9,8 @@ import net.i2p.data.Base64;
 import net.i2p.data.ByteArray;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterIdentity;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterIdentity;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.BuildRequestRecord;
 import net.i2p.data.i2np.BuildResponseRecord;
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java
index fbfca2bcc9..31aaa86654 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java
@@ -8,7 +8,7 @@ import net.i2p.data.ByteArray;
 import net.i2p.data.DataHelper;
 import net.i2p.data.Hash;
 import net.i2p.data.PublicKey;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.TunnelBuildMessage;
 import net.i2p.data.i2np.VariableTunnelBuildMessage;
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
index 14eab47e2c..8bb657831c 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
@@ -16,7 +16,7 @@ import net.i2p.I2PAppContext;
 import net.i2p.crypto.SHA256Generator;
 import net.i2p.data.DataFormatException;
 import net.i2p.data.Hash;
-import net.i2p.data.RouterInfo;
+import net.i2p.data.router.RouterInfo;
 import net.i2p.router.Router;
 import net.i2p.router.RouterContext;
 import net.i2p.router.TunnelPoolSettings;