propagate from branch 'i2p.i2p.zzz.test2' (head 6ccd9ca652057494bb2857e87636f18aadcd33f3)

to branch 'i2p.i2p' (head 376f751adc13923cdbf4f659c3f23ca957cf47b3)
This commit is contained in:
zzz
2014-09-23 13:06:36 +00:00
197 changed files with 4617 additions and 1989 deletions

View File

@ -182,7 +182,7 @@ Applications:
By welterde.
See licenses/LICENSE-GPLv2.txt
Jetty 8.1.15.v20140411:
Jetty 8.1.16.v20140903:
See licenses/ABOUT-Jetty.html
See licenses/NOTICE-Jetty.html
See licenses/LICENSE-Apache2.0.txt

View File

@ -64,10 +64,11 @@ class ConfigParser {
if (inputLine.startsWith(";")) {
return "";
}
if (inputLine.split("#").length > 0) {
return inputLine.split("#")[0];
int hash = inputLine.indexOf('#');
if (hash >= 0) {
return inputLine.substring(0, hash);
} else {
return "";
return inputLine;
}
}

View File

@ -100,15 +100,15 @@
<target name="war" depends="jar, bundle, warUpToDate, listChangedFiles" unless="war.uptodate" >
<!-- set if unset -->
<property name="workspace.changes.tr" value="" />
<copy todir="build/icons/.icons" >
<fileset dir="../icons/" />
<copy todir="build/resources/.resources" >
<fileset dir="../resources/" />
</copy>
<!-- mime.properties must be in with the classes -->
<copy file="../mime.properties" todir="build/obj/org/klomp/snark/web" />
<war destfile="../i2psnark.war" webxml="../web.xml" >
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
<classes dir="./build/obj" includes="**/web/*" />
<fileset dir="build/icons/" />
<fileset dir="build/resources/" />
<manifest>
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
@ -121,7 +121,7 @@
<target name="warUpToDate">
<uptodate property="war.uptodate" targetfile="../i2psnark.war" >
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../icons/* ../web.xml" />
<srcfiles dir= "." includes="build/obj/org/klomp/snark/web/*.class ../resources/**/* ../web.xml" />
</uptodate>
</target>

View File

@ -57,8 +57,8 @@ public class Peer implements Comparable<Peer>
private DataOutputStream dout;
/** running counters */
private long downloaded;
private long uploaded;
private final AtomicLong downloaded = new AtomicLong();
private final AtomicLong uploaded = new AtomicLong();
// Keeps state for in/out connections. Non-null when the handshake
// was successful, the connection setup and runs
@ -618,7 +618,7 @@ public class Peer implements Comparable<Peer>
* @since 0.8.4
*/
public void downloaded(int size) {
downloaded += size;
downloaded.addAndGet(size);
}
/**
@ -626,7 +626,7 @@ public class Peer implements Comparable<Peer>
* @since 0.8.4
*/
public void uploaded(int size) {
uploaded += size;
uploaded.addAndGet(size);
}
/**
@ -635,7 +635,7 @@ public class Peer implements Comparable<Peer>
*/
public long getDownloaded()
{
return downloaded;
return downloaded.get();
}
/**
@ -644,7 +644,7 @@ public class Peer implements Comparable<Peer>
*/
public long getUploaded()
{
return uploaded;
return uploaded.get();
}
/**
@ -652,8 +652,8 @@ public class Peer implements Comparable<Peer>
*/
public void resetCounters()
{
downloaded = 0;
uploaded = 0;
downloaded.set(0);
uploaded.set(0);
}
public long getInactiveTime() {

View File

@ -27,7 +27,6 @@ import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
@ -245,16 +244,19 @@ public class Snark
*
* @deprecated unused
*/
/****
Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
StorageListener slistener, CoordinatorListener clistener) {
this(util, torrent, ip, user_port, slistener, clistener, null, null, null, true, ".");
}
****/
/**
* single torrent - via router
*
* @deprecated unused
*/
/****
public Snark(I2PAppContext ctx, Properties opts, String torrent,
StorageListener slistener, boolean start, String rootDir) {
this(new I2PSnarkUtil(ctx), torrent, null, -1, slistener, null, null, null, null, false, rootDir);
@ -284,6 +286,7 @@ public class Snark
if (start)
this.startTorrent();
}
****/
/**
* multitorrent
@ -515,18 +518,13 @@ public class Snark
// Create a new ID and fill it with something random. First nine
// zeros bytes, then three bytes filled with snark and then
// sixteen random bytes.
// eight random bytes.
byte snark = (((3 + 7 + 10) * (1000 - 8)) / 992) - 17;
byte[] rv = new byte[20];
Random random = I2PAppContext.getGlobalContext().random();
int i;
for (i = 0; i < 9; i++)
rv[i] = 0;
rv[i++] = snark;
rv[i++] = snark;
rv[i++] = snark;
while (i < 20)
rv[i++] = (byte)random.nextInt(256);
rv[9] = snark;
rv[10] = snark;
rv[11] = snark;
I2PAppContext.getGlobalContext().random().nextBytes(rv, 12, 8);
return rv;
}
@ -958,6 +956,7 @@ public class Snark
* non-valid argument list. The given listeners will be
* passed to all components that take one.
*/
/****
private static Snark parseArguments(String[] args,
StorageListener slistener,
CoordinatorListener clistener)
@ -972,6 +971,7 @@ public class Snark
int i = 0;
while (i < args.length)
{
****/
/*
if (args[i].equals("--debug"))
{
@ -993,7 +993,9 @@ public class Snark
catch (NumberFormatException nfe) { }
}
}
else */ if (args[i].equals("--port"))
else */
/****
if (args[i].equals("--port"))
{
if (args.length - 1 < i + 1)
usage("--port needs port number to listen on");
@ -1099,6 +1101,7 @@ public class Snark
System.out.println
(" \tor (with --share) a file to share.");
}
****/
/**
* Aborts program abnormally.

View File

@ -600,10 +600,10 @@ public class SnarkManager implements CompleteListener {
/**
* Get all themes
* @return String[] -- Array of all the themes found.
* @return String[] -- Array of all the themes found, non-null, unsorted
*/
public String[] getThemes() {
String[] themes = null;
String[] themes;
// "docs/themes/snark/"
File dir = new File(_context.getBaseDir(), "docs/themes/snark");
FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } };
@ -614,6 +614,8 @@ public class SnarkManager implements CompleteListener {
for(int i = 0; i < dirnames.length; i++) {
themes[i] = dirnames[i].getName();
}
} else {
themes = new String[0];
}
// return the map.
return themes;

View File

@ -0,0 +1,531 @@
package org.klomp.snark.web;
import java.io.File;
import java.io.Serializable;
import java.text.Collator;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
import org.klomp.snark.MetaInfo;
import org.klomp.snark.Snark;
import org.klomp.snark.Storage;
/**
* Comparators for various columns
*
* @since 0.9.16 from TorrentNameComparator, moved from I2PSnarkservlet
*/
class Sorters {
/**
* Negative is reverse
*
*<ul>
*<li>0, 1: Name
*<li>2: Status
*<li>3: Peers
*<li>4: ETA
*<li>5: Size
*<li>6: Downloaded
*<li>7: Uploaded
*<li>8: Down rate
*<li>9: Up rate
*<li>10: Remaining (needed)
*<li>11: Upload ratio
*<li>12: File type
*</ul>
*
* @param servlet for file type callback only
*/
public static Comparator<Snark> getComparator(int type, I2PSnarkServlet servlet) {
boolean rev = type < 0;
Comparator<Snark> rv;
switch (type) {
case -1:
case 0:
case 1:
default:
rv = new TorrentNameComparator();
if (rev)
rv = Collections.reverseOrder(rv);
break;
case -2:
case 2:
rv = new StatusComparator(rev);
break;
case -3:
case 3:
rv = new PeersComparator(rev);
break;
case -4:
case 4:
rv = new ETAComparator(rev);
break;
case -5:
case 5:
rv = new SizeComparator(rev);
break;
case -6:
case 6:
rv = new DownloadedComparator(rev);
break;
case -7:
case 7:
rv = new UploadedComparator(rev);
break;
case -8:
case 8:
rv = new DownRateComparator(rev);
break;
case -9:
case 9:
rv = new UpRateComparator(rev);
break;
case -10:
case 10:
rv = new RemainingComparator(rev);
break;
case -11:
case 11:
rv = new RatioComparator(rev);
break;
case -12:
case 12:
rv = new FileTypeComparator(rev, servlet);
break;
}
return rv;
}
/**
* Sort alphabetically in current locale, ignore case, ignore leading "the "
* (I guess this is worth it, a lot of torrents start with "The "
* @since 0.7.14
*/
private static class TorrentNameComparator implements Comparator<Snark>, Serializable {
public int compare(Snark l, Snark r) {
return comp(l, r);
}
public static int comp(Snark l, Snark r) {
// put downloads and magnets first
if (l.getStorage() == null && r.getStorage() != null)
return -1;
if (l.getStorage() != null && r.getStorage() == null)
return 1;
String ls = l.getBaseName();
String llc = ls.toLowerCase(Locale.US);
if (llc.startsWith("the ") || llc.startsWith("the.") || llc.startsWith("the_"))
ls = ls.substring(4);
String rs = r.getBaseName();
String rlc = rs.toLowerCase(Locale.US);
if (rlc.startsWith("the ") || rlc.startsWith("the.") || rlc.startsWith("the_"))
rs = rs.substring(4);
return Collator.getInstance().compare(ls, rs);
}
}
/**
* Forward or reverse sort, but the fallback is always forward
*/
private static abstract class Sort implements Comparator<Snark>, Serializable {
private final boolean _rev;
public Sort(boolean rev) {
_rev = rev;
}
public int compare(Snark l, Snark r) {
int rv = compareIt(l, r);
if (rv != 0)
return _rev ? 0 - rv : rv;
return TorrentNameComparator.comp(l, r);
}
protected abstract int compareIt(Snark l, Snark r);
protected static int compLong(long l, long r) {
if (l < r)
return -1;
if (l > r)
return 1;
return 0;
}
}
private static class StatusComparator extends Sort {
private StatusComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
int rv = getStatus(l) - getStatus(r);
if (rv != 0)
return rv;
// use reverse remaining as first tie break
return compLong(r.getNeededLength(), l.getNeededLength());
}
private static int getStatus(Snark snark) {
long remaining = snark.getRemainingLength();
long needed = snark.getNeededLength();
if (snark.isStopped()) {
if (remaining < 0)
return 0;
if (remaining > 0)
return 5;
return 10;
}
if (snark.isStarting())
return 15;
if (snark.isAllocating())
return 20;
if (remaining < 0)
return 15; // magnet
if (remaining == 0)
return 100;
if (snark.isChecking())
return 95;
if (snark.getNeededLength() <= 0)
return 90;
if (snark.getPeerCount() <= 0)
return 40;
if (snark.getDownloadRate() <= 0)
return 50;
return 60;
}
}
private static class PeersComparator extends Sort {
public PeersComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return l.getPeerCount() - r.getPeerCount();
}
}
private static class RemainingComparator extends Sort {
public RemainingComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return compLong(l.getNeededLength(), r.getNeededLength());
}
}
private static class ETAComparator extends Sort {
public ETAComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return compLong(eta(l), eta(r));
}
private static long eta(Snark snark) {
long needed = snark.getNeededLength();
if (needed <= 0)
return 0;
long total = snark.getTotalLength();
if (needed > total)
needed = total;
long downBps = snark.getDownloadRate();
if (downBps > 0)
return needed / downBps;
return Long.MAX_VALUE;
}
}
private static class SizeComparator extends Sort {
public SizeComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return compLong(l.getTotalLength(), r.getTotalLength());
}
}
private static class DownloadedComparator extends Sort {
public DownloadedComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
long ld = l.getTotalLength() - l.getRemainingLength();
long rd = r.getTotalLength() - r.getRemainingLength();
return compLong(ld, rd);
}
}
private static class UploadedComparator extends Sort {
public UploadedComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return compLong(l.getUploaded(), r.getUploaded());
}
}
private static class DownRateComparator extends Sort {
public DownRateComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return compLong(l.getDownloadRate(), r.getDownloadRate());
}
}
private static class UpRateComparator extends Sort {
public UpRateComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
return compLong(l.getUploadRate(), r.getUploadRate());
}
}
private static class RatioComparator extends Sort {
private static final long M = 128 * 1024 * 1024;
public RatioComparator(boolean rev) { super(rev); }
public int compareIt(Snark l, Snark r) {
long lt = l.getTotalLength();
long ld = lt > 0 ? ((M * l.getUploaded()) / lt) : 0;
long rt = r.getTotalLength();
long rd = rt > 0 ? ((M * r.getUploaded()) / rt) : 0;
return compLong(ld, rd);
}
}
private static class FileTypeComparator extends Sort {
private final I2PSnarkServlet servlet;
public FileTypeComparator(boolean rev, I2PSnarkServlet servlet) {
super(rev);
this.servlet = servlet;
}
public int compareIt(Snark l, Snark r) {
String ls = toName(l);
String rs = toName(r);
return ls.compareTo(rs);
}
private String toName(Snark snark) {
MetaInfo meta = snark.getMetaInfo();
if (meta == null)
return "0";
if (meta.getFiles() != null)
return "1";
// arbitrary sort based on icon name
return servlet.toIcon(meta.getName());
}
}
////////////// Comparators for details page below
/**
* Class to precompute and efficiently sort data
* on a torrent file entry.
*/
public static class FileAndIndex {
public final File file;
public final boolean isDirectory;
public final long length;
public final long remaining;
public final int priority;
public final int index;
/**
* @param storage may be null
*/
public FileAndIndex(File file, Storage storage) {
this.file = file;
index = storage != null ? storage.indexOf(file) : -1;
if (index >= 0) {
isDirectory = false;
remaining = storage.remaining(index);
priority = storage.getPriority(index);
} else {
isDirectory = file.isDirectory();
remaining = -1;
priority = -999;
}
length = isDirectory ? 0 : file.length();
}
}
/**
* Negative is reverse
*
*<ul>
*<li>0, 1: Name
*<li>5: Size
*<li>10: Remaining (needed)
*<li>12: File type
*<li>13: Priority
*</ul>
*
* @param servlet for file type callback only
*/
public static Comparator<FileAndIndex> getFileComparator(int type, I2PSnarkServlet servlet) {
boolean rev = type < 0;
Comparator<FileAndIndex> rv;
switch (type) {
case -1:
case 0:
case 1:
default:
rv = new FileNameComparator();
if (rev)
rv = Collections.reverseOrder(rv);
break;
case -5:
case 5:
rv = new FAISizeComparator(rev);
break;
case -10:
case 10:
rv = new FAIRemainingComparator(rev);
break;
case -12:
case 12:
rv = new FAITypeComparator(rev, servlet);
break;
case -13:
case 13:
rv = new FAIPriorityComparator(rev);
break;
}
return rv;
}
/**
* Sort alphabetically in current locale, ignore case,
* directories first
* @since 0.9.6 moved from I2PSnarkServlet in 0.9.16
*/
private static class FileNameComparator implements Comparator<FileAndIndex>, Serializable {
public int compare(FileAndIndex l, FileAndIndex r) {
return comp(l, r);
}
public static int comp(FileAndIndex l, FileAndIndex r) {
boolean ld = l.isDirectory;
boolean rd = r.isDirectory;
if (ld && !rd)
return -1;
if (rd && !ld)
return 1;
return Collator.getInstance().compare(l.file.getName(), r.file.getName());
}
}
/**
* Forward or reverse sort, but the fallback is always forward
*/
private static abstract class FAISort implements Comparator<FileAndIndex>, Serializable {
private final boolean _rev;
public FAISort(boolean rev) {
_rev = rev;
}
public int compare(FileAndIndex l, FileAndIndex r) {
int rv = compareIt(l, r);
if (rv != 0)
return _rev ? 0 - rv : rv;
return FileNameComparator.comp(l, r);
}
protected abstract int compareIt(FileAndIndex l, FileAndIndex r);
protected static int compLong(long l, long r) {
if (l < r)
return -1;
if (l > r)
return 1;
return 0;
}
}
private static class FAIRemainingComparator extends FAISort {
public FAIRemainingComparator(boolean rev) { super(rev); }
public int compareIt(FileAndIndex l, FileAndIndex r) {
return compLong(l.remaining, r.remaining);
}
}
private static class FAISizeComparator extends FAISort {
public FAISizeComparator(boolean rev) { super(rev); }
public int compareIt(FileAndIndex l, FileAndIndex r) {
return compLong(l.length, r.length);
}
}
private static class FAITypeComparator extends FAISort {
private final I2PSnarkServlet servlet;
public FAITypeComparator(boolean rev, I2PSnarkServlet servlet) {
super(rev);
this.servlet = servlet;
}
public int compareIt(FileAndIndex l, FileAndIndex r) {
String ls = toName(l);
String rs = toName(r);
return ls.compareTo(rs);
}
private String toName(FileAndIndex fai) {
if (fai.isDirectory)
return "0";
// arbitrary sort based on icon name
return servlet.toIcon(fai.file.getName());
}
}
private static class FAIPriorityComparator extends FAISort {
public FAIPriorityComparator(boolean rev) { super(rev); }
/** highest first */
public int compareIt(FileAndIndex l, FileAndIndex r) {
return r.priority - l.priority;
}
}
}

