diff --git a/core/java/src/net/i2p/crypto/CryptoConstants.java b/core/java/src/net/i2p/crypto/CryptoConstants.java index 39807d688f..52422a7930 100644 --- a/core/java/src/net/i2p/crypto/CryptoConstants.java +++ b/core/java/src/net/i2p/crypto/CryptoConstants.java @@ -79,6 +79,11 @@ public class CryptoConstants { */ public static final DSAParameterSpec DSA_SHA1_SPEC = new DSAParameterSpec(dsap, dsaq, dsag); + /** + * @since 0.9.25 + */ + public static final ElGamalParameterSpec I2P_ELGAMAL_2048_SPEC = new ElGamalParameterSpec(elgp, elgg); + /** * This will be org.bouncycastle.jce.spec.ElgamalParameterSpec * if BC is available, otherwise it @@ -99,11 +104,11 @@ public class CryptoConstants { } catch (Exception e) { //System.out.println("BC ElG spec failed"); //e.printStackTrace(); - spec = new ElGamalParameterSpec(elgp, elgg); + spec = I2P_ELGAMAL_2048_SPEC; } } else { //System.out.println("BC not available"); - spec = new ElGamalParameterSpec(elgp, elgg); + spec = I2P_ELGAMAL_2048_SPEC; } ELGAMAL_2048_SPEC = spec; } diff --git a/core/java/src/net/i2p/crypto/EncType.java b/core/java/src/net/i2p/crypto/EncType.java index fc07d5d5a1..ca59e0267b 100644 --- a/core/java/src/net/i2p/crypto/EncType.java +++ b/core/java/src/net/i2p/crypto/EncType.java @@ -27,7 +27,7 @@ public enum EncType { * 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"), + ELGAMAL_2048(0, 256, 256, EncAlgo.ELGAMAL, "ElGamal/None/NoPadding", CryptoConstants.I2P_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"), diff --git a/core/java/src/net/i2p/crypto/elgamal/KeyFactory.java b/core/java/src/net/i2p/crypto/elgamal/KeyFactory.java new file mode 100644 index 0000000000..3779b6f617 --- /dev/null +++ b/core/java/src/net/i2p/crypto/elgamal/KeyFactory.java @@ -0,0 +1,88 @@ +package net.i2p.crypto.elgamal; + +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.spec.DHParameterSpec; + +import static net.i2p.crypto.CryptoConstants.I2P_ELGAMAL_2048_SPEC; +import net.i2p.crypto.elgamal.impl.ElGamalPrivateKeyImpl; +import net.i2p.crypto.elgamal.impl.ElGamalPrivateKeyImpl; +import net.i2p.crypto.elgamal.impl.ElGamalPublicKeyImpl; +import net.i2p.crypto.elgamal.spec.ElGamalParameterSpec; +import net.i2p.crypto.elgamal.spec.ElGamalPrivateKeySpec; +import net.i2p.crypto.elgamal.spec.ElGamalPublicKeySpec; + +/** + * Modified from eddsa + * + * @since 0.9.25 + */ +public class KeyFactory extends KeyFactorySpi { + + /** + * Supports PKCS8EncodedKeySpec + */ + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec instanceof ElGamalPrivateKeySpec) { + return new ElGamalPrivateKeyImpl((ElGamalPrivateKeySpec) keySpec); + } + if (keySpec instanceof PKCS8EncodedKeySpec) { + return new ElGamalPrivateKeyImpl((PKCS8EncodedKeySpec) keySpec); + } + throw new InvalidKeySpecException("key spec not recognised"); + } + + /** + * Supports X509EncodedKeySpec + */ + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException { + if (keySpec instanceof ElGamalPublicKeySpec) { + return new ElGamalPublicKeyImpl((ElGamalPublicKeySpec) keySpec); + } + if (keySpec instanceof X509EncodedKeySpec) { + return new ElGamalPublicKeyImpl((X509EncodedKeySpec) keySpec); + } + throw new InvalidKeySpecException("key spec not recognised"); + } + + @SuppressWarnings("unchecked") + protected T engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException { + if (keySpec.isAssignableFrom(ElGamalPublicKeySpec.class) && key instanceof ElGamalPublicKey) { + ElGamalPublicKey k = (ElGamalPublicKey) key; + // key.getParams() is a DHParameterSpec + DHParameterSpec dhp = k.getParams(); + if (dhp != null) { + if (dhp.getP().equals(I2P_ELGAMAL_2048_SPEC.getP()) && + dhp.getG().equals(I2P_ELGAMAL_2048_SPEC.getG())) + return (T) new ElGamalPrivateKeySpec(k.getY(), I2P_ELGAMAL_2048_SPEC); + return (T) new ElGamalPrivateKeySpec(k.getY(), new ElGamalParameterSpec(dhp.getP(), dhp.getG())); + } + } else if (keySpec.isAssignableFrom(ElGamalPrivateKeySpec.class) && key instanceof ElGamalPrivateKey) { + ElGamalPrivateKey k = (ElGamalPrivateKey) key; + // key.getParams() is a DHParameterSpec + DHParameterSpec dhp = k.getParams(); + if (dhp != null) { + if (dhp.getP().equals(I2P_ELGAMAL_2048_SPEC.getP()) && + dhp.getG().equals(I2P_ELGAMAL_2048_SPEC.getG())) + return (T) new ElGamalPrivateKeySpec(k.getX(), I2P_ELGAMAL_2048_SPEC); + return (T) new ElGamalPrivateKeySpec(k.getX(), new ElGamalParameterSpec(dhp.getP(), dhp.getG())); + } + } + throw new InvalidKeySpecException("not implemented yet " + key + " " + keySpec); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException { + throw new InvalidKeyException("No other ElGamal key providers known"); + } +} diff --git a/core/java/src/net/i2p/crypto/elgamal/KeyPairGenerator.java b/core/java/src/net/i2p/crypto/elgamal/KeyPairGenerator.java new file mode 100644 index 0000000000..46f0edcb41 --- /dev/null +++ b/core/java/src/net/i2p/crypto/elgamal/KeyPairGenerator.java @@ -0,0 +1,84 @@ +package net.i2p.crypto.elgamal; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGeneratorSpi; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import static net.i2p.crypto.CryptoConstants.I2P_ELGAMAL_2048_SPEC; +import net.i2p.crypto.KeyGenerator; +import net.i2p.crypto.elgamal.impl.ElGamalPrivateKeyImpl; +import net.i2p.crypto.elgamal.impl.ElGamalPublicKeyImpl; +import net.i2p.crypto.elgamal.spec.ElGamalGenParameterSpec; +import net.i2p.crypto.elgamal.spec.ElGamalParameterSpec; +import net.i2p.crypto.elgamal.spec.ElGamalPrivateKeySpec; +import net.i2p.crypto.elgamal.spec.ElGamalPublicKeySpec; +import net.i2p.data.PrivateKey; +import net.i2p.data.PublicKey; +import net.i2p.data.SimpleDataStructure; +import net.i2p.util.NativeBigInteger; +import net.i2p.util.RandomSource; + +/** + * Modified from eddsa + * Only supported strength is 2048 + * + * @since 0.9.25 + */ +public class KeyPairGenerator extends KeyPairGeneratorSpi { + // always long, don't use short key + private static final int DEFAULT_STRENGTH = 2048; + private ElGamalParameterSpec elgParams; + //private SecureRandom random; + private boolean initialized; + + /** + * @param strength must be 2048 + * @param random ignored + */ + public void initialize(int strength, SecureRandom random) { + if (strength != DEFAULT_STRENGTH) + throw new InvalidParameterException("unknown key type."); + elgParams = I2P_ELGAMAL_2048_SPEC; + try { + initialize(elgParams, random); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidParameterException("key type not configurable."); + } + } + + /** + * @param random ignored + */ + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { + if (params instanceof ElGamalParameterSpec) { + elgParams = (ElGamalParameterSpec) params; + if (!elgParams.equals(I2P_ELGAMAL_2048_SPEC)) + throw new InvalidAlgorithmParameterException("unsupported ElGamalParameterSpec"); + } else if (params instanceof ElGamalGenParameterSpec) { + ElGamalGenParameterSpec elgGPS = (ElGamalGenParameterSpec) params; + if (elgGPS.getPrimeSize() != DEFAULT_STRENGTH) + throw new InvalidAlgorithmParameterException("unsupported prime size"); + elgParams = I2P_ELGAMAL_2048_SPEC; + } else { + throw new InvalidAlgorithmParameterException("parameter object not a ElGamalParameterSpec"); + } + //this.random = random; + initialized = true; + } + + public KeyPair generateKeyPair() { + if (!initialized) + initialize(DEFAULT_STRENGTH, RandomSource.getInstance()); + KeyGenerator kg = KeyGenerator.getInstance(); + SimpleDataStructure[] keys = kg.generatePKIKeys(); + PublicKey pubKey = (PublicKey) keys[0]; + PrivateKey privKey = (PrivateKey) keys[1]; + ElGamalPublicKey epubKey = new ElGamalPublicKeyImpl(new NativeBigInteger(1, pubKey.getData()), elgParams); + ElGamalPrivateKey eprivKey = new ElGamalPrivateKeyImpl(new NativeBigInteger(1, privKey.getData()), elgParams); + return new KeyPair(epubKey, eprivKey); + } +} diff --git a/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPrivateKeyImpl.java b/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPrivateKeyImpl.java index a1cffce7e5..9ca3672ac7 100644 --- a/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPrivateKeyImpl.java +++ b/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPrivateKeyImpl.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; +import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.spec.DHParameterSpec; @@ -25,34 +26,50 @@ public class ElGamalPrivateKeyImpl { } - ElGamalPrivateKeyImpl( + public ElGamalPrivateKeyImpl( ElGamalPrivateKey key) { this.x = key.getX(); this.elSpec = key.getParameters(); } - ElGamalPrivateKeyImpl( + public ElGamalPrivateKeyImpl( DHPrivateKey key) { this.x = key.getX(); this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG()); } - ElGamalPrivateKeyImpl( + public ElGamalPrivateKeyImpl( ElGamalPrivateKeySpec spec) { this.x = spec.getX(); this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG()); } - ElGamalPrivateKeyImpl( + public ElGamalPrivateKeyImpl( DHPrivateKeySpec spec) { this.x = spec.getX(); this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG()); } + public ElGamalPrivateKeyImpl( + BigInteger x, + ElGamalParameterSpec elSpec) + { + this.x = x; + this.elSpec = elSpec; + } + + public ElGamalPrivateKeyImpl( + PKCS8EncodedKeySpec spec) + { + throw new UnsupportedOperationException("todo"); + //this.x = spec.getX(); + //this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG()); + } + public String getAlgorithm() { return "ElGamal"; diff --git a/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPublicKeyImpl.java b/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPublicKeyImpl.java index e43bb6d203..c5cf71dd83 100644 --- a/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPublicKeyImpl.java +++ b/core/java/src/net/i2p/crypto/elgamal/impl/ElGamalPublicKeyImpl.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; +import java.security.spec.X509EncodedKeySpec; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; @@ -21,41 +22,49 @@ public class ElGamalPublicKeyImpl private BigInteger y; private ElGamalParameterSpec elSpec; - ElGamalPublicKeyImpl( + public ElGamalPublicKeyImpl( ElGamalPublicKeySpec spec) { this.y = spec.getY(); this.elSpec = new ElGamalParameterSpec(spec.getParams().getP(), spec.getParams().getG()); } - ElGamalPublicKeyImpl( + public ElGamalPublicKeyImpl( DHPublicKeySpec spec) { this.y = spec.getY(); this.elSpec = new ElGamalParameterSpec(spec.getP(), spec.getG()); } - ElGamalPublicKeyImpl( + public ElGamalPublicKeyImpl( ElGamalPublicKey key) { this.y = key.getY(); this.elSpec = key.getParameters(); } - ElGamalPublicKeyImpl( + public ElGamalPublicKeyImpl( DHPublicKey key) { this.y = key.getY(); this.elSpec = new ElGamalParameterSpec(key.getParams().getP(), key.getParams().getG()); } - ElGamalPublicKeyImpl( + public ElGamalPublicKeyImpl( BigInteger y, ElGamalParameterSpec elSpec) { this.y = y; this.elSpec = elSpec; } + + public ElGamalPublicKeyImpl( + X509EncodedKeySpec spec) + { + throw new UnsupportedOperationException("todo"); + //this.y = y; + //this.elSpec = elSpec; + } public String getAlgorithm() {