diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index a532551f22..8bcf0050d8 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -19,6 +19,7 @@ import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.app.ClientAppManager;
import net.i2p.app.Outproxy;
+import net.i2p.crypto.Blinding;
import net.i2p.data.Certificate;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
@@ -552,6 +553,26 @@ public class IndexBean {
return d.toBase32();
return "";
}
+
+ /**
+ * Works even if tunnel is not running.
+ * @return "{56 chars}.b32.i2p" or "" if not blinded
+ * @since 0.9.40
+ */
+ public String getEncryptedBase32(int tunnel) {
+ Destination d = getDestination(tunnel);
+ if (d != null) {
+ int mode = _helper.getEncryptMode(tunnel);
+ if (mode > 1) {
+ try {
+ String secret = _helper.getBlindedPassword(tunnel);
+ boolean requireSecret = secret != null && secret.length() > 0;
+ return Blinding.encode(_context, d.getSigningPublicKey(), requireSecret, false);
+ } catch (RuntimeException re) {}
+ }
+ }
+ return "";
+ }
/**
* Works even if tunnel is not running.
diff --git a/apps/i2ptunnel/jsp/editServer.jsi b/apps/i2ptunnel/jsp/editServer.jsi
index 991595d63b..5fcecaf6f6 100644
--- a/apps/i2ptunnel/jsp/editServer.jsi
+++ b/apps/i2ptunnel/jsp/editServer.jsi
@@ -505,10 +505,10 @@
int curSigType = editBean.getSigType(curTunnel, tunnelType);
if (curSigType == 7 || curSigType == 11) {
%>
-
<%
if (editBean.isAdvanced()) {
// TODO, unimplemented
@@ -516,11 +516,11 @@
"> class="tickbox" />
<%=intl._t("Blinded with shared key")%>
"> class="tickbox" />
- <%=intl._t("Blinded with shared key and password")%>
+ <%=intl._t("Blinded with lookup password and shared key")%>
"> class="tickbox" />
<%=intl._t("Blinded with per-user key")%>
"> class="tickbox" />
- <%=intl._t("Blinded with shared password and per-user key")%>
+ <%=intl._t("Blinded with lookup password and per-user key")%>
<%
} // isAdvanced()
} // curSigType
@@ -553,7 +553,7 @@
%>
- <%=intl._t("Blinded Password")%>:
+ <%=intl._t("Optional lookup password")%>:
" value="<%=editBean.getBlindedPassword(curTunnel)%>" class="freetext password" />
| |
diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp
index 0b1b6df439..48f31c8dec 100644
--- a/apps/i2ptunnel/jsp/index.jsp
+++ b/apps/i2ptunnel/jsp/index.jsp
@@ -197,15 +197,29 @@
+ <%
+ String encName = indexBean.getEncryptedBase32(curServer);
+ if (encName != null && encName.length() > 0) {
+ %>
+
+
+ <%=intl._t("Encrypted")%>:
+ <%=encName%>
+ |
+
+ <%
+ } // encName
+ %>
+
- Description:
+ <%=intl._t("Description")%>:
<%=indexBean.getTunnelDescription(curServer)%>
|
<%
- }
+ } // for loop
%>
diff --git a/core/java/src/net/i2p/crypto/Blinding.java b/core/java/src/net/i2p/crypto/Blinding.java
index bb91214eba..1752f9897f 100644
--- a/core/java/src/net/i2p/crypto/Blinding.java
+++ b/core/java/src/net/i2p/crypto/Blinding.java
@@ -33,6 +33,10 @@ public final class Blinding {
private static final String INFO = "i2pblinding1";
private static final byte[] INFO_ALPHA = DataHelper.getASCII("I2PGenerateAlpha");
+ private static final byte FLAG_TWOBYTE = 0x01;
+ private static final byte FLAG_SECRET = 0x02;
+ private static final byte FLAG_AUTH = 0x04;
+
// following copied from RouterKeyGenerator
private static final String FORMAT = "yyyyMMdd";
private static final int LENGTH = FORMAT.length();
@@ -233,9 +237,9 @@ public final class Blinding {
int flag = b[0] & 0xff;
if ((flag & 0xf8) != 0)
throw new IllegalArgumentException("Corrupt b32 or unsupported options");
- if ((flag & 0x01) != 0)
+ if ((flag & FLAG_TWOBYTE) != 0)
throw new IllegalArgumentException("Two byte sig types unsupported");
- if ((flag & 0x04) != 0)
+ if ((flag & FLAG_AUTH) != 0)
throw new IllegalArgumentException("Per-client auth unsupported");
// TODO two-byte sigtypes
int st1 = b[1] & 0xff;
@@ -258,13 +262,16 @@ public final class Blinding {
System.arraycopy(b, 3, spkData, 0, spkLen);
SigningPublicKey spk = new SigningPublicKey(sigt1, spkData);
String secret;
- if ((flag & 0x02) != 0) {
- if (4 + spkLen > b.length)
- throw new IllegalArgumentException("No secret data");
- int secLen = b[3 + spkLen] & 0xff;
- if (4 + spkLen + secLen != b.length)
- throw new IllegalArgumentException("Bad b32 length");
- secret = DataHelper.getUTF8(b, 4 + spkLen, secLen);
+ if ((flag & FLAG_SECRET) != 0) {
+ if (4 + spkLen > b.length) {
+ //throw new IllegalArgumentException("No secret data");
+ secret = null;
+ } else {
+ int secLen = b[3 + spkLen] & 0xff;
+ if (4 + spkLen + secLen != b.length)
+ throw new IllegalArgumentException("Bad b32 length");
+ secret = DataHelper.getUTF8(b, 4 + spkLen, secLen);
+ }
} else if (3 + spkLen != b.length) {
throw new IllegalArgumentException("b32 too long");
} else {
@@ -274,6 +281,33 @@ public final class Blinding {
return rv;
}
+ /**
+ * Encode a public key as a new-format b32 address.
+ * PRELIMINARY - Subject to change - see proposal 149
+ *
+ * @return (56 chars).b32.i2p
+ * @throws IllegalArgumentException on bad inputs
+ * @throws UnsupportedOperationException unless supported SigTypes
+ * @since 0.9.40
+ */
+ public static String encode(I2PAppContext ctx, SigningPublicKey key) throws RuntimeException {
+ return encode(ctx, key, false, false, null);
+ }
+
+ /**
+ * Encode a public key as a new-format b32 address.
+ * PRELIMINARY - Subject to change - see proposal 149
+ *
+ * @return (56 chars).b32.i2p
+ * @throws IllegalArgumentException on bad inputs
+ * @throws UnsupportedOperationException unless supported SigTypes
+ * @since 0.9.40
+ */
+ public static String encode(I2PAppContext ctx, SigningPublicKey key,
+ boolean requireSecret, boolean requireAuth) throws RuntimeException {
+ return encode(ctx, key, requireSecret, requireAuth, null);
+ }
+
/**
* Encode a public key as a new-format b32 address.
* PRELIMINARY - Subject to change - see proposal 149
@@ -284,7 +318,9 @@ public final class Blinding {
* @throws UnsupportedOperationException unless supported SigTypes
* @since 0.9.40
*/
- public static String encode(I2PAppContext ctx, SigningPublicKey key, String secret) throws RuntimeException {
+ public static String encode(I2PAppContext ctx, SigningPublicKey key,
+ boolean requireSecret, boolean requireAuth,
+ String secret) throws RuntimeException {
SigType type = key.getType();
if (type != TYPE && type != TYPER)
throw new UnsupportedOperationException();
@@ -303,8 +339,10 @@ public final class Blinding {
crc.update(b, 3, b.length - 3);
long check = crc.getValue();
// TODO two-byte sigtypes
- if (slen > 0)
- b[0] = 0x02;
+ if (slen > 0 || requireSecret)
+ b[0] = FLAG_SECRET;
+ if (requireAuth)
+ b[0] |= FLAG_AUTH;
b[1] = (byte) (type.getCode() & 0xff);
b[2] = (byte) (TYPER.getCode() & 0xff);
b[0] ^= (byte) check;