forked from I2P_Developers/i2p.i2p
Router: Checks for new enc types
- Prevent encrypted lookups or stores - Prevent participting in our tunnels - Handle padding - Checks in crypto classes
This commit is contained in:
@ -119,6 +119,9 @@ public final class ElGamalEngine {
|
||||
if ((data == null) || (data.length > ELG_CLEARTEXT_LENGTH))
|
||||
throw new IllegalArgumentException("Data to encrypt must be <= 222 bytes");
|
||||
if (publicKey == null) throw new IllegalArgumentException("Null public key specified");
|
||||
EncType type = publicKey.getType();
|
||||
if (type != EncType.ELGAMAL_2048)
|
||||
throw new IllegalArgumentException("Bad public key type " + type);
|
||||
|
||||
long start = _context.clock().now();
|
||||
|
||||
@ -193,6 +196,9 @@ public final class ElGamalEngine {
|
||||
* @return unencrypted data or null on failure
|
||||
*/
|
||||
public byte[] decrypt(byte encrypted[], PrivateKey privateKey) {
|
||||
EncType type = privateKey.getType();
|
||||
if (type != EncType.ELGAMAL_2048)
|
||||
throw new IllegalArgumentException("Bad private key type " + type);
|
||||
if ((encrypted == null) || (encrypted.length != ELG_ENCRYPTED_LENGTH))
|
||||
throw new IllegalArgumentException("Data to decrypt must be exactly ELG_ENCRYPTED_LENGTH bytes");
|
||||
long start = _context.clock().now();
|
||||
|
@ -11,7 +11,7 @@ import net.i2p.data.Hash;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
|
||||
/**
|
||||
* PRELIMINARY - unused - subject to change
|
||||
* PRELIMINARY - subject to change
|
||||
*
|
||||
* Defines the properties for various encryption types
|
||||
* that I2P supports or may someday support.
|
||||
@ -33,18 +33,21 @@ public enum EncType {
|
||||
/**
|
||||
* Used by i2pd. Not yet supported by Java I2P.
|
||||
* Pubkey 64 bytes; privkey 32 bytes.
|
||||
* See proposal 145.
|
||||
*/
|
||||
EC_P256(1, 64, 32, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P256_SPEC, "0.9.38"),
|
||||
|
||||
/**
|
||||
* Reserved, not used by anybody.
|
||||
* Pubkey 96 bytes; privkey 48 bytes.
|
||||
* See proposal 145.
|
||||
*/
|
||||
EC_P384(2, 96, 48, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P384_SPEC, "0.9.38"),
|
||||
|
||||
/**
|
||||
* Reserved, not used by anybody.
|
||||
* Pubkey 132 bytes; privkey 66 bytes.
|
||||
* See proposal 145.
|
||||
*/
|
||||
EC_P521(3, 132, 66, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P521_SPEC, "0.9.38"),
|
||||
|
||||
@ -56,8 +59,6 @@ public enum EncType {
|
||||
ECIES_X25519(4, 32, 32, EncAlgo.ECIES, "EC/None/NoPadding", X25519_SPEC, "0.9.38");
|
||||
|
||||
|
||||
|
||||
|
||||
private final int code, pubkeyLen, privkeyLen;
|
||||
private final EncAlgo base;
|
||||
private final String algoName, since;
|
||||
@ -71,6 +72,8 @@ public enum EncType {
|
||||
*/
|
||||
EncType(int cod, int pubLen, int privLen, EncAlgo baseAlgo,
|
||||
String transformation, AlgorithmParameterSpec pSpec, String supportedSince) {
|
||||
if (pubLen > 256)
|
||||
throw new IllegalArgumentException("fixup PublicKey for longer keys");
|
||||
code = cod;
|
||||
pubkeyLen = pubLen;
|
||||
privkeyLen = privLen;
|
||||
|
@ -60,8 +60,12 @@ public class Destination extends KeysAndCert {
|
||||
byte[] padding;
|
||||
if (c.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
|
||||
// convert SPK to new SPK and padding
|
||||
// EncTypes 1-3 allowed in Destinations, see proposal 145
|
||||
KeyCertificate kcert = c.toKeyCertificate();
|
||||
padding = sk.getPadding(kcert);
|
||||
byte[] pad1 = pk.getPadding(kcert);
|
||||
byte[] pad2 = sk.getPadding(kcert);
|
||||
padding = combinePadding(pad1, pad2);
|
||||
pk = pk.toTypedKey(kcert);
|
||||
sk = sk.toTypedKey(kcert);
|
||||
c = kcert;
|
||||
} else {
|
||||
@ -70,7 +74,8 @@ public class Destination extends KeysAndCert {
|
||||
Destination rv;
|
||||
synchronized(_cache) {
|
||||
rv = _cache.get(sk);
|
||||
if (rv != null && rv.getPublicKey().equals(pk) && rv.getCertificate().equals(c)) {
|
||||
if (rv != null && rv.getPublicKey().equals(pk) && rv.getCertificate().equals(c) &&
|
||||
DataHelper.eq(rv.getPadding(), padding)) {
|
||||
//if (STATS)
|
||||
// I2PAppContext.getGlobalContext().statManager().addRateData("DestCache", 1);
|
||||
return rv;
|
||||
@ -97,6 +102,11 @@ public class Destination extends KeysAndCert {
|
||||
* @since 0.9.9
|
||||
*/
|
||||
private Destination(PublicKey pk, SigningPublicKey sk, Certificate c, byte[] padding) {
|
||||
if (padding != null) {
|
||||
int sz = pk.length() + sk.length() + padding.length;
|
||||
if (sz != 384)
|
||||
throw new IllegalArgumentException("bad total length " + sz);
|
||||
}
|
||||
_publicKey = pk;
|
||||
_signingKey = sk;
|
||||
_certificate = c;
|
||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.crypto.EncType;
|
||||
import net.i2p.crypto.SigType;
|
||||
|
||||
/**
|
||||
@ -147,6 +148,14 @@ public class KeyCertificate extends Certificate {
|
||||
return SigType.getByCode(getSigTypeCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if unset or unknown
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public EncType getEncType() {
|
||||
return EncType.getByCode(getCryptoTypeCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Signing Key extra data, if any, is first in the array.
|
||||
* Crypto Key extra data, if any, is second in the array,
|
||||
|
@ -15,6 +15,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.i2p.crypto.EncType;
|
||||
import net.i2p.crypto.SHA256Generator;
|
||||
import net.i2p.crypto.SigType;
|
||||
|
||||
@ -68,6 +69,22 @@ public class KeysAndCert extends DataStructureImpl {
|
||||
return SigType.DSA_SHA1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if not set or unknown
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public EncType getEncType() {
|
||||
if (_certificate == null)
|
||||
return null;
|
||||
if (_certificate.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
|
||||
try {
|
||||
KeyCertificate kcert = _certificate.toKeyCertificate();
|
||||
return kcert.getEncType();
|
||||
} catch (DataFormatException dfe) {}
|
||||
}
|
||||
return EncType.ELGAMAL_2048;
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() {
|
||||
return _publicKey;
|
||||
}
|
||||
@ -117,28 +134,48 @@ public class KeysAndCert extends DataStructureImpl {
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
if (_publicKey != null || _signingKey != null || _certificate != null)
|
||||
throw new IllegalStateException();
|
||||
_publicKey = PublicKey.create(in);
|
||||
PublicKey pk = PublicKey.create(in);
|
||||
SigningPublicKey spk = SigningPublicKey.create(in);
|
||||
Certificate cert = Certificate.create(in);
|
||||
Certificate cert = Certificate.create(in);
|
||||
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
|
||||
// convert SPK to new SPK and padding
|
||||
// convert PK and SPK to new PK and SPK and padding
|
||||
KeyCertificate kcert = cert.toKeyCertificate();
|
||||
_publicKey = pk.toTypedKey(kcert);
|
||||
_signingKey = spk.toTypedKey(kcert);
|
||||
_padding = spk.getPadding(kcert);
|
||||
byte[] pad1 = pk.getPadding(kcert);
|
||||
byte[] pad2 = spk.getPadding(kcert);
|
||||
_padding = combinePadding(pad1, pad2);
|
||||
_certificate = kcert;
|
||||
} else {
|
||||
_publicKey = pk;
|
||||
_signingKey = spk;
|
||||
_certificate = cert;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if both are null
|
||||
* @since 0.9.42
|
||||
*/
|
||||
protected static byte[] combinePadding(byte[] pad1, byte[] pad2) {
|
||||
if (pad1 == null)
|
||||
return pad2;
|
||||
if (pad2 == null)
|
||||
return pad1;
|
||||
byte[] rv = new byte[pad1.length + pad2.length];
|
||||
System.arraycopy(pad1, 0, rv, 0, pad1.length);
|
||||
System.arraycopy(pad2, 0, rv, pad1.length, pad2.length);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||
if ((_certificate == null) || (_publicKey == null) || (_signingKey == null))
|
||||
throw new DataFormatException("Not enough data to format the router identity");
|
||||
_publicKey.writeBytes(out);
|
||||
if (_padding != null)
|
||||
out.write(_padding);
|
||||
else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES)
|
||||
else if (_signingKey.length() < SigningPublicKey.KEYSIZE_BYTES ||
|
||||
_publicKey.length() < PublicKey.KEYSIZE_BYTES)
|
||||
throw new DataFormatException("No padding set");
|
||||
_signingKey.writeTruncatedBytes(out);
|
||||
_certificate.writeBytes(out);
|
||||
|
@ -11,6 +11,7 @@ package net.i2p.data;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.i2p.crypto.EncType;
|
||||
|
||||
@ -20,6 +21,7 @@ import net.i2p.crypto.EncType;
|
||||
* exponent, not the primes, which are constant and defined in the crypto spec.
|
||||
*
|
||||
* As of release 0.9.38, keys of arbitrary length and type are supported.
|
||||
* Note: Support for keys longer than 256 bytes unimplemented.
|
||||
* See EncType.
|
||||
*
|
||||
* @author jrandom
|
||||
@ -134,6 +136,63 @@ public class PublicKey extends SimpleDataStructure {
|
||||
return _unknownTypeCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Up-convert this from an untyped (type 0) PK to a typed PK based on the Key Cert given.
|
||||
* The type of the returned key will be null if the kcert sigtype is null.
|
||||
*
|
||||
* @throws IllegalArgumentException if this is already typed to a different type
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public PublicKey toTypedKey(KeyCertificate kcert) {
|
||||
if (_data == null)
|
||||
throw new IllegalStateException();
|
||||
EncType newType = kcert.getEncType();
|
||||
if (_type == newType)
|
||||
return this;
|
||||
if (_type != EncType.ELGAMAL_2048)
|
||||
throw new IllegalArgumentException("Cannot convert " + _type + " to " + newType);
|
||||
// unknown type, keep the 256 bytes of data
|
||||
if (newType == null)
|
||||
return new PublicKey(null, _data);
|
||||
int newLen = newType.getPubkeyLen();
|
||||
if (newLen == KEYSIZE_BYTES)
|
||||
return new PublicKey(newType, _data);
|
||||
byte[] newData = new byte[newLen];
|
||||
if (newLen < KEYSIZE_BYTES) {
|
||||
// LEFT justified, padding at end
|
||||
System.arraycopy(_data, 0, newData, 0, newLen);
|
||||
} else {
|
||||
// full 256 bytes + fragment in kcert
|
||||
throw new IllegalArgumentException("TODO");
|
||||
}
|
||||
return new PublicKey(newType, newData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the portion of this (type 0) PK that is really padding based on the Key Cert type given,
|
||||
* if any
|
||||
*
|
||||
* @return trailing padding length > 0 or null if no padding or type is unknown
|
||||
* @throws IllegalArgumentException if this is already typed to a different type
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public byte[] getPadding(KeyCertificate kcert) {
|
||||
if (_data == null)
|
||||
throw new IllegalStateException();
|
||||
EncType newType = kcert.getEncType();
|
||||
if (_type == newType || newType == null)
|
||||
return null;
|
||||
if (_type != EncType.ELGAMAL_2048)
|
||||
throw new IllegalStateException("Cannot convert " + _type + " to " + newType);
|
||||
int newLen = newType.getPubkeyLen();
|
||||
if (newLen >= KEYSIZE_BYTES)
|
||||
return null;
|
||||
int padLen = KEYSIZE_BYTES - newLen;
|
||||
byte[] pad = new byte[padLen];
|
||||
System.arraycopy(_data, _data.length - padLen, pad, 0, padLen);
|
||||
return pad;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.17
|
||||
*/
|
||||
@ -160,4 +219,23 @@ public class PublicKey extends SimpleDataStructure {
|
||||
buf.append(']');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.42
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return DataHelper.hashCode(_type) ^ super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.42
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || !(obj instanceof PublicKey)) return false;
|
||||
PublicKey s = (PublicKey) obj;
|
||||
return _type == s._type && Arrays.equals(_data, s._data);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user