Crypto: Change X25519 key classes from Java keys to I2P keys,

in prep for new crypto (Proposal 144)
Add EncType
Fix PrivateKey constructor w/ EncType
Add support to KeyGenerator
This commit is contained in:
zzz
2018-11-30 15:15:31 +00:00
parent cc4da1b4da
commit 2487bca47c
12 changed files with 103 additions and 113 deletions

View File

@ -10,7 +10,10 @@ package net.i2p.crypto;
public enum EncAlgo { public enum EncAlgo {
ELGAMAL("ElGamal"), ELGAMAL("ElGamal"),
EC("EC"); EC("EC"),
/** @since 0.9.38 */
ECIES("ECIES");
private final String name; private final String name;

View File

@ -6,6 +6,7 @@ import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import static net.i2p.crypto.x25519.spec.X25519Spec.X25519_SPEC;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.SimpleDataStructure; import net.i2p.data.SimpleDataStructure;
@ -36,7 +37,13 @@ public enum EncType {
EC_P384(2, 96, 48, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P384_SPEC, "0.9.20"), EC_P384(2, 96, 48, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P384_SPEC, "0.9.20"),
/** Pubkey 132 bytes; privkey 66 bytes; */ /** Pubkey 132 bytes; privkey 66 bytes; */
EC_P521(3, 132, 66, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P521_SPEC, "0.9.20"); EC_P521(3, 132, 66, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P521_SPEC, "0.9.20"),
/**
* Pubkey 32 bytes; privkey 32 bytes
* @since 0.9.38
*/
ECIES_X25519(4, 32, 32, EncAlgo.ECIES, "EC/None/NoPadding", X25519_SPEC, "0.9.38");

View File

@ -31,6 +31,8 @@ import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import com.southernstorm.noise.crypto.x25519.Curve25519;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.crypto.eddsa.EdDSAPrivateKey; import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey; import net.i2p.crypto.eddsa.EdDSAPublicKey;
@ -173,20 +175,38 @@ public final class KeyGenerator {
return keys; return keys;
} }
/** Convert a PrivateKey to its corresponding PublicKey /**
* Convert a PrivateKey to its corresponding PublicKey.
* As of 0.9.38, supports EncTypes
*
* @param priv PrivateKey object * @param priv PrivateKey object
* @return the corresponding PublicKey object * @return the corresponding PublicKey object
* @throws IllegalArgumentException on bad key * @throws IllegalArgumentException on bad key
*/ */
public static PublicKey getPublicKey(PrivateKey priv) { public static PublicKey getPublicKey(PrivateKey priv) {
EncType type = priv.getType();
byte[] data;
switch (type) {
case ELGAMAL_2048:
BigInteger a = new NativeBigInteger(1, priv.toByteArray()); BigInteger a = new NativeBigInteger(1, priv.toByteArray());
BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp); BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp);
PublicKey pub = new PublicKey();
try { try {
pub.setData(SigUtil.rectify(aalpha, PublicKey.KEYSIZE_BYTES)); data = SigUtil.rectify(aalpha, PublicKey.KEYSIZE_BYTES);
} catch (InvalidKeyException ike) { } catch (InvalidKeyException ike) {
throw new IllegalArgumentException(ike); throw new IllegalArgumentException(ike);
} }
break;
case ECIES_X25519:
data = new byte[32];
Curve25519.eval(data, 0, priv.getData(), null);
break;
default:
throw new IllegalArgumentException("Unsupported algorithm");
}
PublicKey pub = new PublicKey(type, data);
return pub; return pub;
} }

View File

@ -0,0 +1,28 @@
package net.i2p.crypto;
import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey;
/**
* Same as java.security.KeyPair, but with I2P keys
*
* @since 0.9.38
*/
public class KeyPair {
private final PublicKey pub;
private final PrivateKey priv;
public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
pub = publicKey;
priv = privateKey;
}
public PublicKey getPublic() {
return pub;
}
public PrivateKey getPrivate() {
return priv;
}
}