View File

@ -8,6 +8,7 @@ epub = application/epub+zip
flac = audio/flac
flv = video/x-flv
iso = application/x-iso9660-image
js = text/javascript
m4a = audio/mp4a-latm
m4v = video/x-m4v
mkv = video/x-matroska

View File

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 464 B

View File

Before

Width:  |  Height:  |  Size: 733 B

After

Width:  |  Height:  |  Size: 733 B

View File

Before

Width:  |  Height:  |  Size: 587 B

After

Width:  |  Height:  |  Size: 587 B

View File

Before

Width:  |  Height:  |  Size: 673 B

After

Width:  |  Height:  |  Size: 673 B

View File

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 882 B

View File

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View File

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 766 B

View File

Before

Width:  |  Height:  |  Size: 653 B

After

Width:  |  Height:  |  Size: 653 B

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

Before

Width:  |  Height:  |  Size: 578 B

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

View File

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 385 B

View File

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 853 B

View File

Before

Width:  |  Height:  |  Size: 635 B

After

Width:  |  Height:  |  Size: 635 B

View File

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 294 B

View File

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 589 B

After

Width:  |  Height:  |  Size: 589 B

View File

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 591 B

View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

View File

@ -0,0 +1,93 @@
function setupbuttons() {
updatesetallbuttons();
var form = document.forms[0];
form.savepri.disabled = true;
form.savepri.className = 'disabled';
}
function priorityclicked() {
updatesetallbuttons();
var form = document.forms[0];
form.savepri.disabled = false;
form.savepri.className = 'accept';
}
function updatesetallbuttons() {
var notNorm = false;
var notHigh = false;
var notSkip = false;
var form = document.forms[0];
for(i = 0; i < form.elements.length; i++) {
var elem = form.elements[i];
if (elem.type == 'radio') {
if (!elem.checked) {
if (elem.className == 'prinorm')
notNorm = true;
else if (elem.className == 'prihigh')
notHigh = true;
else
notSkip = true;
}
}
}
if (notNorm)
document.getElementById('setallnorm').className = 'control';
else
document.getElementById('setallnorm').className = 'controld';
if (notHigh)
document.getElementById('setallhigh').className = 'control';
else
document.getElementById('setallhigh').className = 'controld';
if (notSkip)
document.getElementById('setallskip').className = 'control';
else
document.getElementById('setallskip').className = 'controld';
}
function setallnorm() {
var form = document.forms[0];
for(i = 0; i < form.elements.length; i++) {
var elem = form.elements[i];
if (elem.type == 'radio') {
if (elem.className === 'prinorm')
elem.checked = true;
}
}
document.getElementById('setallnorm').className = 'controld';
document.getElementById('setallhigh').className = 'control';
document.getElementById('setallskip').className = 'control';
form.savepri.disabled = false;
form.savepri.className = 'accept';
}
function setallhigh() {
var form = document.forms[0];
for(i = 0; i < form.elements.length; i++) {
var elem = form.elements[i];
if (elem.type == 'radio') {
if (elem.className === 'prihigh')
elem.checked = true;
}
}
document.getElementById('setallnorm').className = 'control';
document.getElementById('setallhigh').className = 'controld';
document.getElementById('setallskip').className = 'control';
form.savepri.disabled = false;
form.savepri.className = 'accept';
}
function setallskip() {
var form = document.forms[0];
for(i = 0; i < form.elements.length; i++) {
var elem = form.elements[i];
if (elem.type == 'radio') {
if (elem.className === 'priskip')
elem.checked = true;
}
}
document.getElementById('setallnorm').className = 'control';
document.getElementById('setallhigh').className = 'control';
document.getElementById('setallskip').className = 'controld';
form.savepri.disabled = false;
form.savepri.className = 'accept';
}

