diff --git a/core/java/src/net/i2p/crypto/KeyGenerator.java b/core/java/src/net/i2p/crypto/KeyGenerator.java index c6d459cfc..54b45055c 100644 --- a/core/java/src/net/i2p/crypto/KeyGenerator.java +++ b/core/java/src/net/i2p/crypto/KeyGenerator.java @@ -20,6 +20,7 @@ import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; import net.i2p.data.SimpleDataStructure; import net.i2p.util.NativeBigInteger; +import net.i2p.util.SystemVersion; /** Define a way of generating asymmetrical key pairs as well as symmetrical keys * @author jrandom @@ -79,7 +80,35 @@ public class KeyGenerator { * (damn commercial access to http://www.springerlink.com/(xrkdvv45w0cmnur4aimsxx55)/app/home/contribution.asp?referrer=parent&backto=issue,13,31;journal,893,3280;linkingpublicationresults,1:105633,1 ) */ private static final int PUBKEY_EXPONENT_SIZE_SHORT = 226; - public static final int PUBKEY_EXPONENT_SIZE = PUBKEY_EXPONENT_SIZE_SHORT; + + /** @since 0.9.8 */ + private static final boolean DEFAULT_USE_LONG_EXPONENT = + NativeBigInteger.isNative() && + SystemVersion.is64Bit() && + !SystemVersion.isGNU() && + !SystemVersion.isApache() && + !SystemVersion.isARM(); + + /** + * @deprecated use getElGamalExponentSize() which allows override in the properties + */ + public static final int PUBKEY_EXPONENT_SIZE = DEFAULT_USE_LONG_EXPONENT ? + PUBKEY_EXPONENT_SIZE_FULL : + PUBKEY_EXPONENT_SIZE_SHORT; + + private static final String PROP_LONG_EXPONENT = "crypto.elGamal.useLongKey"; + + /** @since 0.9.8 */ + public boolean useLongElGamalExponent() { + return _context.getProperty(PROP_LONG_EXPONENT, DEFAULT_USE_LONG_EXPONENT); + } + + /** @since 0.9.8 */ + public int getElGamalExponentSize() { + return useLongElGamalExponent() ? + PUBKEY_EXPONENT_SIZE_FULL : + PUBKEY_EXPONENT_SIZE_SHORT; + } /** Generate a pair of keys, where index 0 is a PublicKey, and * index 1 is a PrivateKey @@ -94,7 +123,7 @@ public class KeyGenerator { * @since 0.8.7 */ public SimpleDataStructure[] generatePKIKeys() { - BigInteger a = new NativeBigInteger(PUBKEY_EXPONENT_SIZE, _context.random()); + BigInteger a = new NativeBigInteger(getElGamalExponentSize(), _context.random()); BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp); SimpleDataStructure[] keys = new SimpleDataStructure[2]; diff --git a/core/java/src/net/i2p/crypto/YKGenerator.java b/core/java/src/net/i2p/crypto/YKGenerator.java index 3b23c4df5..2832f3c92 100644 --- a/core/java/src/net/i2p/crypto/YKGenerator.java +++ b/core/java/src/net/i2p/crypto/YKGenerator.java @@ -119,7 +119,7 @@ class YKGenerator { //long t1 = 0; while (k == null) { //t0 = Clock.getInstance().now(); - k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, ctx.random()); + k = new NativeBigInteger(ctx.keyGenerator().getElGamalExponentSize(), ctx.random()); //t1 = Clock.getInstance().now(); if (BigInteger.ZERO.compareTo(k) == 0) { k = null; diff --git a/core/java/src/net/i2p/util/NativeBigInteger.java b/core/java/src/net/i2p/util/NativeBigInteger.java index c84ebf059..9c7f9b2c6 100644 --- a/core/java/src/net/i2p/util/NativeBigInteger.java +++ b/core/java/src/net/i2p/util/NativeBigInteger.java @@ -184,7 +184,7 @@ public class NativeBigInteger extends BigInteger { private static final boolean _isX86 = System.getProperty("os.arch").contains("86") || System.getProperty("os.arch").equals("amd64"); - private static final boolean _isArm = System.getProperty("os.arch").startsWith("arm"); + private static final boolean _isArm = SystemVersion.isARM(); private static final boolean _isPPC = System.getProperty("os.arch").contains("ppc"); diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java index eaca96e62..80114d0a7 100644 --- a/core/java/src/net/i2p/util/SystemVersion.java +++ b/core/java/src/net/i2p/util/SystemVersion.java @@ -15,6 +15,7 @@ public abstract class SystemVersion { private static final boolean _isWin = System.getProperty("os.name").startsWith("Win"); private static final boolean _isMac = System.getProperty("os.name").startsWith("Mac"); + private static final boolean _isArm = System.getProperty("os.arch").startsWith("arm"); private static final boolean _isAndroid; private static final boolean _isApache; private static final boolean _isGNU; @@ -86,6 +87,13 @@ public abstract class SystemVersion { return _isGNU; } + /** + * @since 0.9.8 + */ + public static boolean isARM() { + return _isArm; + } + /** * Better than (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0 * as it handles Android also, where java.version = "0". diff --git a/history.txt b/history.txt index 0bd5d3741..6dccaaccf 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,7 @@ +2013-09-07 zzz + * Crypto: Don't use "short exponent" on faster platforms. + Rebuild router identity if key length doesn't match setting. + 2013-09-03 zzz * configui: Change pw restart warning to error so people dont miss it * Data: deprecate most of LeaseSetKeys diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 0bd65feeb..7f0b07e77 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 23; + public final static long BUILD = 24; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java index e937cca8c..76b07cb1c 100644 --- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java @@ -14,6 +14,7 @@ import java.io.FileInputStream; import java.io.InputStream; import java.io.IOException; +import net.i2p.crypto.KeyGenerator; import net.i2p.data.DataFormatException; import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; @@ -91,6 +92,14 @@ public class LoadRouterInfoJob extends JobImpl { fis2 = new BufferedInputStream(new FileInputStream(rkf)); PrivateKey privkey = new PrivateKey(); privkey.readBytes(fis2); + if (shouldRebuild(privkey)) { + _us = null; + rif.delete(); + rkf.delete(); + _infoExists = false; + _keysExist = false; + return; + } SigningPrivateKey signingPrivKey = new SigningPrivateKey(); signingPrivKey.readBytes(fis2); PublicKey pubkey = new PublicKey(); @@ -119,4 +128,29 @@ public class LoadRouterInfoJob extends JobImpl { if (fis2 != null) try { fis2.close(); } catch (IOException ioe) {} } } + + /** + * Does our RI private key length match the configuration? + * If not, return true. + * @since 0.9.8 + */ + private boolean shouldRebuild(PrivateKey privkey) { + byte[] pkd = privkey.getData(); + boolean haslong = false; + for (int i = 0; i < 8; i++) { + if (pkd[i] != 0) { + haslong = true; + break; + } + } + boolean uselong = getContext().keyGenerator().useLongElGamalExponent(); + // transition to a longer key (update to 0.9.8) + if (uselong && !haslong) + _log.logAlways(Log.WARN, "Rebuilding RouterInfo with longer key"); + // transition to a shorter key, should be rare (copy files to different hardware, + // jbigi broke, user overrides in advanced config, ...) + if (!uselong && haslong) + _log.logAlways(Log.WARN, "Rebuilding RouterInfo with faster key"); + return uselong != haslong; + } } diff --git a/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java b/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java index 36911b67a..72d3097c8 100644 --- a/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java +++ b/router/java/src/net/i2p/router/transport/crypto/DHSessionKeyBuilder.java @@ -71,7 +71,7 @@ public class DHSessionKeyBuilder { * Others should get instances from PrecalcRunner.getBuilder() */ DHSessionKeyBuilder() { - this(RandomSource.getInstance()); + this(I2PAppContext.getGlobalContext()); } /** @@ -79,8 +79,8 @@ public class DHSessionKeyBuilder { * Only for internal use and unit tests. * Others should get instances from PrecalcRunner.getBuilder() */ - DHSessionKeyBuilder(RandomSource random) { - _myPrivateValue = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, random); + DHSessionKeyBuilder(I2PAppContext ctx) { + _myPrivateValue = new NativeBigInteger(ctx.keyGenerator().getElGamalExponentSize(), ctx.random()); _myPublicValue = CryptoConstants.elgg.modPow(_myPrivateValue, CryptoConstants.elgp); _extraExchangedBytes = new ByteArray(); } @@ -547,7 +547,7 @@ public class DHSessionKeyBuilder { private DHSessionKeyBuilder precalc() { long start = System.currentTimeMillis(); - DHSessionKeyBuilder builder = new DHSessionKeyBuilder(_context.random()); + DHSessionKeyBuilder builder = new DHSessionKeyBuilder(_context); long end = System.currentTimeMillis(); long diff = end - start; _context.statManager().addRateData("crypto.dhGeneratePublicTime", diff, diff);