View File

@ -0,0 +1,9 @@
package net.i2p.crypto.x25519.spec;
import java.security.spec.AlgorithmParameterSpec;
public class X25519Spec implements AlgorithmParameterSpec {
public static final X25519Spec X25519_SPEC = new X25519Spec();
}

View File

@ -0,0 +1,7 @@
<html><body>
<p>
AlgorithmParameterSpec for X25519.
</p><p>
Since 0.9.38.
</p>
</body></html>

View File

@ -53,8 +53,11 @@ public class PrivateKey extends SimpleDataStructure {
* @since 0.9.38 * @since 0.9.38
*/ */
public PrivateKey(EncType type, byte data[]) { public PrivateKey(EncType type, byte data[]) {
super(data); super();
_type = type; _type = type;
if (data == null)
throw new IllegalArgumentException("Data must be specified");
_data = data;
} }
/** constructs from base64 /** constructs from base64

View File

@ -22,11 +22,11 @@
package com.southernstorm.noise.protocol; package com.southernstorm.noise.protocol;
import java.security.KeyPair;
import java.util.Arrays; import java.util.Arrays;
import com.southernstorm.noise.crypto.x25519.Curve25519; import com.southernstorm.noise.crypto.x25519.Curve25519;
import net.i2p.crypto.KeyPair;
import net.i2p.router.transport.crypto.X25519KeyFactory; import net.i2p.router.transport.crypto.X25519KeyFactory;
/** /**
@ -78,8 +78,8 @@ class Curve25519DHState implements DHState {
@Override @Override
public void generateKeyPair() { public void generateKeyPair() {
KeyPair kp = _xdh.getKeys(); KeyPair kp = _xdh.getKeys();
System.arraycopy(kp.getPrivate().getEncoded(), 0, privateKey, 0, 32); System.arraycopy(kp.getPrivate().getData(), 0, privateKey, 0, 32);
System.arraycopy(kp.getPublic().getEncoded(), 0, publicKey, 0, 32); System.arraycopy(kp.getPublic().getData(), 0, publicKey, 0, 32);
mode = 0x03; mode = 0x03;
} }

View File

@ -1,11 +1,14 @@
package net.i2p.router.transport.crypto; package net.i2p.router.transport.crypto;
import java.security.KeyPair;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import com.southernstorm.noise.crypto.x25519.Curve25519; import com.southernstorm.noise.crypto.x25519.Curve25519;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.crypto.EncType;
import net.i2p.crypto.KeyPair;
import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.SystemVersion; import net.i2p.util.SystemVersion;
@ -133,7 +136,7 @@ public class X25519KeyFactory extends I2PThread {
} while (priv[31] == 0); } while (priv[31] == 0);
byte[] pub = new byte[32]; byte[] pub = new byte[32];
Curve25519.eval(pub, 0, priv, null); Curve25519.eval(pub, 0, priv, null);
KeyPair rv = new KeyPair(new X25519PublicKey(pub), new X25519PrivateKey(priv)); KeyPair rv = new KeyPair(new PublicKey(EncType.ECIES_X25519, pub), new PrivateKey(EncType.ECIES_X25519, priv));
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
long diff = end - start; long diff = end - start;
_context.statManager().addRateData("crypto.XDHGenerateTime", diff); _context.statManager().addRateData("crypto.XDHGenerateTime", diff);

View File

@ -1,50 +0,0 @@
package net.i2p.router.transport.crypto;
import java.security.PrivateKey;
import com.southernstorm.noise.crypto.x25519.Curve25519;
/**
* A PrivateKey we can stick in a KeyPair.
* Raw data is accessible via getEncoded().
* Also provides a toPublic() method.
*
* @since 0.9.36
*/
public class X25519PrivateKey implements PrivateKey {
private final byte[] _data;
/**
* Montgomery representation, little-endian
* @param data 32 bytes
* @throws IllegalArgumentException if not 32 bytes
*/
public X25519PrivateKey(byte[] data) {
if (data.length != 32)
throw new IllegalArgumentException();
_data = data;
}
public X25519PublicKey toPublic() {
byte[] pub = new byte[32];
Curve25519.eval(pub, 0, _data, null);
return new X25519PublicKey(pub);
}
/**
* The raw byte array, there is no encoding.
* @return the data passed in
*/
public byte[] getEncoded() {
return _data;
}
public String getAlgorithm() {
return "X25519";
}
public String getFormat() {
return "raw";
}
}

View File

@ -1,41 +0,0 @@
package net.i2p.router.transport.crypto;
import java.security.PublicKey;
/**
* A PublicKey we can stick in a KeyPair.
* Raw data is accessible via getEncoded().
*
* @since 0.9.36
*/
public class X25519PublicKey implements PublicKey {
private final byte[] _data;
/**
* Montgomery representation, little-endian
* @param data 32 bytes
* @throws IllegalArgumentException if not 32 bytes
*/
public X25519PublicKey(byte[] data) {
if (data.length != 32)
throw new IllegalArgumentException();
_data = data;
}
/**
* The raw byte array, there is no encoding.
* @return the data passed in
*/
public byte[] getEncoded() {
return _data;
}
public String getAlgorithm() {
return "X25519";
}
public String getFormat() {
return "raw";
}
}

View File

@ -8,7 +8,6 @@ import java.net.Inet6Address;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.security.KeyPair;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -27,11 +26,15 @@ import java.util.TreeSet;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import net.i2p.crypto.EncType;
import net.i2p.crypto.KeyPair;
import net.i2p.crypto.SigType; import net.i2p.crypto.SigType;
import net.i2p.data.Base64; import net.i2p.data.Base64;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
import net.i2p.data.PrivateKey;
import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterAddress;
import net.i2p.data.router.RouterIdentity; import net.i2p.data.router.RouterIdentity;
import net.i2p.data.router.RouterInfo; import net.i2p.data.router.RouterInfo;
@ -48,8 +51,6 @@ import net.i2p.router.transport.TransportUtil;
import static net.i2p.router.transport.TransportUtil.IPv6Config.*; import static net.i2p.router.transport.TransportUtil.IPv6Config.*;
import net.i2p.router.transport.crypto.DHSessionKeyBuilder; import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
import net.i2p.router.transport.crypto.X25519KeyFactory; import net.i2p.router.transport.crypto.X25519KeyFactory;
import net.i2p.router.transport.crypto.X25519PublicKey;
import net.i2p.router.transport.crypto.X25519PrivateKey;
import net.i2p.router.util.DecayingHashSet; import net.i2p.router.util.DecayingHashSet;
import net.i2p.router.util.DecayingBloomFilter; import net.i2p.router.util.DecayingBloomFilter;
import net.i2p.router.util.EventLog; import net.i2p.router.util.EventLog;
@ -257,12 +258,12 @@ public class NTCPTransport extends TransportImpl {
} }
if (priv == null || priv.length != NTCP2_KEY_LEN) { if (priv == null || priv.length != NTCP2_KEY_LEN) {
KeyPair keys = xdh.getKeys(); KeyPair keys = xdh.getKeys();
_ntcp2StaticPrivkey = keys.getPrivate().getEncoded(); _ntcp2StaticPrivkey = keys.getPrivate().getData();
_ntcp2StaticPubkey = keys.getPublic().getEncoded(); _ntcp2StaticPubkey = keys.getPublic().getData();
shouldSave = true; shouldSave = true;
} else { } else {
_ntcp2StaticPrivkey = priv; _ntcp2StaticPrivkey = priv;
_ntcp2StaticPubkey = (new X25519PrivateKey(priv)).toPublic().getEncoded(); _ntcp2StaticPubkey = (new PrivateKey(EncType.ECIES_X25519, priv)).toPublic().getData();
} }
if (!shouldSave) { if (!shouldSave) {
s = ctx.getProperty(PROP_NTCP2_IV); s = ctx.getProperty(PROP_NTCP2_IV);