View File

@ -40,6 +40,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
@ -256,7 +257,15 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
}
if (gui) {
new I2PTunnelGUI(this);
// removed from source, now in i2p.scripts
//new I2PTunnelGUI(this);
try {
Class<?> cls = Class.forName("net.i2p.i2ptunnel.I2PTunnelGUI");
Constructor<?> con = cls.getConstructor(I2PTunnel.class);
con.newInstance(this);
} catch (Throwable t) {
throw new UnsupportedOperationException("GUI is not available, try -cli", t);
}
} else if (cli) {
try {
System.out.println("Enter 'help' for help.");

View File

@ -1,48 +0,0 @@
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
* (c) 2003 - 2004 mihi
*/
package net.i2p.i2ptunnel;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* AWT gui since kaffe doesn't support swing yet
*/
public class I2PTunnelGUI extends Frame implements ActionListener, Logging {
TextField input;
TextArea log;
I2PTunnel t;
public I2PTunnelGUI(I2PTunnel t) {
super("I2PTunnel control panel");
this.t = t;
setLayout(new BorderLayout());
add("South", input = new TextField());
input.addActionListener(this);
Font font = new Font("Monospaced", Font.PLAIN, 12);
add("Center", log = new TextArea("", 20, 80, TextArea.SCROLLBARS_VERTICAL_ONLY));
log.setFont(font);
log.setEditable(false);
log("enter 'help' for help.");
pack();
setVisible(true);
}
public void log(String s) {
log.append(s + "\n");
}
public void actionPerformed(ActionEvent evt) {
log("I2PTunnel>" + input.getText());
t.runCommand(input.getText(), this);
log("---");
input.setText("");
}
}

View File

@ -601,9 +601,12 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
return;
int status = ise != null ? ise.getStatus() : -1;
String error;
//TODO MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION
if (status == MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET) {
// We won't get this one unless it is treated as a hard failure
// in streaming. See PacketQueue.java
error = usingWWWProxy ? "nolsp" : "nols";
} else if (status == MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION) {
error = usingWWWProxy ? "encp" : "enc";
} else {
error = usingWWWProxy ? "dnfp" : "dnf";
}

View File

@ -188,8 +188,7 @@ public class EditBean extends IndexBean {
/** @since 0.9.12 */
public boolean isSigTypeAvailable(int code) {
SigType type = SigType.getByCode(code);
return type != null && type.isAvailable();
return SigType.isAvailable(code);
}
/** @since 0.8.9 */

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="jetty">
<property name="jetty.ver" value="8.1.15.v20140411" />
<property name="jetty.ver" value="8.1.16.v20140903" />
<property name="jetty.base" value="jetty-distribution-${jetty.ver}" />
<property name="jetty.sha1" value="41ec2b5e5605c038fb28d1f118669f06b4479e71" />
<property name="jetty.sha1" value="5440b33a722d82b746b9ce50168bfce3c22af349" />
<property name="jetty.filename" value="${jetty.base}.zip" />
<property name="jetty.url" value="http://download.eclipse.org/jetty/${jetty.ver}/dist/${jetty.filename}" />
<property name="verified.filename" value="verified.txt" />

View File

@ -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;

View File

@ -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
@ -199,10 +199,10 @@ public class NetDbRenderer {
FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade)_context.netDb();
buf.append("<p><b>Total Leasesets: ").append(leases.size());
buf.append("</b></p><p><b>Published (RAP) Leasesets: ").append(netdb.getKnownLeaseSets());
buf.append("</b></p><p><b>Mod Data: \"").append(DataHelper.getUTF8(_context.routingKeyGenerator().getModData()))
.append("\" Last Changed: ").append(new Date(_context.routingKeyGenerator().getLastChanged()));
buf.append("</b></p><p><b>Next Mod Data: \"").append(DataHelper.getUTF8(_context.routingKeyGenerator().getNextModData()))
.append("\" Change in: ").append(DataHelper.formatDuration(_context.routingKeyGenerator().getTimeTillMidnight()));
buf.append("</b></p><p><b>Mod Data: \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getModData()))
.append("\" Last Changed: ").append(new Date(_context.routerKeyGenerator().getLastChanged()));
buf.append("</b></p><p><b>Next Mod Data: \"").append(DataHelper.getUTF8(_context.routerKeyGenerator().getNextModData()))
.append("\" Change in: ").append(DataHelper.formatDuration(_context.routerKeyGenerator().getTimeTillMidnight()));
int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size();
buf.append("</b></p><p><b>Known Floodfills: ").append(ff);
buf.append("</b></p><p><b>Currently Floodfill? ");
@ -415,7 +415,9 @@ public class NetDbRenderer {
// shouldnt happen
buf.append("<b>" + _("Published") + ":</b> in ").append(DataHelper.formatDuration2(0-age)).append("???<br>\n");
}
buf.append("<b>" + _("Address(es)") + ":</b> ");
buf.append("<b>").append(_("Signing Key")).append(":</b> ")
.append(info.getIdentity().getSigningPublicKey().getType().toString());
buf.append("<br>\n<b>" + _("Address(es)") + ":</b> ");
String country = _context.commSystem().getCountry(info.getIdentity().getHash());
if(country != null) {
buf.append("<img height=\"11\" width=\"16\" alt=\"").append(country.toUpperCase(Locale.US)).append('\"');

View File

@ -10,7 +10,7 @@ import java.util.TreeSet;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.RouterInfo;
import net.i2p.data.router.RouterInfo;
import net.i2p.router.RouterContext;
import net.i2p.router.peermanager.DBHistory;
import net.i2p.router.peermanager.PeerProfile;

View File

@ -3,8 +3,8 @@ package net.i2p.router.web;
import java.util.Date;
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.Signature;
/**

View File

@ -15,8 +15,8 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
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.router.CommSystemFacade;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;

View File

@ -11,7 +11,7 @@ import java.util.Map;
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.TunnelId;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;

View File

@ -44,7 +44,7 @@ class PacketQueue implements SendMessageStatusListener {
private static final int FINAL_TAGS_TO_SEND = 4;
private static final int FINAL_TAG_THRESHOLD = 2;
private static final long REMOVE_EXPIRED_TIME = 67*1000;
private static final boolean ENABLE_STATUS_LISTEN = false;
private static final boolean ENABLE_STATUS_LISTEN = true;
public PacketQueue(I2PAppContext context, I2PSession session, ConnectionManager mgr) {
_context = context;
@ -267,6 +267,20 @@ class PacketQueue implements SendMessageStatusListener {
_messageStatusMap.remove(id);
break;
case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
// Ideally we would like to make this a hard failure,
// but it caused far too many fast-fails that were then
// resolved by the user clicking reload in his browser.
// Until the LS fetch is faster and more reliable,
// or we increase the timeout for it,
// we can't treat this one as a hard fail.
// Let the streaming retransmission paper over the problem.
if (_log.shouldLog(Log.WARN))
_log.warn("LS lookup (soft) failure for msg " + msgId + " on " + con);
_messageStatusMap.remove(id);
break;
case MessageStatusMessage.STATUS_SEND_FAILURE_LOCAL:
case MessageStatusMessage.STATUS_SEND_FAILURE_ROUTER:
case MessageStatusMessage.STATUS_SEND_FAILURE_NETWORK:
@ -280,7 +294,6 @@ class PacketQueue implements SendMessageStatusListener {
case MessageStatusMessage.STATUS_SEND_FAILURE_DESTINATION:
case MessageStatusMessage.STATUS_SEND_FAILURE_BAD_LEASESET:
case MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED_LEASESET:
case MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET:
case SendMessageStatusListener.STATUS_CANCELLED:
if (con.getHighestAckedThrough() >= 0) {
// a retxed SYN succeeded before the first SYN failed

View File

@ -548,7 +548,7 @@
windowtitle="I2P Anonymous Network - Java Documentation - Version ${release.number}">
<group title="Core SDK (i2p.jar)" packages="net.i2p:net.i2p.*:net.i2p.client:net.i2p.client.*:net.i2p.internal:net.i2p.internal.*:freenet.support.CPUInformation:org.bouncycastle.oldcrypto:org.bouncycastle.oldcrypto.*:gnu.crypto.*:gnu.getopt:gnu.gettext:com.nettgryppa.security:net.metanotion:net.metanotion.*" />
<group title="Streaming Library" packages="net.i2p.client.streaming:net.i2p.client.streaming.impl" />
<group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
<group title="Router" packages="net.i2p.router:net.i2p.router.*:net.i2p.data.i2np:net.i2p.data.router:org.cybergarage.*:org.freenetproject:org.xlattice.crypto.filters" />
<group title="Router Console" packages="net.i2p.router.web:net.i2p.router.update" />
<!-- apps and bridges starting here, alphabetical please -->
<group title="Addressbook Application" packages="net.i2p.addressbook" />

View File

@ -86,7 +86,6 @@ public class I2PAppContext {
private SHA256Generator _sha;
protected Clock _clock; // overridden in RouterContext
private DSAEngine _dsa;
private RoutingKeyGenerator _routingKeyGenerator;
private RandomSource _random;
private KeyGenerator _keyGenerator;
protected KeyRing _keyRing; // overridden in RouterContext
@ -106,7 +105,6 @@ public class I2PAppContext {
private volatile boolean _shaInitialized;
protected volatile boolean _clockInitialized; // used in RouterContext
private volatile boolean _dsaInitialized;
private volatile boolean _routingKeyGeneratorInitialized;
private volatile boolean _randomInitialized;
private volatile boolean _keyGeneratorInitialized;
protected volatile boolean _keyRingInitialized; // used in RouterContext
@ -126,7 +124,7 @@ public class I2PAppContext {
private final Object _lock1 = new Object(), _lock2 = new Object(), _lock3 = new Object(), _lock4 = new Object(),
_lock5 = new Object(), _lock6 = new Object(), _lock7 = new Object(), _lock8 = new Object(),
_lock9 = new Object(), _lock10 = new Object(), _lock11 = new Object(), _lock12 = new Object(),
_lock13 = new Object(), _lock14 = new Object(), _lock15 = new Object(), _lock16 = new Object(),
_lock13 = new Object(), _lock14 = new Object(), _lock16 = new Object(),
_lock17 = new Object(), _lock18 = new Object(), _lock19 = new Object(), _lock20 = new Object();
/**
@ -851,19 +849,13 @@ public class I2PAppContext {
* may want to test out how things react when peers don't agree on
* how to skew.
*
* As of 0.9.16, returns null in I2PAppContext.
* You must be in RouterContext to get a generator.
*
* @return null always
*/
public RoutingKeyGenerator routingKeyGenerator() {
if (!_routingKeyGeneratorInitialized)
initializeRoutingKeyGenerator();
return _routingKeyGenerator;
}
private void initializeRoutingKeyGenerator() {
synchronized (_lock15) {
if (_routingKeyGenerator == null)
_routingKeyGenerator = new RoutingKeyGenerator(this);
_routingKeyGeneratorInitialized = true;
}
return null;
}
/**

View File

@ -0,0 +1,135 @@
package net.i2p.crypto;
import java.math.BigInteger;
import java.security.spec.ECField;
import java.security.spec.ECFieldFp;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import net.i2p.util.NativeBigInteger;
/**
* Used by KeyGenerator.getSigningPublicKey()
*
* Modified from
* http://stackoverflow.com/questions/15727147/scalar-multiplication-of-point-over-elliptic-curve
* Apparently public domain.
* Supported P-192 only.
* Added curve parameters to support all curves.
*
* @since 0.9.16
*/
class ECUtil {
private static final BigInteger TWO = new BigInteger("2");
private static final BigInteger THREE = new BigInteger("3");
public static ECPoint scalarMult(ECPoint p, BigInteger kin, EllipticCurve curve) {
ECPoint r = ECPoint.POINT_INFINITY;
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
BigInteger k = kin.mod(prime);
int length = k.bitLength();
byte[] binarray = new byte[length];
for (int i = 0; i <= length-1; i++) {
binarray[i] = k.mod(TWO).byteValue();
k = k.divide(TWO);
}
for (int i = length-1; i >= 0; i--) {
// i should start at length-1 not -2 because the MSB of binarry may not be 1
r = doublePoint(r, curve);
if (binarray[i] == 1)
r = addPoint(r, p, curve);
}
return r;
}
private static ECPoint addPoint(ECPoint r, ECPoint s, EllipticCurve curve) {
if (r.equals(s))
return doublePoint(r, curve);
else if (r.equals(ECPoint.POINT_INFINITY))
return s;
else if (s.equals(ECPoint.POINT_INFINITY))
return r;
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
BigInteger slope = (r.getAffineY().subtract(s.getAffineY())).multiply(r.getAffineX().subtract(s.getAffineX()).modInverse(prime)).mod(prime);
slope = new NativeBigInteger(slope);
BigInteger xOut = (slope.modPow(TWO, prime).subtract(r.getAffineX())).subtract(s.getAffineX()).mod(prime);
BigInteger yOut = s.getAffineY().negate().mod(prime);
yOut = yOut.add(slope.multiply(s.getAffineX().subtract(xOut))).mod(prime);
ECPoint out = new ECPoint(xOut, yOut);
return out;
}
private static ECPoint doublePoint(ECPoint r, EllipticCurve curve) {
if (r.equals(ECPoint.POINT_INFINITY))
return r;
BigInteger slope = (r.getAffineX().pow(2)).multiply(THREE);
slope = slope.add(curve.getA());
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
slope = slope.multiply((r.getAffineY().multiply(TWO)).modInverse(prime));
BigInteger xOut = slope.pow(2).subtract(r.getAffineX().multiply(TWO)).mod(prime);
BigInteger yOut = (r.getAffineY().negate()).add(slope.multiply(r.getAffineX().subtract(xOut))).mod(prime);
ECPoint out = new ECPoint(xOut, yOut);
return out;
}
/**
* P-192 test only.
* See KeyGenerator.main() for a test of all supported curves.
*/
/****
public static void main(String[] args) {
EllipticCurve P192 = ECConstants.P192_SPEC.getCurve();
BigInteger xs = new BigInteger("d458e7d127ae671b0c330266d246769353a012073e97acf8", 16);
BigInteger ys = new BigInteger("325930500d851f336bddc050cf7fb11b5673a1645086df3b", 16);
BigInteger xt = new BigInteger("f22c4395213e9ebe67ddecdd87fdbd01be16fb059b9753a4", 16);
BigInteger yt = new BigInteger("264424096af2b3597796db48f8dfb41fa9cecc97691a9c79", 16);
ECPoint S = new ECPoint(xs,ys);
ECPoint T = new ECPoint(xt,yt);
// Verifying addition
ECPoint Rst = addPoint(S, T, P192);
BigInteger xst = new BigInteger("48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290", 16); // Specified value of x of point R for addition in NIST Routine example
System.out.println("x-coordinate of point Rst is : " + Rst.getAffineX());
System.out.println("y-coordinate of point Rst is : " + Rst.getAffineY());
if (Rst.getAffineX().equals(xst))
System.out.println("Adding is correct");
else
System.out.println("Adding FAIL");
//Verifying Doubling
BigInteger xr = new BigInteger("30c5bc6b8c7da25354b373dc14dd8a0eba42d25a3f6e6962", 16); // Specified value of x of point R for doubling in NIST Routine example
BigInteger yr = new BigInteger("0dde14bc4249a721c407aedbf011e2ddbbcb2968c9d889cf", 16);
ECPoint R2s = new ECPoint(xr, yr); // Specified value of y of point R for doubling in NIST Routine example
System.out.println("x-coordinate of point R2s is : " + R2s.getAffineX());
System.out.println("y-coordinate of point R2s is : " + R2s.getAffineY());
System.out.println("x-coordinate of calculated point is : " + doublePoint(S, P192).getAffineX());
System.out.println("y-coordinate of calculated point is : " + doublePoint(S, P192).getAffineY());
if (R2s.getAffineX().equals(doublePoint(S, P192).getAffineX()) &&
R2s.getAffineY().equals(doublePoint(S, P192).getAffineY()))
System.out.println("Doubling is correct");
else
System.out.println("Doubling FAIL");
xr = new BigInteger("1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31", 16); // Specified value of x of point R for scalar Multiplication in NIST Routine example
yr = new BigInteger("5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06", 16); // Specified value of y of point R for scalar Multiplication in NIST Routine example
ECPoint Rds = new ECPoint(xr, yr);
BigInteger d = new BigInteger("a78a236d60baec0c5dd41b33a542463a8255391af64c74ee", 16);
ECPoint Rs = scalarMult(S, d, P192);
System.out.println("x-coordinate of point Rds is : " + Rds.getAffineX());
System.out.println("y-coordinate of point Rds is : " + Rds.getAffineY());
System.out.println("x-coordinate of calculated point is : " + Rs.getAffineX());
System.out.println("y-coordinate of calculated point is : " + Rs.getAffineY());
if (Rds.getAffineX().equals(Rs.getAffineX()) &&
Rds.getAffineY().equals(Rs.getAffineY()))
System.out.println("Scalar Multiplication is correct");
else
System.out.println("Scalar Multiplication FAIL");
}
****/
}

View File

@ -57,6 +57,9 @@ public class ElGamalEngine {
private final I2PAppContext _context;
private final YKGenerator _ykgen;
private static final BigInteger ELGPM1 = CryptoConstants.elgp.subtract(BigInteger.ONE);
/**
* The ElGamal engine should only be constructed and accessed through the
* application context. This constructor should only be used by the
@ -171,10 +174,11 @@ public class ElGamalEngine {
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to encrypt ElGamal block (" + diff + "ms)");
}
_context.statManager().addRateData("crypto.elGamal.encrypt", diff, 0);
_context.statManager().addRateData("crypto.elGamal.encrypt", diff);
return out;
}
/** Decrypt the data
* @param encrypted encrypted data, must be exactly 514 bytes
* Contains the two-part encrypted data starting at bytes 0 and 257.
@ -184,26 +188,26 @@ public class ElGamalEngine {
* @return unencrypted data or null on failure
*/
public byte[] decrypt(byte encrypted[], PrivateKey privateKey) {
// actually it must be exactly 514 bytes or the arraycopy below will AIOOBE
if ((encrypted == null) || (encrypted.length > 514))
throw new IllegalArgumentException("Data to decrypt must be <= 514 bytes at the moment");
if ((encrypted == null) || (encrypted.length != 514))
throw new IllegalArgumentException("Data to decrypt must be exactly 514 bytes");
long start = _context.clock().now();
byte[] ybytes = new byte[257];
byte[] dbytes = new byte[257];
System.arraycopy(encrypted, 0, ybytes, 0, 257);
System.arraycopy(encrypted, 257, dbytes, 0, 257);
BigInteger y = new NativeBigInteger(1, ybytes);
BigInteger d = new NativeBigInteger(1, dbytes);
BigInteger a = new NativeBigInteger(1, privateKey.getData());
BigInteger y1p = CryptoConstants.elgp.subtract(BigInteger.ONE).subtract(a);
BigInteger y1p = ELGPM1.subtract(a);
// we use this buf first for Y, then for D, then for the hash
byte[] buf = SimpleByteCache.acquire(257);
System.arraycopy(encrypted, 0, buf, 0, 257);
BigInteger y = new NativeBigInteger(1, buf);
BigInteger ya = y.modPow(y1p, CryptoConstants.elgp);
System.arraycopy(encrypted, 257, buf, 0, 257);
BigInteger d = new NativeBigInteger(1, buf);
BigInteger m = ya.multiply(d);
m = m.mod(CryptoConstants.elgp);
byte val[] = m.toByteArray();
int i = 0;
for (i = 0; i < val.length; i++)
int i;
for (i = 0; i < val.length; i++) {
if (val[i] != (byte) 0x00) break;
}
int payloadLen = val.length - i - 1 - Hash.HASH_LENGTH;
if (payloadLen < 0) {
@ -220,10 +224,10 @@ public class ElGamalEngine {
byte rv[] = new byte[payloadLen];
System.arraycopy(val, i + 1 + Hash.HASH_LENGTH, rv, 0, rv.length);
byte[] calcHash = SimpleByteCache.acquire(Hash.HASH_LENGTH);
_context.sha().calculateHash(rv, 0, payloadLen, calcHash, 0);
boolean ok = DataHelper.eq(calcHash, 0, val, i + 1, Hash.HASH_LENGTH);
SimpleByteCache.release(calcHash);
// we reuse buf here for the calculated hash
_context.sha().calculateHash(rv, 0, payloadLen, buf, 0);
boolean ok = DataHelper.eq(buf, 0, val, i + 1, Hash.HASH_LENGTH);
SimpleByteCache.release(buf);
long end = _context.clock().now();
@ -233,7 +237,7 @@ public class ElGamalEngine {
_log.warn("Took too long to decrypt and verify ElGamal block (" + diff + "ms)");
}
_context.statManager().addRateData("crypto.elGamal.decrypt", diff, 0);
_context.statManager().addRateData("crypto.elGamal.decrypt", diff);
if (ok) {
//_log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length));

View File

@ -12,11 +12,25 @@ package net.i2p.crypto;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.ProviderException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.RSAKeyGenParameterSpec;
import java.security.spec.RSAPublicKeySpec;
import net.i2p.I2PAppContext;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import net.i2p.data.Hash;
import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey;
@ -268,24 +282,56 @@ public class KeyGenerator {
}
/** Convert a SigningPrivateKey to a SigningPublicKey.
* DSA-SHA1 only.
* As of 0.9.16, supports all key types.
*
* @param priv a SigningPrivateKey object
* @return a SigningPublicKey object
* @throws IllegalArgumentException on bad key
* @throws IllegalArgumentException on bad key or unknown type
*/
public static SigningPublicKey getSigningPublicKey(SigningPrivateKey priv) {
if (priv.getType() != SigType.DSA_SHA1)
throw new IllegalArgumentException();
SigType type = priv.getType();
if (type == null)
throw new IllegalArgumentException("Unknown type");
try {
switch (type.getBaseAlgorithm()) {
case DSA:
BigInteger x = new NativeBigInteger(1, priv.toByteArray());
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
SigningPublicKey pub = new SigningPublicKey();
try {
pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
} catch (InvalidKeyException ike) {
throw new IllegalArgumentException(ike);
}
return pub;
case EC:
ECPrivateKey ecpriv = SigUtil.toJavaECKey(priv);
BigInteger s = ecpriv.getS();
ECParameterSpec spec = (ECParameterSpec) type.getParams();
EllipticCurve curve = spec.getCurve();
ECPoint g = spec.getGenerator();
ECPoint w = ECUtil.scalarMult(g, s, curve);
ECPublicKeySpec ecks = new ECPublicKeySpec(w, ecpriv.getParams());
KeyFactory eckf = KeyFactory.getInstance("EC");
ECPublicKey ecpub = (ECPublicKey) eckf.generatePublic(ecks);
return SigUtil.fromJavaKey(ecpub, type);
case RSA:
RSAPrivateKey rsapriv = SigUtil.toJavaRSAKey(priv);
BigInteger exp = ((RSAKeyGenParameterSpec)type.getParams()).getPublicExponent();
RSAPublicKeySpec rsaks = new RSAPublicKeySpec(rsapriv.getModulus(), exp);
KeyFactory rsakf = KeyFactory.getInstance("RSA");
RSAPublicKey rsapub = (RSAPublicKey) rsakf.generatePublic(rsaks);
return SigUtil.fromJavaKey(rsapub, type);
case EdDSA:
EdDSAPrivateKey epriv = SigUtil.toJavaEdDSAKey(priv);
EdDSAPublicKey epub = new EdDSAPublicKey(new EdDSAPublicKeySpec(epriv.getA(), epriv.getParams()));
return SigUtil.fromJavaKey(epub, type);
default:
throw new IllegalArgumentException("Unsupported algorithm");
}
} catch (GeneralSecurityException gse) {
throw new IllegalArgumentException("Conversion failed", gse);
}
}
public static void main(String args[]) {
@ -322,14 +368,20 @@ public class KeyGenerator {
long stime = 0;
long vtime = 0;
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
//System.out.println("pubkey " + keys[0]);
SigningPublicKey pubkey = (SigningPublicKey) keys[0];
SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
SigningPublicKey pubkey2 = getSigningPublicKey(privkey);
if (pubkey.equals(pubkey2))
System.out.println(type + " private-to-public test PASSED");
else
System.out.println(type + " private-to-public test FAILED");
//System.out.println("privkey " + keys[1]);
for (int i = 0; i < runs; i++) {
RandomSource.getInstance().nextBytes(src);
long start = System.nanoTime();
Signature sig = DSAEngine.getInstance().sign(src, (SigningPrivateKey) keys[1]);
Signature sig = DSAEngine.getInstance().sign(src, privkey);
long mid = System.nanoTime();
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, (SigningPublicKey) keys[0]);
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, pubkey);
long end = System.nanoTime();
stime += mid - start;
vtime += end - mid;

View File

@ -345,7 +345,7 @@ public class SigUtil {
}
/**
* @deprecated unused
*
*/
public static RSAPrivateKey toJavaRSAKey(SigningPrivateKey pk)
throws GeneralSecurityException {
@ -358,7 +358,7 @@ public class SigUtil {
}
/**
* @deprecated unused
*
*/
public static SigningPublicKey fromJavaKey(RSAPublicKey pk, SigType type)
throws GeneralSecurityException {

View File

@ -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;
@ -638,13 +633,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);
@ -667,7 +666,7 @@ public class DataHelper {
* @param value non-negative
*/
public static void toLong(byte target[], int offset, int numBytes, long value) throws IllegalArgumentException {
if (numBytes <= 0) throw new IllegalArgumentException("Invalid number of bytes");
if (numBytes <= 0 || numBytes > 8) throw new IllegalArgumentException("Invalid number of bytes");
if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
for (int i = offset + numBytes - 1; i >= offset; i--) {
@ -1425,58 +1424,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<? extends DataStructure> sortStructures(Collection<? extends DataStructure> 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<DataStructure> rv = new ArrayList(dataStructures.size());
//TreeMap<String, DataStructure> tm = new TreeMap();
//for (DataStructure struct : dataStructures) {
// tm.put(struct.calculateHash().toString(), struct);
//}
//for (DataStructure struct : tm.values()) {
// rv.add(struct);
//}
ArrayList<DataStructure> rv = new ArrayList<DataStructure>(dataStructures);
sortStructureList(rv);
return rv;
}
/**
* See above.
* DEPRECATED - Only used by RouterInfo.
*
* @since 0.9
*/
static void sortStructureList(List<? extends DataStructure> dataStructures) {
Collections.sort(dataStructures, new DataStructureComparator());
}
/**
* See sortStructures() comments.
* @since 0.8.3
*/
private static class DataStructureComparator implements Comparator<DataStructure>, Serializable {
public int compare(DataStructure l, DataStructure r) {
return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64());
}
}
/**
* NOTE: formatDuration2() recommended in most cases for readability
*/

View File

@ -11,6 +11,7 @@ package net.i2p.data;
import java.util.Arrays;
import net.i2p.I2PAppContext;
import net.i2p.crypto.DSAEngine;
/**
@ -47,7 +48,7 @@ public abstract class DatabaseEntry extends DataStructureImpl {
protected volatile Signature _signature;
protected volatile Hash _currentRoutingKey;
protected volatile byte[] _routingKeyGenMod;
protected volatile long _routingKeyGenMod;
/**
* A common interface to the timestamp of the two subclasses.
@ -106,11 +107,15 @@ public abstract class DatabaseEntry extends DataStructureImpl {
* Get the routing key for the structure using the current modifier in the RoutingKeyGenerator.
* This only calculates a new one when necessary though (if the generator's key modifier changes)
*
* @throws IllegalStateException if not in RouterContext
*/
public Hash getRoutingKey() {
RoutingKeyGenerator gen = RoutingKeyGenerator.getInstance();
byte[] mod = gen.getModData();
if (!Arrays.equals(mod, _routingKeyGenMod)) {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
if (!ctx.isRouterContext())
throw new IllegalStateException("Not in router context");
RoutingKeyGenerator gen = ctx.routingKeyGenerator();
long mod = gen.getLastChanged();
if (mod != _routingKeyGenMod) {
_currentRoutingKey = gen.getRoutingKey(getHash());
_routingKeyGenMod = mod;
}
@ -124,9 +129,16 @@ public abstract class DatabaseEntry extends DataStructureImpl {
_currentRoutingKey = key;
}
/**
* @throws IllegalStateException if not in RouterContext
*/
public boolean validateRoutingKey() {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
if (!ctx.isRouterContext())
throw new IllegalStateException("Not in router context");
RoutingKeyGenerator gen = ctx.routingKeyGenerator();
Hash destKey = getHash();
Hash rk = RoutingKeyGenerator.getInstance().getRoutingKey(destKey);
Hash rk = gen.getRoutingKey(destKey);
return rk.equals(getRoutingKey());
}

View File

@ -77,6 +77,13 @@ public class KeysAndCert extends DataStructureImpl {
_signingKey = key;
}
/**
* @since 0.9.16
*/
public byte[] getPadding() {
return _padding;
}
/**
* @throws IllegalStateException if was already set
* @since 0.9.12
@ -114,6 +121,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);
}

View File

@ -50,6 +50,7 @@ public class PrivateKey extends SimpleDataStructure {
/** derives a new PublicKey object derived from the secret contents
* of this PrivateKey
* @return a PublicKey object
* @throws IllegalArgumentException on bad key
*/
public PublicKey toPublic() {
return KeyGenerator.getPublicKey(this);

View File

@ -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 Destination dest;
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) {}
@ -438,6 +455,23 @@ public class PrivateKeyFile {
}
}
/**
* Verify that the PublicKey matches the PrivateKey, and
* the SigningPublicKey matches the SigningPrivateKey.
*
* @return success
* @since 0.9.16
*/
public boolean validateKeyPairs() {
try {
if (!dest.getPublicKey().equals(KeyGenerator.getPublicKey(privKey)))
return false;
return dest.getSigningPublicKey().equals(KeyGenerator.getSigningPublicKey(signingPrivKey));
} catch (IllegalArgumentException iae) {
return false;
}
}
@Override
public String toString() {
StringBuilder s = new StringBuilder(128);

View File

@ -9,215 +9,40 @@ package net.i2p.data;
*
*/
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA256Generator;
import net.i2p.util.HexDump;
import net.i2p.util.Log;
/**
* Component to manage the munging of hashes into routing keys - given a hash,
* perform some consistent transformation against it and return the result.
* This transformation is fed by the current "mod data".
*
* Right now the mod data is the current date (GMT) as a string: "yyyyMMdd",
* and the transformation takes the original hash, appends the bytes of that mod data,
* then returns the SHA256 of that concatenation.
*
* Do we want this to simply do the XOR of the SHA256 of the current mod data and
* the key? does that provide the randomization we need? It'd save an SHA256 op.
* Bah, too much effort to think about for so little gain. Other algorithms may come
* into play layer on about making periodic updates to the routing key for data elements
* to mess with Sybil. This may be good enough though.
*
* Also - the method generateDateBasedModData() should be called after midnight GMT
* once per day to generate the correct routing keys!
*
* Warning - API subject to change. Not for use outside the router.
* As of 0.9.16, this is essentially just an interface.
* Implementation moved to net.i2p.data.router.RouterKeyGenerator.
* No generator is available in I2PAppContext; you must be in RouterContext.
*
*/
public class RoutingKeyGenerator {
private final Log _log;
private final I2PAppContext _context;
public RoutingKeyGenerator(I2PAppContext context) {
_log = context.logManager().getLog(RoutingKeyGenerator.class);
_context = context;
// ensure non-null mod data
generateDateBasedModData();
}
public abstract class RoutingKeyGenerator {
/**
* Get the generator for this context.
*
* @return null in I2PAppContext; non-null in RouterContext.
*/
public static RoutingKeyGenerator getInstance() {
return I2PAppContext.getGlobalContext().routingKeyGenerator();
}
private volatile byte _currentModData[];
private volatile byte _nextModData[];
private volatile long _nextMidnight;
private volatile long _lastChanged;
private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
private static final String FORMAT = "yyyyMMdd";
private static final int LENGTH = FORMAT.length();
private final static SimpleDateFormat _fmt = new SimpleDateFormat(FORMAT, Locale.US);
static {
// make sure GMT is set, azi2phelper Vuze plugin is disabling static JVM TZ setting in Router.java
_fmt.setCalendar(_cal);
}
/**
* The current (today's) mod data.
* Warning - not a copy, do not corrupt.
*
* @return non-null, 8 bytes
* The version of the current (today's) mod data.
* Use to determine if the routing key should be regenerated.
*/
public byte[] getModData() {
return _currentModData;
}
public abstract long getLastChanged();
/**
* Tomorrow's mod data.
* Warning - not a copy, do not corrupt.
* For debugging use only.
*
* @return non-null, 8 bytes
* @since 0.9.10
*/
public byte[] getNextModData() {
return _nextModData;
}
public long getLastChanged() {
return _lastChanged;
}
/**
* How long until midnight (ms)
*
* @return could be slightly negative
* @since 0.9.10 moved from UpdateRoutingKeyModifierJob
*/
public long getTimeTillMidnight() {
return _nextMidnight - _context.clock().now();
}
/**
* Set _cal to midnight for the time given.
* Caller must synch.
* @since 0.9.10
*/
private void setCalToPreviousMidnight(long now) {
_cal.setTime(new Date(now));
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR)); // gcj <= 4.0 workaround
_cal.set(Calendar.DAY_OF_YEAR, _cal.get(Calendar.DAY_OF_YEAR)); // gcj <= 4.0 workaround
_cal.set(Calendar.HOUR_OF_DAY, 0);
_cal.set(Calendar.MINUTE, 0);
_cal.set(Calendar.SECOND, 0);
_cal.set(Calendar.MILLISECOND, 0);
}
/**
* Generate mod data from _cal.
* Caller must synch.
* @since 0.9.10
*/
private byte[] generateModDataFromCal() {
Date today = _cal.getTime();
String modVal = _fmt.format(today);
if (modVal.length() != LENGTH)
throw new IllegalStateException();
byte[] mod = new byte[LENGTH];
for (int i = 0; i < LENGTH; i++)
mod[i] = (byte)(modVal.charAt(i) & 0xFF);
return mod;
}
/**
* Update the current modifier data with some bytes derived from the current
* date (yyyyMMdd in GMT)
*
* @return true if changed
*/
public synchronized boolean generateDateBasedModData() {
long now = _context.clock().now();
setCalToPreviousMidnight(now);
byte[] mod = generateModDataFromCal();
boolean changed = !Arrays.equals(_currentModData, mod);
if (changed) {
// add a day and store next midnight and mod data for convenience
_cal.add(Calendar.DATE, 1);
_nextMidnight = _cal.getTime().getTime();
byte[] next = generateModDataFromCal();
_currentModData = mod;
_nextModData = next;
_lastChanged = now;
if (_log.shouldLog(Log.INFO))
_log.info("Routing modifier generated: " + HexDump.dump(mod));
}
return changed;
}
/**
* Generate a modified (yet consistent) hash from the origKey by generating the
* SHA256 of the targetKey with the current modData appended to it
*
* This makes Sybil's job a lot harder, as she needs to essentially take over the
* whole keyspace.
* Get the routing key for a key.
*
* @throws IllegalArgumentException if origKey is null
*/
public Hash getRoutingKey(Hash origKey) {
return getKey(origKey, _currentModData);
}
public abstract Hash getRoutingKey(Hash origKey);
/**
* Get the routing key using tomorrow's modData, not today's
*
* @since 0.9.10
*/
public Hash getNextRoutingKey(Hash origKey) {
return getKey(origKey, _nextModData);
}
/**
* Generate a modified (yet consistent) hash from the origKey by generating the
* SHA256 of the targetKey with the specified modData appended to it
*
* @throws IllegalArgumentException if origKey is null
*/
private static Hash getKey(Hash origKey, byte[] modData) {
if (origKey == null) throw new IllegalArgumentException("Original key is null");
byte modVal[] = new byte[Hash.HASH_LENGTH + LENGTH];
System.arraycopy(origKey.getData(), 0, modVal, 0, Hash.HASH_LENGTH);
System.arraycopy(modData, 0, modVal, Hash.HASH_LENGTH, LENGTH);
return SHA256Generator.getInstance().calculateHash(modVal);
}
/****
public static void main(String args[]) {
Hash k1 = new Hash();
byte k1d[] = new byte[Hash.HASH_LENGTH];
RandomSource.getInstance().nextBytes(k1d);
k1.setData(k1d);
for (int i = 0; i < 10; i++) {
System.out.println("K1: " + k1);
Hash k1m = RoutingKeyGenerator.getInstance().getRoutingKey(k1);
System.out.println("MOD: " + new String(RoutingKeyGenerator.getInstance().getModData()));
System.out.println("K1M: " + k1m);
}
try {
Thread.sleep(2000);
} catch (Throwable t) { // nop
}
}
****/
}

View File

@ -75,8 +75,12 @@ public class SigningPrivateKey extends SimpleDataStructure {
return _type;
}
/** converts this signing private key to its public equivalent
/**
* Converts this signing private key to its public equivalent.
* As of 0.9.16, supports all key types.
*
* @return a SigningPublicKey object derived from this private key
* @throws IllegalArgumentException on bad key or unknown or unsupported type
*/
public SigningPublicKey toPublic() {
return KeyGenerator.getSigningPublicKey(this);

View File

@ -70,9 +70,12 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
}
}
/**
* @throws UnsupportedOperationException always
*/
@Override
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
throw new RuntimeException("go away, we dont want any");
throw new UnsupportedOperationException();
}
/**

View File

@ -101,9 +101,12 @@ public class SendMessageMessage extends I2CPMessageImpl {
}
}
/**
* @throws UnsupportedOperationException always
*/
@Override
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
throw new RuntimeException("wtf, dont run me");
throw new UnsupportedOperationException();
}
/**

View File

@ -0,0 +1,24 @@
HTTP/1.1 504 Gateway Timeout
Content-Type: text/html; charset=UTF-8
Cache-control: no-cache
Connection: close
Proxy-Connection: close
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>_("Warning: Eepsite Unreachable")</title>
<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico">
<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="logo">
<a href="http://127.0.0.1:7657/" title="_("Router Console")"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="_("I2P Router Console")" border="0"></a><hr>
<a href="http://127.0.0.1:7657/config.jsp">_("Configuration")</a> <a href="http://127.0.0.1:7657/help.jsp">_("Help")</a> <a href="http://127.0.0.1:7657/susidns/index">_("Addressbook")</a>
</div>
<div class="warning" id="warning">
<h3>_("Warning: Eepsite Unreachable")</h3>
<p>
_("The eepsite was not reachable, because it uses encryption options that are not supported by your I2P or Java version.")
<hr>
<p><b>_("Could not connect to the following destination:")</b>
</p>

View File

@ -0,0 +1,25 @@
HTTP/1.1 504 Gateway Timeout
Content-Type: text/html; charset=UTF-8
Cache-control: no-cache
Connection: close
Proxy-Connection: close
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>_("Warning: Outproxy Unreachable")</title>
<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico">
<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="logo">
<a href="http://127.0.0.1:7657/" title="_("Router Console")"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="_("I2P Router Console")" border="0"></a><hr>
<a href="http://127.0.0.1:7657/config.jsp">_("Configuration")</a> <a href="http://127.0.0.1:7657/help.jsp">_("Help")</a> <a href="http://127.0.0.1:7657/susidns/index">_("Addressbook")</a>
</div>
<div class="warning" id="warning">
<h3>_("Warning: Outproxy Unreachable")</h3>
<p>
_("The HTTP outproxy was not reachable, because it uses encryption options that are not supported by your I2P or Java version.")
_("You may want to {0}retry{1} as this will randomly reselect an outproxy from the pool you have defined {2}here{3} (if you have more than one configured).", "<a href=\"javascript:parent.window.location.reload()\">", "</a>", "<a href=\"http://127.0.0.1:7657/i2ptunnel/index.jsp\">", "</a>")
_("If you continue to have trouble you may want to edit your outproxy list {0}here{1}.", "<a href=\"http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=0\">", "</a>")
</p>
<hr><p><b>_("Could not connect to the following destination:")</b></p>

View File

@ -513,6 +513,40 @@ a:active {
color: #77b;
}
a.control, a.controld {
background: #fff;
border: 1px inset #191;
border-radius: 4px;
color: #359;
font-weight: bold;
margin: 2px 4px;
padding: 3px 4px;
text-shadow: 0px 0px #410;
white-space: nowrap;
}
a.controld {
color: #459;
font-weight: normal;
}
a.control img, a.controld img {
display: none;
}
a.control:hover {
background-color: #559;
border: 1px outset #559;
color: #fff;
text-shadow: 0px 1px 5px #410;
}
a.control:active {
background: #f60 !important;
color: #fff !important;
text-shadow: 0 !important;
}
input {
font-size: 9pt;
font-weight: bold;
@ -594,6 +628,14 @@ input[type=radio] {
input.default { width: 1px; height: 1px; visibility: hidden; }
input.disabled, input.disabled:hover {
background-color: #fff;
border: 1px inset #191;
color: #459;
font-weight: normal;
text-shadow: 0px 0px 0px #410;
}
select {
background: #fff !important;
color: #22f;

View File

@ -366,6 +366,10 @@ table.snarkTorrents tbody tr:hover, table.snarkDirInfo tbody tr:hover {
width: 16px;
}
td.snarkFileIcon:first-child {
text-align: center;
}
.snarkFileName {
padding: 4px 0px !important;
text-align: left !important;
@ -526,6 +530,40 @@ a:hover {
font-weight: bold;
}
a.control, a.controld {
background: #989;
border: 1px inset #bbb;
border-radius: 4px;
color: #000;
font-weight: bold;
margin: 2px 4px;
padding: 3px 4px;
text-shadow: 0px 0px #410;
white-space: nowrap;
}
a.controld {
color: #444;
font-weight: normal;
}
a.controld img {
display: none;
}
a.control:hover {
background-color: #f60;
border: 1px outset #bbb;
color: #fff;
text-shadow: 0px 1px 5px #f00;
}
a.control:active {
background: #000 !important;
color: #f60 !important;
text-shadow: 0 !important;
}
input {
font-size: 8.5pt;
font-weight: bold;
@ -598,6 +636,14 @@ input[type=radio] {
input.default { width: 1px; height: 1px; visibility: hidden; }
input.disabled, input.disabled:hover {
background-color: #989;
border: 1px inset #bbb;
color: #444;
font-weight: normal;
text-shadow: 0px 0px 0px #444;
}
input.accept {
background: #989 url('../../console/images/accept.png') no-repeat 2px center;
padding: 2px 3px 2px 20px !important;

View File

@ -373,6 +373,10 @@ td:first-child {
width: 16px;
}
td.snarkFileIcon:first-child {
text-align: center;
}
.snarkFileName {
padding: 4px 0px !important;
text-align: left !important;
@ -543,6 +547,40 @@ a:hover {
font-weight: bold;
}
a.control, a.controld {
background: #fef url('images/bling.png') repeat-x scroll center center;
border: 1px inset #bbb;
border-radius: 4px;
color: #f30;
font-weight: bold;
margin: 2px 4px;
padding: 3px 4px;
text-shadow: 0px 0px #410;
white-space: nowrap;
}
a.controld {
color: #f60;
font-weight: normal;
}
a.controld img {
display: none;
}
a.control:hover {
background-color: #fef;
border: 1px outset #bbb;
color: #f60;
text-shadow: 0px 1px 5px #fdf;
}
a.control:active {
background: #000 !important;
color: #f60 !important;
text-shadow: 0 !important;
}
input {
font-size: 9pt;
font-weight: bold;
@ -612,6 +650,14 @@ input[type=radio] {
input.default { width: 1px; height: 1px; visibility: hidden; }
input.disabled, input.disabled:hover {
background-color: #989;
border: 1px inset #bbb;
color: #f60;
font-weight: normal;
text-shadow: 0px 0px 0px #410;
}
input.accept {
background: #f3efc7 url('../../console/images/accept.png') no-repeat 2px center;
padding: 2px 3px 2px 20px !important;

View File

@ -146,10 +146,10 @@ public class BuildRequestRecord {
return (_data.getData()[_data.getOffset() + OFF_FLAG] & FLAG_OUTBOUND_ENDPOINT) != 0;
}
/**
* Time that the request was sent, truncated to the nearest hour
* Time that the request was sent (ms), truncated to the nearest hour
*/
public long readRequestTime() {
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * 60l * 60l * 1000l;
return DataHelper.fromLong(_data.getData(), _data.getOffset() + OFF_REQ_TIME, 4) * (60 * 60 * 1000L);
}
/**
* What message ID should we send the request to the next hop with. If this is the outbound tunnel endpoint,
@ -250,6 +250,8 @@ public class BuildRequestRecord {
else if (isOutEndpoint)
buf[OFF_FLAG] |= FLAG_OUTBOUND_ENDPOINT;
long truncatedHour = ctx.clock().now();
// prevent hop identification at top of the hour
truncatedHour -= ctx.random().nextInt(90*1000);
truncatedHour /= (60l*60l*1000l);
DataHelper.toLong(buf, OFF_REQ_TIME, 4, truncatedHour);
DataHelper.toLong(buf, OFF_SEND_MSG_ID, 4, nextMsgId);

View File

@ -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;

View File

@ -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;
/**

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package net.i2p.data;
package net.i2p.data.router;
/*
* free (adj.): unencumbered; not under the control of others
@ -31,6 +31,13 @@ import net.i2p.crypto.SHA1;
import net.i2p.crypto.SHA1Hash;
import net.i2p.crypto.SHA256Generator;
import net.i2p.crypto.SigType;
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;
@ -47,6 +54,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 {
@ -190,7 +198,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);
}
}
}
@ -308,7 +316,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<Hash>) DataHelper.sortStructures(peers);
peers = (Collection<Hash>) SortHelper.sortStructures(peers);
for (Hash peerHash : peers) {
peerHash.writeBytes(out);
}

View File

@ -0,0 +1,224 @@
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.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SHA256Generator;
import net.i2p.data.Hash;
import net.i2p.data.RoutingKeyGenerator;
import net.i2p.util.HexDump;
import net.i2p.util.Log;
/**
* Component to manage the munging of hashes into routing keys - given a hash,
* perform some consistent transformation against it and return the result.
* This transformation is fed by the current "mod data".
*
* Right now the mod data is the current date (GMT) as a string: "yyyyMMdd",
* and the transformation takes the original hash, appends the bytes of that mod data,
* then returns the SHA256 of that concatenation.
*
* Do we want this to simply do the XOR of the SHA256 of the current mod data and
* the key? does that provide the randomization we need? It'd save an SHA256 op.
* Bah, too much effort to think about for so little gain. Other algorithms may come
* into play layer on about making periodic updates to the routing key for data elements
* to mess with Sybil. This may be good enough though.
*
* Also - the method generateDateBasedModData() should be called after midnight GMT
* once per day to generate the correct routing keys!
*
* @since 0.9.16 moved from net.i2p.data.RoutingKeyGenerator..
*
*/
public class RouterKeyGenerator extends RoutingKeyGenerator {
private final Log _log;
private final I2PAppContext _context;
public RouterKeyGenerator(I2PAppContext context) {
_log = context.logManager().getLog(RoutingKeyGenerator.class);
_context = context;
// ensure non-null mod data
generateDateBasedModData();
}
private volatile byte _currentModData[];
private volatile byte _nextModData[];
private volatile long _nextMidnight;
private volatile long _lastChanged;
private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
private static final String FORMAT = "yyyyMMdd";
private static final int LENGTH = FORMAT.length();
private final static SimpleDateFormat _fmt = new SimpleDateFormat(FORMAT, Locale.US);
static {
// make sure GMT is set, azi2phelper Vuze plugin is disabling static JVM TZ setting in Router.java
_fmt.setCalendar(_cal);
}
/**
* The current (today's) mod data.
* Warning - not a copy, do not corrupt.
*
* @return non-null, 8 bytes
*/
public byte[] getModData() {
return _currentModData;
}
/**
* Tomorrow's mod data.
* Warning - not a copy, do not corrupt.
* For debugging use only.
*
* @return non-null, 8 bytes
* @since 0.9.10
*/
public byte[] getNextModData() {
return _nextModData;
}
public long getLastChanged() {
return _lastChanged;
}
/**
* How long until midnight (ms)
*
* @return could be slightly negative
* @since 0.9.10 moved from UpdateRoutingKeyModifierJob
*/
public long getTimeTillMidnight() {
return _nextMidnight - _context.clock().now();
}
/**
* Set _cal to midnight for the time given.
* Caller must synch.
* @since 0.9.10
*/
private void setCalToPreviousMidnight(long now) {
_cal.setTime(new Date(now));
_cal.set(Calendar.YEAR, _cal.get(Calendar.YEAR)); // gcj <= 4.0 workaround
_cal.set(Calendar.DAY_OF_YEAR, _cal.get(Calendar.DAY_OF_YEAR)); // gcj <= 4.0 workaround
_cal.set(Calendar.HOUR_OF_DAY, 0);
_cal.set(Calendar.MINUTE, 0);
_cal.set(Calendar.SECOND, 0);
_cal.set(Calendar.MILLISECOND, 0);
}
/**
* Generate mod data from _cal.
* Caller must synch.
* @since 0.9.10
*/
private byte[] generateModDataFromCal() {
Date today = _cal.getTime();
String modVal = _fmt.format(today);
if (modVal.length() != LENGTH)
throw new IllegalStateException();
byte[] mod = new byte[LENGTH];
for (int i = 0; i < LENGTH; i++)
mod[i] = (byte)(modVal.charAt(i) & 0xFF);
return mod;
}
/**
* Update the current modifier data with some bytes derived from the current
* date (yyyyMMdd in GMT)
*
* @return true if changed
*/
public synchronized boolean generateDateBasedModData() {
long now = _context.clock().now();
setCalToPreviousMidnight(now);
byte[] mod = generateModDataFromCal();
boolean changed = !Arrays.equals(_currentModData, mod);
if (changed) {
// add a day and store next midnight and mod data for convenience
_cal.add(Calendar.DATE, 1);
_nextMidnight = _cal.getTime().getTime();
byte[] next = generateModDataFromCal();
_currentModData = mod;
_nextModData = next;
// ensure version is bumped
if (_lastChanged == now)
now++;
_lastChanged = now;
if (_log.shouldLog(Log.INFO))
_log.info("Routing modifier generated: " + HexDump.dump(mod));
}
return changed;
}
/**
* Generate a modified (yet consistent) hash from the origKey by generating the
* SHA256 of the targetKey with the current modData appended to it
*
* This makes Sybil's job a lot harder, as she needs to essentially take over the
* whole keyspace.
*
* @throws IllegalArgumentException if origKey is null
*/
public Hash getRoutingKey(Hash origKey) {
return getKey(origKey, _currentModData);
}
/**
* Get the routing key using tomorrow's modData, not today's
*
* @since 0.9.10
*/
public Hash getNextRoutingKey(Hash origKey) {
return getKey(origKey, _nextModData);
}
/**
* Generate a modified (yet consistent) hash from the origKey by generating the
* SHA256 of the targetKey with the specified modData appended to it
*
* @throws IllegalArgumentException if origKey is null
*/
private static Hash getKey(Hash origKey, byte[] modData) {
if (origKey == null) throw new IllegalArgumentException("Original key is null");
byte modVal[] = new byte[Hash.HASH_LENGTH + LENGTH];
System.arraycopy(origKey.getData(), 0, modVal, 0, Hash.HASH_LENGTH);
System.arraycopy(modData, 0, modVal, Hash.HASH_LENGTH, LENGTH);
return SHA256Generator.getInstance().calculateHash(modVal);
}
/****
public static void main(String args[]) {
Hash k1 = new Hash();
byte k1d[] = new byte[Hash.HASH_LENGTH];
RandomSource.getInstance().nextBytes(k1d);
k1.setData(k1d);
for (int i = 0; i < 10; i++) {
System.out.println("K1: " + k1);
Hash k1m = RoutingKeyGenerator.getInstance().getRoutingKey(k1);
System.out.println("MOD: " + new String(RoutingKeyGenerator.getInstance().getModData()));
System.out.println("K1M: " + k1m);
}
try {
Thread.sleep(2000);
} catch (Throwable t) { // nop
}
}
****/
}

View File

@ -0,0 +1,62 @@
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.Destination;
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);
// set it a Destination, so we may call validateKeyPairs()
// or other methods
dest = new Destination();
dest.setPublicKey(ri.getPublicKey());
dest.setSigningPublicKey(ri.getSigningPublicKey());
dest.setCertificate(ri.getCertificate());
dest.setPadding(ri.getPadding());
return ri;
} finally {
if (in != null) {
try { in.close(); } catch (IOException ioe) {}
}
}
}
}

View File

@ -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<? extends DataStructure> sortStructures(Collection<? extends DataStructure> 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<DataStructure> rv = new ArrayList(dataStructures.size());
//TreeMap<String, DataStructure> tm = new TreeMap();
//for (DataStructure struct : dataStructures) {
// tm.put(struct.calculateHash().toString(), struct);
//}
//for (DataStructure struct : tm.values()) {
// rv.add(struct);
//}
ArrayList<DataStructure> rv = new ArrayList<DataStructure>(dataStructures);
sortStructureList(rv);
return rv;
}
/**
* See above.
* DEPRECATED - Only used by RouterInfo.
*
* @since 0.9
*/
static void sortStructureList(List<? extends DataStructure> dataStructures) {
Collections.sort(dataStructures, new DataStructureComparator());
}
/**
* See sortStructures() comments.
* @since 0.8.3
*/
private static class DataStructureComparator implements Comparator<DataStructure>, Serializable {
public int compare(DataStructure l, DataStructure r) {
return l.calculateHash().toBase64().compareTo(r.calculateHash().toBase64());
}
}
}

View File

@ -0,0 +1,7 @@
<html>
<body>
<p>
Classes formerly in net.i2p.data but moved here as they are only used by the router.
</p>
</body>
</html>

View File

@ -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;

View File

@ -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,

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;

View File

@ -40,7 +40,7 @@ public class LeaseSetKeys {
/**
* Key with which a LeaseSet can be revoked (by republishing it with no Leases)
*
* @deprecated unused
* Deprecated, unused
*/
public SigningPrivateKey getRevocationKey() { return _revocationKey; }

View File

@ -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;
/**

View File

@ -14,9 +14,10 @@ import java.util.Collections;
import java.util.Set;
import net.i2p.data.DatabaseEntry;
import net.i2p.data.Destination;
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;
/**
@ -51,18 +52,51 @@ public abstract class NetworkDatabaseFacade implements Service {
public abstract LeaseSet lookupLeaseSetLocally(Hash key);
public abstract void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs);
public abstract RouterInfo lookupRouterInfoLocally(Hash key);
/**
* return the leaseSet if another leaseSet already existed at that key
* Lookup using the client's tunnels
* Succeeds even if LS validation fails due to unsupported sig type
*
* @param fromLocalDest use these tunnels for the lookup, or null for exploratory
* @since 0.9.16
*/
public abstract void lookupDestination(Hash key, Job onFinishedJob, long timeoutMs, Hash fromLocalDest);
/**
* Lookup locally in netDB and in badDest cache
* Succeeds even if LS validation failed due to unsupported sig type
*
* @since 0.9.16
*/
public abstract Destination lookupDestinationLocally(Hash key);
/**
* @return the leaseSet if another leaseSet already existed at that key
*
* @throws IllegalArgumentException if the data is not valid
*/
public abstract LeaseSet store(Hash key, LeaseSet leaseSet) throws IllegalArgumentException;
/**
* return the routerInfo if another router already existed at that key
* @return the routerInfo if another router already existed at that key
*
* @throws IllegalArgumentException if the data is not valid
*/
public abstract RouterInfo store(Hash key, RouterInfo routerInfo) throws IllegalArgumentException;
/**
* @return the old entry if it already existed at that key
* @throws IllegalArgumentException if the data is not valid
* @since 0.9.16
*/
public DatabaseEntry store(Hash key, DatabaseEntry entry) throws IllegalArgumentException {
if (entry.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO)
return store(key, (RouterInfo) entry);
if (entry.getType() == DatabaseEntry.KEY_TYPE_LEASESET)
return store(key, (LeaseSet) entry);
throw new IllegalArgumentException("unknown type");
}
/**
* @throws IllegalArgumentException if the local router is not valid
*/
@ -101,4 +135,12 @@ public abstract class NetworkDatabaseFacade implements Service {
* @since IPv6
*/
public boolean floodfillEnabled() { return false; };
/**
* Is it permanently negative cached?
*
* @param key only for Destinations; for RouterIdentities, see Banlist
* @since 0.9.16
*/
public boolean isNegativeCachedForever(Hash key) { return false; }
}

View File

@ -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;

View File

@ -70,9 +70,8 @@ public class PersistentKeyRing extends KeyRing {
Hash h = e.getKey();
buf.append(h.toBase64().substring(0, 6)).append("&hellip;");
buf.append("<td>");
LeaseSet ls = _ctx.netDb().lookupLeaseSetLocally(h);
if (ls != null) {
Destination dest = ls.getDestination();
Destination dest = _ctx.netDb().lookupDestinationLocally(h);
if (dest != null) {
if (_ctx.clientManager().isLocal(dest)) {
TunnelPoolSettings in = _ctx.tunnelManager().getInboundSettings(h);
if (in != null && in.getDestinationNickname() != null)

View File

@ -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";
@ -673,20 +670,6 @@ public class Router implements RouterClock.ClockShiftListener {
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
*/
@ -698,14 +681,16 @@ 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",
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?
"keyBackup/privateEncryption.key",
"keyBackup/privateSigning.key",
"keyBackup/publicEncryption.key",
"keyBackup/publicSigning.key",
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
};
@ -1085,7 +1070,7 @@ public class Router implements RouterClock.ClockShiftListener {
return;
_eventLog.addEvent(EventLog.CLOCK_SHIFT, Long.toString(delta));
// update the routing key modifier
_context.routingKeyGenerator().generateDateBasedModData();
_context.routerKeyGenerator().generateDateBasedModData();
if (_context.commSystem().countActivePeers() <= 0)
return;
if (delta > 0)

View File

@ -10,7 +10,9 @@ 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.RoutingKeyGenerator;
import net.i2p.data.router.RouterInfo;
import net.i2p.data.router.RouterKeyGenerator;
import net.i2p.internal.InternalClientManager;
import net.i2p.router.client.ClientManagerFacadeImpl;
import net.i2p.router.crypto.TransientSessionKeyManager;
@ -65,6 +67,7 @@ public class RouterContext extends I2PAppContext {
//private MessageStateMonitor _messageStateMonitor;
private RouterThrottle _throttle;
private RouterAppManager _appManager;
private RouterKeyGenerator _routingKeyGenerator;
private final Set<Runnable> _finalShutdownTasks;
// split up big lock on this to avoid deadlocks
private volatile boolean _initialized;
@ -183,6 +186,7 @@ public class RouterContext extends I2PAppContext {
_messageHistory = new MessageHistory(this);
_messageRegistry = new OutboundMessageRegistry(this);
//_messageStateMonitor = new MessageStateMonitor(this);
_routingKeyGenerator = new RouterKeyGenerator(this);
if (!getBooleanProperty("i2p.dummyNetDb"))
_netDb = new FloodfillNetworkDatabaseFacade(this); // new KademliaNetworkDatabaseFacade(this);
else
@ -582,4 +586,35 @@ public class RouterContext extends I2PAppContext {
_sessionKeyManagerInitialized = true;
}
}
/**
* Determine how much do we want to mess with the keys to turn them
* into something we can route. This is context specific because we
* may want to test out how things react when peers don't agree on
* how to skew.
*
* Returns same thing as routerKeyGenerator()
*
* @return non-null
* @since 0.9.16 Overrides I2PAppContext. Returns non-null in RouterContext and null in I2PAppcontext.
*/
@Override
public RoutingKeyGenerator routingKeyGenerator() {
return _routingKeyGenerator;
}
/**
* Determine how much do we want to mess with the keys to turn them
* into something we can route. This is context specific because we
* may want to test out how things react when peers don't agree on
* how to skew.
*
* Returns same thing as routingKeyGenerator()
*
* @return non-null
* @since 0.9.16
*/
public RouterKeyGenerator routerKeyGenerator() {
return _routingKeyGenerator;
}
}

Some files were not shown because too many files have changed in this diff Show More