From 60017f7c552082e600248a55d8d64b86773205c0 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 17 Dec 2014 14:41:24 +0000 Subject: [PATCH] Crypto: Stubs for encryption key types --- .../src/net/i2p/crypto/CryptoConstants.java | 37 ++++ .../net/i2p/crypto/ElGamalParameterSpec.java | 66 +++++++ core/java/src/net/i2p/crypto/EncAlgo.java | 20 +++ core/java/src/net/i2p/crypto/EncType.java | 169 ++++++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 core/java/src/net/i2p/crypto/ElGamalParameterSpec.java create mode 100644 core/java/src/net/i2p/crypto/EncAlgo.java create mode 100644 core/java/src/net/i2p/crypto/EncType.java 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; + } + } + } +}