diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java index fa108a0b8..e8bd2e49d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java @@ -294,19 +294,23 @@ public class EditBean extends IndexBean { * @since 0.9.18 */ public String getKey1(int tunnel) { - return _helper.getInboundRandomKey(tunnel); + String v = _helper.getInboundRandomKey(tunnel); + return encrypt(tunnel, "inbound.randomKey", v); } public String getKey2(int tunnel) { - return _helper.getOutboundRandomKey(tunnel); + String v = _helper.getOutboundRandomKey(tunnel); + return encrypt(tunnel, "outbound.randomKey", v); } public String getKey3(int tunnel) { - return _helper.getLeaseSetSigningPrivateKey(tunnel); + String v = _helper.getLeaseSetSigningPrivateKey(tunnel); + return encrypt(tunnel, "i2cp.leaseSetSigningPrivateKey", v); } public String getKey4(int tunnel) { - return _helper.getLeaseSetPrivateKey(tunnel); + String v = _helper.getLeaseSetPrivateKey(tunnel); + return encrypt(tunnel, "i2cp.leaseSetPrivateKey", v); } /** @since 0.8.9 */ 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 0d0425b5f..00cf3ec48 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -11,14 +11,17 @@ package net.i2p.i2ptunnel.web; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Properties; import net.i2p.I2PAppContext; import net.i2p.I2PException; import net.i2p.app.ClientAppManager; import net.i2p.app.Outproxy; +import net.i2p.crypto.ChaCha20; import net.i2p.crypto.Blinding; import net.i2p.data.Base64; import net.i2p.data.Certificate; @@ -78,6 +81,7 @@ public class IndexBean { /** store nonces in a static FIFO instead of in System Properties @since 0.8.1 */ private static final List _nonces = new ArrayList(MAX_NONCES + 1); private static final UIMessages _messages = new UIMessages(100); + private static final Map _formKeys = new HashMap(); private static final String PROP_THEME_NAME = "routerconsole.theme"; private static final String DEFAULT_THEME = "light"; @@ -1252,21 +1256,92 @@ public class IndexBean { * @since 0.9.18 */ public void setKey1(String s) { + s = decrypt("inbound.randomKey", s); _config.setInboundRandomKey(s); } public void setKey2(String s) { + s = decrypt("outbound.randomKey", s); _config.setOutboundRandomKey(s); } public void setKey3(String s) { + s = decrypt("i2cp.leaseSetSigningPrivateKey", s); _config.setLeaseSetSigningPrivateKey(s); } public void setKey4(String s) { + s = decrypt("i2cp.leaseSetPrivateKey", s); _config.setLeaseSetPrivateKey(s); } + /** + * Decrypt a property using an in-memory key, for + * interaction with the UI only, using ChaCha20. + * IV is SHA256(k). + * + * These are transient keys by design, but are persisted + * to hide restarts. They are hidden inputs in the edit form. + * Storage in config files is not encrypted. + * + * @param k non-null + * @param v Base64, or empty, or null + * @since 0.9.46 + */ + private String decrypt(String k, String v) { + if (v == null || v.length() <= 0) + return v; + byte[] enc = Base64.decode(v); + if (enc == null) + return null; + SessionKey key; + synchronized(_formKeys) { + key = _formKeys.get(Integer.valueOf(_tunnel)); + } + if (key == null) + return null; + byte[] kb = DataHelper.getUTF8(k); + byte[] iv = new byte[32]; + _context.sha().calculateHash(kb, 0, kb.length, iv, 0); + ChaCha20.decrypt(key.getData(), iv, enc, 0, enc, 0, enc.length); + return DataHelper.getUTF8(enc); + } + + /** + * Encrypt a property using an in-memory key, for + * interaction with the UI only, using ChaCha20. + * IV is SHA256(k). + * + * These are transient keys by design, but are persisted + * to hide restarts. They are hidden inputs in the edit form. + * Storage in config files is not encrypted. + * + * @param k non-null + * @param v may be empty or null + * @return Base64, or empty, or null + * @since 0.9.46 + */ + protected String encrypt(int tunnel, String k, String v) { + if (v == null || v.length() <= 0) + return v; + byte[] dec = DataHelper.getUTF8(v); + SessionKey key; + synchronized(_formKeys) { + key = _formKeys.get(Integer.valueOf(tunnel)); + if (key == null) { + byte[] keyb = new byte[32]; + _context.random().nextBytes(keyb); + key = new SessionKey(keyb); + _formKeys.put(Integer.valueOf(tunnel), key); + } + } + byte[] kb = DataHelper.getUTF8(k); + byte[] iv = new byte[32]; + _context.sha().calculateHash(kb, 0, kb.length, iv, 0); + ChaCha20.encrypt(key.getData(), iv, dec, 0, dec, 0, dec.length); + return Base64.encode(dec); + } + /** Modify or create a destination */ private String modifyDestination() { String privKeyFile = _config.getPrivKeyFile(); diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp index f21c6a53b..2ead27d2f 100644 --- a/apps/i2ptunnel/jsp/index.jsp +++ b/apps/i2ptunnel/jsp/index.jsp @@ -5,6 +5,7 @@ %> +<%-- must be set before key1-4 --%>