diff --git a/core/java/src/net/i2p/crypto/CryptoConstants.java b/core/java/src/net/i2p/crypto/CryptoConstants.java
index 21ebe3c1d..94facd366 100644
--- a/core/java/src/net/i2p/crypto/CryptoConstants.java
+++ b/core/java/src/net/i2p/crypto/CryptoConstants.java
@@ -29,7 +29,9 @@ package net.i2p.crypto;
* POSSIBILITY OF SUCH DAMAGE.
*/
+import java.lang.reflect.Constructor;
import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
import net.i2p.util.NativeBigInteger;
@@ -37,6 +39,9 @@ import net.i2p.util.NativeBigInteger;
/**
* Prime for ElGamal from http://tools.ietf.org/html/rfc3526
* Primes for DSA: Generated by TheCrypto http://article.gmane.org/gmane.comp.security.invisiblenet.iip.devel/343
+ *
+ * See also: ECConstants, RSAConstants
+ *
*/
public class CryptoConstants {
public static final BigInteger dsap = new NativeBigInteger(
@@ -52,6 +57,8 @@ public class CryptoConstants {
+ "985e43d136cdcfc6bd5409cd2f450821142a5e6f8eb1c3ab5d0484b8129fcf17bce4f7f3"
+ "3321c3cb3dbb14a905e7b2b3e93be4708cbcc82",
16);
+
+ /** 2048-bit MODP Group from RFC 3526 */
public static final BigInteger elgp = new NativeBigInteger("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
@@ -63,10 +70,40 @@ public class CryptoConstants {
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);
+
public static final BigInteger elgg = new NativeBigInteger("2");
/**
* @since 0.9.9
*/
public static final DSAParameterSpec DSA_SHA1_SPEC = new DSAParameterSpec(dsap, dsaq, dsag);
+
+ /**
+ * This will be org.bouncycastle.jce.spec.ElgamalParameterSpec
+ * if BC is available, otherwise it
+ * will be net.i2p.crypto.ElgamalParameterSpec
+ *
+ * @since 0.9.18
+ */
+ public static final AlgorithmParameterSpec ELGAMAL_2048_SPEC;
+
+ static {
+ AlgorithmParameterSpec spec;
+ if (ECConstants.isBCAvailable()) {
+ try {
+ Class> cls = Class.forName("org.bouncycastle.jce.spec.ElGamalParameterSpec");
+ Constructor> con = cls.getConstructor(new Class[] {BigInteger.class, BigInteger.class});
+ spec = (AlgorithmParameterSpec)con.newInstance(new Object[] {elgp, elgg});
+ //System.out.println("BC ElG spec loaded");
+ } catch (Exception e) {
+ //System.out.println("BC ElG spec failed");
+ //e.printStackTrace();
+ spec = new ElGamalParameterSpec(elgp, elgg);
+ }
+ } else {
+ //System.out.println("BC not available");
+ spec = new ElGamalParameterSpec(elgp, elgg);
+ }
+ ELGAMAL_2048_SPEC = spec;
+ }
}
diff --git a/core/java/src/net/i2p/crypto/ElGamalParameterSpec.java b/core/java/src/net/i2p/crypto/ElGamalParameterSpec.java
new file mode 100644
index 000000000..cee640804
--- /dev/null
+++ b/core/java/src/net/i2p/crypto/ElGamalParameterSpec.java
@@ -0,0 +1,66 @@
+package net.i2p.crypto;
+
+/*
+ * Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
+ * is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Copied from org.bouncycastle.jce.spec
+ * This can't actually be passed to the BC provider, we would have to
+ * use reflection to create a "real" org.bouncycasle.jce.spec.ElGamalParameterSpec.
+ *
+ * @since 0.9.18
+ */
+public class ElGamalParameterSpec implements AlgorithmParameterSpec {
+ private final BigInteger p;
+ private final BigInteger g;
+
+ /**
+ * Constructs a parameter set for Diffie-Hellman, using a prime modulus
+ * p and a base generator g.
+ *
+ * @param p the prime modulus
+ * @param g the base generator
+ */
+ public ElGamalParameterSpec(BigInteger p, BigInteger g) {
+ this.p = p;
+ this.g = g;
+ }
+
+ /**
+ * Returns the prime modulus p.
+ *
+ * @return the prime modulus p
+ */
+ public BigInteger getP() {
+ return p;
+ }
+
+ /**
+ * Returns the base generator g.
+ *
+ * @return the base generator g
+ */
+ public BigInteger getG() {
+ return g;
+ }
+}
diff --git a/core/java/src/net/i2p/crypto/EncAlgo.java b/core/java/src/net/i2p/crypto/EncAlgo.java
new file mode 100644
index 000000000..b6c21753f
--- /dev/null
+++ b/core/java/src/net/i2p/crypto/EncAlgo.java
@@ -0,0 +1,20 @@
+package net.i2p.crypto;
+
+/**
+ * Base encryption algorithm type
+ *
+ * @since 0.9.18
+ */
+public enum EncAlgo {
+
+ ELGAMAL("ElGamal"),
+ EC("EC");
+
+ private final String name;
+
+ EncAlgo(String name) {
+ this.name = name;
+ }
+
+ public String getName() { return name; }
+}
diff --git a/core/java/src/net/i2p/crypto/EncType.java b/core/java/src/net/i2p/crypto/EncType.java
new file mode 100644
index 000000000..ae5334859
--- /dev/null
+++ b/core/java/src/net/i2p/crypto/EncType.java
@@ -0,0 +1,169 @@
+package net.i2p.crypto;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import net.i2p.data.Hash;
+import net.i2p.data.SimpleDataStructure;
+
+/**
+ * Defines the properties for various signature types
+ * that I2P supports or may someday support.
+ *
+ * All Signatures, SigningPublicKeys, and SigningPrivateKeys have a type.
+ * Note that a EncType specifies both an algorithm and parameters, so that
+ * we may change primes or curves for a given algorithm.
+ *
+ * @since 0.9.18
+ */
+public enum EncType {
+ /**
+ * 2048-bit MODP Group from RFC 3526.
+ * This is the default.
+ * Pubkey 256 bytes, privkey 256 bytes.
+ */
+ ELGAMAL_2048(0, 256, 256, EncAlgo.ELGAMAL, "ElGamal/None/NoPadding", CryptoConstants.ELGAMAL_2048_SPEC, "0"),
+
+ /** Pubkey 64 bytes; privkey 32 bytes; */
+ EC_P256(1, 64, 32, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P256_SPEC, "0.9.20"),
+
+ /** Pubkey 96 bytes; privkey 48 bytes; */
+ EC_P384(2, 96, 48, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P384_SPEC, "0.9.20"),
+
+ /** Pubkey 132 bytes; privkey 66 bytes; */
+ EC_P521(3, 132, 66, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P521_SPEC, "0.9.20");
+
+
+
+
+ private final int code, pubkeyLen, privkeyLen;
+ private final EncAlgo base;
+ private final String algoName, since;
+ private final AlgorithmParameterSpec params;
+ private final boolean isAvail;
+
+ /**
+ *
+ * @param transformation algorithm/mode/padding
+ *
+ */
+ EncType(int cod, int pubLen, int privLen, EncAlgo baseAlgo,
+ String transformation, AlgorithmParameterSpec pSpec, String supportedSince) {
+ code = cod;
+ pubkeyLen = pubLen;
+ privkeyLen = privLen;
+ base = baseAlgo;
+ algoName = transformation;
+ params = pSpec;
+ since = supportedSince;
+ isAvail = x_isAvailable();
+ }
+
+ /** the unique identifier for this type */
+ public int getCode() { return code; }
+
+ /** the length of the public key, in bytes */
+ public int getPubkeyLen() { return pubkeyLen; }
+
+ /** the length of the private key, in bytes */
+ public int getPrivkeyLen() { return privkeyLen; }
+
+ /** the standard base algorithm name used for the Java crypto factories */
+ public EncAlgo getBaseAlgorithm() { return base; }
+
+ /** the standard name used for the Java crypto factories */
+ public String getAlgorithmName() { return algoName; }
+
+ /**
+ * The elliptic curve ECParameterSpec for ECDSA; DSAParameterSpec for DSA
+ * @throws InvalidParameterSpecException if the algorithm is not available on this JVM.
+ */
+ public AlgorithmParameterSpec getParams() throws InvalidParameterSpecException {
+ if (params == null)
+ throw new InvalidParameterSpecException(toString() + " is not available in this JVM");
+ return params;
+ }
+
+ /**
+ * The router version in which this type was first supported.
+ */
+ public String getSupportedSince() {
+ return since;
+ }
+
+ /**
+ * @return true if supported in this JVM
+ */
+ public boolean isAvailable() {
+ return isAvail;
+ }
+
+ private boolean x_isAvailable() {
+ if (ELGAMAL_2048 == this)
+ return true;
+ try {
+ getParams();
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return true if supported in this JVM
+ */
+ public static boolean isAvailable(int code) {
+ EncType type = getByCode(code);
+ if (type == null)
+ return false;
+ return type.isAvailable();
+ }
+
+ /**
+ * @param stype number or name
+ * @return true if supported in this JVM
+ */
+ public static boolean isAvailable(String stype) {
+ EncType type = parseEncType(stype);
+ if (type == null)
+ return false;
+ return type.isAvailable();
+ }
+
+ private static final Map BY_CODE = new HashMap();
+
+ static {
+ for (EncType type : EncType.values()) {
+ if (BY_CODE.put(Integer.valueOf(type.getCode()), type) != null)
+ throw new IllegalStateException("Duplicate EncType code");
+ }
+ }
+
+ /** @return null if not supported */
+ public static EncType getByCode(int code) {
+ return BY_CODE.get(Integer.valueOf(code));
+ }
+
+ /**
+ * Convenience for user apps
+ *
+ * @param stype number or name
+ * @return null if not found
+ */
+ public static EncType parseEncType(String stype) {
+ try {
+ String uc = stype.toUpperCase(Locale.US);
+ return valueOf(uc);
+ } catch (IllegalArgumentException iae) {
+ try {
+ int code = Integer.parseInt(stype);
+ return getByCode(code);
+ } catch (NumberFormatException nfe) {
+ return null;
+ }
+ }
+ }
+}