diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java
index 062ab73d5e..e3845df9da 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java
@@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
+import net.i2p.crypto.SigType;
import net.i2p.util.FileUtil;
import net.i2p.util.VersionComparator;
@@ -29,6 +30,17 @@ public class LogsHelper extends HelperBase {
return Server.getVersion();
}
+ /** @since 0.9.15 */
+ public String getUnavailableCrypto() {
+ StringBuilder buf = new StringBuilder(128);
+ for (SigType t : SigType.values()) {
+ if (!t.isAvailable()) {
+ buf.append("Crypto: ").append(t.toString()).append(" unavailable
");
+ }
+ }
+ return buf.toString();
+ }
+
/**
* Does not call logManager.flush(); call getCriticalLogs() first to flush
*/
diff --git a/apps/routerconsole/jsp/error500.jsp b/apps/routerconsole/jsp/error500.jsp
index 2a965fc617..70e82e9d2d 100644
--- a/apps/routerconsole/jsp/error500.jsp
+++ b/apps/routerconsole/jsp/error500.jsp
@@ -60,9 +60,10 @@
I2P version: <%=net.i2p.router.RouterVersion.FULL_VERSION%>
Java version: <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)
-Wrapper version: <%=System.getProperty("wrapper.version", "none")%>
" />
+
+Wrapper version: <%=System.getProperty("wrapper.version", "none")%>
Server version:
Servlet version: <%=getServletInfo()%>
Platform: <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%>
diff --git a/apps/routerconsole/jsp/logs.jsp b/apps/routerconsole/jsp/logs.jsp
index a028d9334c..99d518cbbd 100644
--- a/apps/routerconsole/jsp/logs.jsp
+++ b/apps/routerconsole/jsp/logs.jsp
@@ -24,16 +24,18 @@
I2P version: <%=net.i2p.router.RouterVersion.FULL_VERSION%>
Java version: <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)
-Wrapper version: <%=System.getProperty("wrapper.version", "none")%>
" />
+
+Wrapper version: <%=System.getProperty("wrapper.version", "none")%>
Server version:
Servlet version: <%=getServletInfo()%>
Platform: <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%>
Processor: <%=net.i2p.util.NativeBigInteger.cpuModel()%> (<%=net.i2p.util.NativeBigInteger.cpuType()%>)
Jbigi: <%=net.i2p.util.NativeBigInteger.loadStatus()%>
Encoding: <%=System.getProperty("file.encoding")%>
-Charset: <%=java.nio.charset.Charset.defaultCharset().name()%>
+Charset: <%=java.nio.charset.Charset.defaultCharset().name()%>
+
<%=intl._("Note that system information, log timestamps, and log messages may provide clues to your location; please review everything you include in a bug report.")%>
<%=intl._("Critical Logs")%>
diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java
index 6411058db9..6650cf4797 100644
--- a/core/java/src/net/i2p/util/SystemVersion.java
+++ b/core/java/src/net/i2p/util/SystemVersion.java
@@ -26,6 +26,7 @@ public abstract class SystemVersion {
private static final boolean _oneDotSix;
private static final boolean _oneDotSeven;
+ private static final boolean _oneDotEight;
private static final int _androidSDK;
static {
@@ -60,9 +61,11 @@ public abstract class SystemVersion {
if (_isAndroid) {
_oneDotSix = _androidSDK >= 9;
_oneDotSeven = _androidSDK >= 19;
+ _oneDotEight = false;
} else {
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
- _oneDotSeven = VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
+ _oneDotSeven = _oneDotSix && VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
+ _oneDotEight = _oneDotSeven && VersionComparator.comp(System.getProperty("java.version"), "1.8") >= 0;
}
}
@@ -127,6 +130,15 @@ public abstract class SystemVersion {
return _oneDotSeven;
}
+ /**
+ *
+ * @return true if Java 1.8 or higher, false for Android.
+ * @since 0.9.15
+ */
+ public static boolean isJava8() {
+ return _oneDotEight;
+ }
+
/**
* This isn't always correct.
* http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index f6eb8a907e..106efe00dd 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -317,6 +317,7 @@ public class Router implements RouterClock.ClockShiftListener {
if (f.exists())
SecureFileOutputStream.setPerms(f);
}
+ CryptoChecker.warnUnavailableCrypto(_context);
_routerInfo = null;
_higherVersionSeen = false;
diff --git a/router/java/src/net/i2p/router/tasks/CryptoChecker.java b/router/java/src/net/i2p/router/tasks/CryptoChecker.java
new file mode 100644
index 0000000000..a870e887a7
--- /dev/null
+++ b/router/java/src/net/i2p/router/tasks/CryptoChecker.java
@@ -0,0 +1,77 @@
+package net.i2p.router.tasks;
+
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+
+import net.i2p.crypto.SigType;
+import net.i2p.router.RouterContext;
+import net.i2p.util.Log;
+import net.i2p.util.SystemVersion;
+
+/**
+ * Warn about unavailable crypto to router and wrapper logs
+ *
+ * @since 0.9.15
+ */
+public class CryptoChecker {
+
+ private static String JRE6 = "http://www.oracle.com/technetwork/java/javase/downloads/index.html";
+ private static String JRE7 = "http://www.oracle.com/technetwork/java/javase/documentation/java-se-7-doc-download-435117.html";
+ private static String JRE8 = "http://www.oracle.com/technetwork/java/javase/documentation/jdk8-doc-downloads-2133158.html";
+
+ public static void warnUnavailableCrypto(RouterContext ctx) {
+ if (SystemVersion.isAndroid())
+ return;
+ boolean unavail = false;
+ Log log = null;
+ for (SigType t : SigType.values()) {
+ if (!t.isAvailable()) {
+ if (!unavail) {
+ unavail = true;
+ log = ctx.logManager().getLog(CryptoChecker.class);
+ }
+ String s = "Crypto " + t + " is not available";
+ log.logAlways(log.WARN, s);
+ System.out.println("Warning: " + s);
+ }
+ }
+ if (unavail) {
+ if (!SystemVersion.isJava7()) {
+ String s = "Java version: " + System.getProperty("java.version") + " Please consider upgrading to Java 7";
+ log.logAlways(log.WARN, s);
+ System.out.println(s);
+ }
+ if (!isUnlimited()) {
+ String s = "Please consider installing the Java Cryptography Unlimited Strength Jurisdiction Policy Files from ";
+ if (SystemVersion.isJava8())
+ s += JRE8;
+ else if (SystemVersion.isJava7())
+ s += JRE7;
+ else
+ s += JRE6;
+ log.logAlways(log.WARN, s);
+ System.out.println(s);
+ }
+ String s = "This crypto will be required in a future release";
+ log.logAlways(log.WARN, s);
+ System.out.println("Warning: " + s);
+ }
+ }
+
+ /**
+ * Following code adapted from Orchid
+ * According to http://www.subgraph.com/orchid.html ,
+ * "Orchid is licensed under a three-clause BSD license."
+ */
+ private static boolean isUnlimited() {
+ try {
+ if (Cipher.getMaxAllowedKeyLength("AES") < 256)
+ return false;
+ } catch (NoSuchAlgorithmException e) {
+ return false;
+ } catch (NoSuchMethodError e) {
+ }
+ return true;
+ }
+}
+