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))
|
if ((data == null) || (data.length > ELG_CLEARTEXT_LENGTH))
|
||||||
throw new IllegalArgumentException("Data to encrypt must be <= 222 bytes");
|
throw new IllegalArgumentException("Data to encrypt must be <= 222 bytes");
|
||||||
if (publicKey == null) throw new IllegalArgumentException("Null public key specified");
|
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();
|
long start = _context.clock().now();
|
||||||
|
|
||||||
@ -193,6 +196,9 @@ public final class ElGamalEngine {
|
|||||||
* @return unencrypted data or null on failure
|
* @return unencrypted data or null on failure
|
||||||
*/
|
*/
|
||||||
public byte[] decrypt(byte encrypted[], PrivateKey privateKey) {
|
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))
|
if ((encrypted == null) || (encrypted.length != ELG_ENCRYPTED_LENGTH))
|
||||||
throw new IllegalArgumentException("Data to decrypt must be exactly ELG_ENCRYPTED_LENGTH bytes");
|
throw new IllegalArgumentException("Data to decrypt must be exactly ELG_ENCRYPTED_LENGTH bytes");
|
||||||
long start = _context.clock().now();
|
long start = _context.clock().now();
|
||||||
|
@ -11,7 +11,7 @@ import net.i2p.data.Hash;
|
|||||||
import net.i2p.data.SimpleDataStructure;
|
import net.i2p.data.SimpleDataStructure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PRELIMINARY - unused - subject to change
|
* PRELIMINARY - subject to change
|
||||||
*
|
*
|
||||||
* Defines the properties for various encryption types
|
* Defines the properties for various encryption types
|
||||||
* that I2P supports or may someday support.
|
* that I2P supports or may someday support.
|
||||||
@ -33,18 +33,21 @@ public enum EncType {
|
|||||||
/**
|
/**
|
||||||
* Used by i2pd. Not yet supported by Java I2P.
|
* Used by i2pd. Not yet supported by Java I2P.
|
||||||
* Pubkey 64 bytes; privkey 32 bytes.
|
* 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"),
|
EC_P256(1, 64, 32, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P256_SPEC, "0.9.38"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reserved, not used by anybody.
|
* Reserved, not used by anybody.
|
||||||
* Pubkey 96 bytes; privkey 48 bytes.
|
* 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"),
|
EC_P384(2, 96, 48, EncAlgo.EC, "EC/None/NoPadding", ECConstants.P384_SPEC, "0.9.38"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reserved, not used by anybody.
|
* Reserved, not used by anybody.
|
||||||
* Pubkey 132 bytes; privkey 66 bytes.
|
* 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"),
|
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");
|
ECIES_X25519(4, 32, 32, EncAlgo.ECIES, "EC/None/NoPadding", X25519_SPEC, "0.9.38");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private final int code, pubkeyLen, privkeyLen;
|
private final int code, pubkeyLen, privkeyLen;
|
||||||
private final EncAlgo base;
|
private final EncAlgo base;
|
||||||
private final String algoName, since;
|
private final String algoName, since;
|
||||||
@ -71,6 +72,8 @@ public enum EncType {
|
|||||||
*/
|
*/
|
||||||
EncType(int cod, int pubLen, int privLen, EncAlgo baseAlgo,
|
EncType(int cod, int pubLen, int privLen, EncAlgo baseAlgo,
|
||||||
String transformation, AlgorithmParameterSpec pSpec, String supportedSince) {
|
String transformation, AlgorithmParameterSpec pSpec, String supportedSince) {
|
||||||
|
if (pubLen > 256)
|
||||||
|
throw new IllegalArgumentException("fixup PublicKey for longer keys");
|
||||||
code = cod;
|
code = cod;
|
||||||
pubkeyLen = pubLen;
|
pubkeyLen = pubLen;
|
||||||
privkeyLen = privLen;
|
privkeyLen = privLen;
|
||||||
|
@ -60,8 +60,12 @@ public class Destination extends KeysAndCert {
|
|||||||
byte[] padding;
|
byte[] padding;
|
||||||
if (c.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
|
if (c.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
|
||||||
// convert SPK to new SPK and padding
|
// convert SPK to new SPK and padding
|
||||||
|
// EncTypes 1-3 allowed in Destinations, see proposal 145
|
||||||
KeyCertificate kcert = c.toKeyCertificate();
|
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);
|
sk = sk.toTypedKey(kcert);
|
||||||
c = kcert;
|
c = kcert;
|
||||||
} else {
|
} else {
|
||||||
@ -70,7 +74,8 @@ public class Destination extends KeysAndCert {
|
|||||||
Destination rv;
|
Destination rv;
|
||||||
synchronized(_cache) {
|
synchronized(_cache) {
|
||||||
rv = _cache.get(sk);
|
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)
|
//if (STATS)
|
||||||
// I2PAppContext.getGlobalContext().statManager().addRateData("DestCache", 1);
|
// I2PAppContext.getGlobalContext().statManager().addRateData("DestCache", 1);
|
||||||
return rv;
|
return rv;
|
||||||
@ -97,6 +102,11 @@ public class Destination extends KeysAndCert {
|
|||||||
* @since 0.9.9
|
* @since 0.9.9
|
||||||
*/
|
*/
|
||||||
private Destination(PublicKey pk, SigningPublicKey sk, Certificate c, byte[] padding) {
|
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;
|
_publicKey = pk;
|
||||||
_signingKey = sk;
|
_signingKey = sk;
|
||||||
_certificate = c;
|
_certificate = c;
|
||||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,6 +148,14 @@ public class KeyCertificate extends Certificate {
|
|||||||
return SigType.getByCode(getSigTypeCode());
|
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.
|
* Signing Key extra data, if any, is first in the array.
|
||||||
* Crypto Key extra data, if any, is second 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.io.OutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SHA256Generator;
|
import net.i2p.crypto.SHA256Generator;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
|
|
||||||
@ -68,6 +69,22 @@ public class KeysAndCert extends DataStructureImpl {
|
|||||||
return SigType.DSA_SHA1;
|
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() {
|
public PublicKey getPublicKey() {
|
||||||
return _publicKey;
|
return _publicKey;
|
||||||
}
|
}
|
||||||
@ -117,28 +134,48 @@ public class KeysAndCert extends DataStructureImpl {
|
|||||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||||
if (_publicKey != null || _signingKey != null || _certificate != null)
|
if (_publicKey != null || _signingKey != null || _certificate != null)
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
_publicKey = PublicKey.create(in);
|
PublicKey pk = PublicKey.create(in);
|
||||||
SigningPublicKey spk = SigningPublicKey.create(in);
|
SigningPublicKey spk = SigningPublicKey.create(in);
|
||||||
Certificate cert = Certificate.create(in);
|
Certificate cert = Certificate.create(in);
|
||||||
if (cert.getCertificateType() == Certificate.CERTIFICATE_TYPE_KEY) {
|
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();
|
KeyCertificate kcert = cert.toKeyCertificate();
|
||||||
|
_publicKey = pk.toTypedKey(kcert);
|
||||||
_signingKey = spk.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;
|
_certificate = kcert;
|
||||||
} else {
|
} else {
|
||||||
|
_publicKey = pk;
|
||||||
_signingKey = spk;
|
_signingKey = spk;
|
||||||
_certificate = cert;
|
_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 {
|
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
|
||||||
if ((_certificate == null) || (_publicKey == null) || (_signingKey == null))
|
if ((_certificate == null) || (_publicKey == null) || (_signingKey == null))
|
||||||
throw new DataFormatException("Not enough data to format the router identity");
|
throw new DataFormatException("Not enough data to format the router identity");
|
||||||
_publicKey.writeBytes(out);
|
_publicKey.writeBytes(out);
|
||||||
if (_padding != null)
|
if (_padding != null)
|
||||||
out.write(_padding);
|
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");
|
throw new DataFormatException("No padding set");
|
||||||
_signingKey.writeTruncatedBytes(out);
|
_signingKey.writeTruncatedBytes(out);
|
||||||
_certificate.writeBytes(out);
|
_certificate.writeBytes(out);
|
||||||
|
@ -11,6 +11,7 @@ package net.i2p.data;
|
|||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import net.i2p.crypto.EncType;
|
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.
|
* 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.
|
* 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.
|
* See EncType.
|
||||||
*
|
*
|
||||||
* @author jrandom
|
* @author jrandom
|
||||||
@ -134,6 +136,63 @@ public class PublicKey extends SimpleDataStructure {
|
|||||||
return _unknownTypeCode;
|
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
|
* @since 0.9.17
|
||||||
*/
|
*/
|
||||||
@ -160,4 +219,23 @@ public class PublicKey extends SimpleDataStructure {
|
|||||||
buf.append(']');
|
buf.append(']');
|
||||||
return buf.toString();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.crypto.AESEngine;
|
import net.i2p.crypto.AESEngine;
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
@ -97,6 +98,8 @@ public final class ElGamalAESEngine {
|
|||||||
_log.error("Data is less than the minimum size (" + data.length + " < " + MIN_ENCRYPTED_SIZE + ")");
|
_log.error("Data is less than the minimum size (" + data.length + " < " + MIN_ENCRYPTED_SIZE + ")");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (targetPrivateKey.getType() != EncType.ELGAMAL_2048)
|
||||||
|
return null;
|
||||||
|
|
||||||
byte tag[] = new byte[32];
|
byte tag[] = new byte[32];
|
||||||
System.arraycopy(data, 0, tag, 0, 32);
|
System.arraycopy(data, 0, tag, 0, 32);
|
||||||
@ -399,7 +402,8 @@ public final class ElGamalAESEngine {
|
|||||||
* no less than the paddedSize parameter, but may be more. This method uses the
|
* no less than the paddedSize parameter, but may be more. This method uses the
|
||||||
* ElGamal+AES algorithm in the data structure spec.
|
* ElGamal+AES algorithm in the data structure spec.
|
||||||
*
|
*
|
||||||
* @param target public key to which the data should be encrypted.
|
* @param target public key to which the data should be encrypted, must be ELGAMAL_2048.
|
||||||
|
* May be null if key and currentTag are non-null.
|
||||||
* @param key session key to use during encryption
|
* @param key session key to use during encryption
|
||||||
* @param tagsForDelivery session tags to be associated with the key (or newKey if specified), or null;
|
* @param tagsForDelivery session tags to be associated with the key (or newKey if specified), or null;
|
||||||
* 200 max enforced at receiver
|
* 200 max enforced at receiver
|
||||||
@ -407,11 +411,17 @@ public final class ElGamalAESEngine {
|
|||||||
* @param newKey key to be delivered to the target, with which the tagsForDelivery should be associated, or null
|
* @param newKey key to be delivered to the target, with which the tagsForDelivery should be associated, or null
|
||||||
* @param paddedSize minimum size in bytes of the body after padding it (if less than the
|
* @param paddedSize minimum size in bytes of the body after padding it (if less than the
|
||||||
* body's real size, no bytes are appended but the body is not truncated)
|
* body's real size, no bytes are appended but the body is not truncated)
|
||||||
|
* @throws IllegalArgumentException on bad target EncType
|
||||||
*
|
*
|
||||||
* Unused externally, only called by below (i.e. newKey is always null)
|
* Unused externally, only called by below (i.e. newKey is always null)
|
||||||
*/
|
*/
|
||||||
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery,
|
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery,
|
||||||
SessionTag currentTag, SessionKey newKey, long paddedSize) {
|
SessionTag currentTag, SessionKey newKey, long paddedSize) {
|
||||||
|
if (target != null) {
|
||||||
|
EncType type = target.getType();
|
||||||
|
if (type != EncType.ELGAMAL_2048)
|
||||||
|
throw new IllegalArgumentException("Bad public key type " + type);
|
||||||
|
}
|
||||||
if (currentTag == null) {
|
if (currentTag == null) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Current tag is null, encrypting as new session");
|
_log.info("Current tag is null, encrypting as new session");
|
||||||
@ -420,8 +430,9 @@ public final class ElGamalAESEngine {
|
|||||||
}
|
}
|
||||||
//if (_log.shouldLog(Log.INFO))
|
//if (_log.shouldLog(Log.INFO))
|
||||||
// _log.info("Current tag is NOT null, encrypting as existing session");
|
// _log.info("Current tag is NOT null, encrypting as existing session");
|
||||||
|
// target unused, using key and tag only
|
||||||
_context.statManager().updateFrequency("crypto.elGamalAES.encryptExistingSession");
|
_context.statManager().updateFrequency("crypto.elGamalAES.encryptExistingSession");
|
||||||
byte rv[] = encryptExistingSession(data, target, key, tagsForDelivery, currentTag, newKey, paddedSize);
|
byte rv[] = encryptExistingSession(data, key, tagsForDelivery, currentTag, newKey, paddedSize);
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Existing session encrypted with tag: " + currentTag.toString() + ": " + rv.length + " bytes and key: " + key.toBase64() /* + ": " + Base64.encode(rv, 0, 64) */);
|
_log.debug("Existing session encrypted with tag: " + currentTag.toString() + ": " + rv.length + " bytes and key: " + key.toBase64() /* + ": " + Base64.encode(rv, 0, 64) */);
|
||||||
return rv;
|
return rv;
|
||||||
@ -447,13 +458,15 @@ public final class ElGamalAESEngine {
|
|||||||
* or a 514-byte ElGamal block and several 32-byte session tags for a new session.
|
* or a 514-byte ElGamal block and several 32-byte session tags for a new session.
|
||||||
* So the returned encrypted data will be at least 32 bytes larger than paddedSize.
|
* So the returned encrypted data will be at least 32 bytes larger than paddedSize.
|
||||||
*
|
*
|
||||||
* @param target public key to which the data should be encrypted.
|
* @param target public key to which the data should be encrypted, must be ELGAMAL_2048.
|
||||||
|
* May be null if key and currentTag are non-null.
|
||||||
* @param key session key to use during encryption
|
* @param key session key to use during encryption
|
||||||
* @param tagsForDelivery session tags to be associated with the key or null;
|
* @param tagsForDelivery session tags to be associated with the key or null;
|
||||||
* 200 max enforced at receiver
|
* 200 max enforced at receiver
|
||||||
* @param currentTag sessionTag to use, or null if it should use ElG (i.e. new session)
|
* @param currentTag sessionTag to use, or null if it should use ElG (i.e. new session)
|
||||||
* @param paddedSize minimum size in bytes of the body after padding it (if less than the
|
* @param paddedSize minimum size in bytes of the body after padding it (if less than the
|
||||||
* body's real size, no bytes are appended but the body is not truncated)
|
* body's real size, no bytes are appended but the body is not truncated)
|
||||||
|
* @throws IllegalArgumentException on bad target EncType
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery,
|
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery,
|
||||||
@ -468,6 +481,7 @@ public final class ElGamalAESEngine {
|
|||||||
*
|
*
|
||||||
* @param tagsForDelivery session tags to be associated with the key or null;
|
* @param tagsForDelivery session tags to be associated with the key or null;
|
||||||
* 200 max enforced at receiver
|
* 200 max enforced at receiver
|
||||||
|
* @throws IllegalArgumentException on bad target EncType
|
||||||
* @deprecated unused
|
* @deprecated unused
|
||||||
*/
|
*/
|
||||||
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery, long paddedSize) {
|
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery, long paddedSize) {
|
||||||
@ -479,6 +493,7 @@ public final class ElGamalAESEngine {
|
|||||||
* No new session key
|
* No new session key
|
||||||
* No current tag (encrypt as new session)
|
* No current tag (encrypt as new session)
|
||||||
*
|
*
|
||||||
|
* @throws IllegalArgumentException on bad target EncType
|
||||||
* @deprecated unused
|
* @deprecated unused
|
||||||
*/
|
*/
|
||||||
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, long paddedSize) {
|
public byte[] encrypt(byte data[], PublicKey target, SessionKey key, long paddedSize) {
|
||||||
@ -573,11 +588,10 @@ public final class ElGamalAESEngine {
|
|||||||
* - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
|
* - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @param target unused, this is AES encrypt only using the session key and tag
|
|
||||||
* @param tagsForDelivery session tags to be associated with the key or null;
|
* @param tagsForDelivery session tags to be associated with the key or null;
|
||||||
* 200 max enforced at receiver
|
* 200 max enforced at receiver
|
||||||
*/
|
*/
|
||||||
private byte[] encryptExistingSession(byte data[], PublicKey target, SessionKey key, Set<SessionTag> tagsForDelivery,
|
private byte[] encryptExistingSession(byte data[], SessionKey key, Set<SessionTag> tagsForDelivery,
|
||||||
SessionTag currentTag, SessionKey newKey, long paddedSize) {
|
SessionTag currentTag, SessionKey newKey, long paddedSize) {
|
||||||
//_log.debug("Encrypting to an EXISTING session");
|
//_log.debug("Encrypting to an EXISTING session");
|
||||||
byte rawTag[] = currentTag.getData();
|
byte rawTag[] = currentTag.getData();
|
||||||
|
@ -25,6 +25,7 @@ import java.util.TreeSet;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.crypto.TagSetHandle;
|
import net.i2p.crypto.TagSetHandle;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
@ -283,6 +284,8 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
* Retrieve the session key currently associated with encryption to the target.
|
* Retrieve the session key currently associated with encryption to the target.
|
||||||
* Generates a new session and session key if not previously exising.
|
* Generates a new session and session key if not previously exising.
|
||||||
*
|
*
|
||||||
|
* @param target public key to which the data should be encrypted, must be ELGAMAL_2048.
|
||||||
|
* @throws IllegalArgumentException on bad target EncType
|
||||||
* @return non-null
|
* @return non-null
|
||||||
* @since 0.9
|
* @since 0.9
|
||||||
*/
|
*/
|
||||||
@ -310,6 +313,9 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
*
|
*
|
||||||
* Racy if called after getCurrentKey() to check for a current session;
|
* Racy if called after getCurrentKey() to check for a current session;
|
||||||
* use getCurrentOrNewKey() in that case.
|
* use getCurrentOrNewKey() in that case.
|
||||||
|
*
|
||||||
|
* @param target public key to which the data should be encrypted, must be ELGAMAL_2048.
|
||||||
|
* @throws IllegalArgumentException on bad target EncType
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void createSession(PublicKey target, SessionKey key) {
|
public void createSession(PublicKey target, SessionKey key) {
|
||||||
@ -322,6 +328,9 @@ public class TransientSessionKeyManager extends SessionKeyManager {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private OutboundSession createAndReturnSession(PublicKey target, SessionKey key) {
|
private OutboundSession createAndReturnSession(PublicKey target, SessionKey key) {
|
||||||
|
EncType type = target.getType();
|
||||||
|
if (type != EncType.ELGAMAL_2048)
|
||||||
|
throw new IllegalArgumentException("Bad public key type " + type);
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("New OB session, sesskey: " + key + " target: " + toString(target));
|
_log.info("New OB session, sesskey: " + key + " target: " + toString(target));
|
||||||
OutboundSession sess = new OutboundSession(_context, _log, target, key);
|
OutboundSession sess = new OutboundSession(_context, _log, target, key);
|
||||||
|
@ -10,6 +10,7 @@ import java.util.SortedSet;
|
|||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
@ -425,6 +426,13 @@ public class IterativeSearchJob extends FloodSearchJob {
|
|||||||
// request encrypted reply
|
// request encrypted reply
|
||||||
// now covered by version check above, which is more recent
|
// now covered by version check above, which is more recent
|
||||||
//if (DatabaseLookupMessage.supportsEncryptedReplies(ri)) {
|
//if (DatabaseLookupMessage.supportsEncryptedReplies(ri)) {
|
||||||
|
EncType type = ri.getIdentity().getPublicKey().getType();
|
||||||
|
if (type != EncType.ELGAMAL_2048) {
|
||||||
|
failed(peer, false);
|
||||||
|
if (_log.shouldLog(Log.WARN))
|
||||||
|
_log.warn(getJobId() + ": Can't do encrypted lookup to " + peer + " with EncType " + type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (true) {
|
if (true) {
|
||||||
MessageWrapper.OneTimeSession sess;
|
MessageWrapper.OneTimeSession sess;
|
||||||
if (isClientReplyTunnel)
|
if (isClientReplyTunnel)
|
||||||
|
@ -3,6 +3,7 @@ package net.i2p.router.networkdb.kademlia;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SessionKeyManager;
|
import net.i2p.crypto.SessionKeyManager;
|
||||||
import net.i2p.crypto.TagSetHandle;
|
import net.i2p.crypto.TagSetHandle;
|
||||||
import net.i2p.data.Certificate;
|
import net.i2p.data.Certificate;
|
||||||
@ -40,9 +41,14 @@ public class MessageWrapper {
|
|||||||
*
|
*
|
||||||
* @param from must be a local client with a session key manager,
|
* @param from must be a local client with a session key manager,
|
||||||
* or null to use the router's session key manager
|
* or null to use the router's session key manager
|
||||||
|
* @param to must be ELGAMAL_2048 EncType
|
||||||
* @return null on encrypt failure
|
* @return null on encrypt failure
|
||||||
*/
|
*/
|
||||||
static WrappedMessage wrap(RouterContext ctx, I2NPMessage m, Hash from, RouterInfo to) {
|
static WrappedMessage wrap(RouterContext ctx, I2NPMessage m, Hash from, RouterInfo to) {
|
||||||
|
PublicKey sentTo = to.getIdentity().getPublicKey();
|
||||||
|
if (sentTo.getType() != EncType.ELGAMAL_2048)
|
||||||
|
return null;
|
||||||
|
|
||||||
PayloadGarlicConfig payload = new PayloadGarlicConfig(Certificate.NULL_CERT,
|
PayloadGarlicConfig payload = new PayloadGarlicConfig(Certificate.NULL_CERT,
|
||||||
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
|
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
|
||||||
m.getMessageExpiration(),
|
m.getMessageExpiration(),
|
||||||
@ -63,7 +69,6 @@ public class MessageWrapper {
|
|||||||
if (msg == null)
|
if (msg == null)
|
||||||
return null;
|
return null;
|
||||||
TagSetHandle tsh = null;
|
TagSetHandle tsh = null;
|
||||||
PublicKey sentTo = to.getIdentity().getPublicKey();
|
|
||||||
if (!sentTags.isEmpty())
|
if (!sentTags.isEmpty())
|
||||||
tsh = skm.tagsDelivered(sentTo, sentKey, sentTags);
|
tsh = skm.tagsDelivered(sentTo, sentKey, sentTags);
|
||||||
//if (_log.shouldLog(Log.DEBUG))
|
//if (_log.shouldLog(Log.DEBUG))
|
||||||
@ -118,10 +123,15 @@ public class MessageWrapper {
|
|||||||
* to hide the contents from the OBEP.
|
* to hide the contents from the OBEP.
|
||||||
* Forces ElGamal.
|
* Forces ElGamal.
|
||||||
*
|
*
|
||||||
|
* @param to must be ELGAMAL_2048 EncType
|
||||||
* @return null on encrypt failure
|
* @return null on encrypt failure
|
||||||
* @since 0.9.5
|
* @since 0.9.5
|
||||||
*/
|
*/
|
||||||
static GarlicMessage wrap(RouterContext ctx, I2NPMessage m, RouterInfo to) {
|
static GarlicMessage wrap(RouterContext ctx, I2NPMessage m, RouterInfo to) {
|
||||||
|
PublicKey key = to.getIdentity().getPublicKey();
|
||||||
|
if (key.getType() != EncType.ELGAMAL_2048)
|
||||||
|
return null;
|
||||||
|
|
||||||
PayloadGarlicConfig payload = new PayloadGarlicConfig(Certificate.NULL_CERT,
|
PayloadGarlicConfig payload = new PayloadGarlicConfig(Certificate.NULL_CERT,
|
||||||
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
|
ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE),
|
||||||
m.getMessageExpiration(),
|
m.getMessageExpiration(),
|
||||||
@ -129,7 +139,6 @@ public class MessageWrapper {
|
|||||||
payload.setRecipient(to);
|
payload.setRecipient(to);
|
||||||
|
|
||||||
SessionKey sentKey = ctx.keyGenerator().generateSessionKey();
|
SessionKey sentKey = ctx.keyGenerator().generateSessionKey();
|
||||||
PublicKey key = to.getIdentity().getPublicKey();
|
|
||||||
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, null,
|
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, null,
|
||||||
key, sentKey, null);
|
key, sentKey, null);
|
||||||
return msg;
|
return msg;
|
||||||
|
@ -12,6 +12,7 @@ import java.util.Properties;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
import net.i2p.crypto.EncType;
|
||||||
import net.i2p.crypto.SHA256Generator;
|
import net.i2p.crypto.SHA256Generator;
|
||||||
import net.i2p.crypto.SigType;
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
@ -469,6 +470,9 @@ public abstract class TunnelPeerSelector extends ConnectChecker {
|
|||||||
maxLen++;
|
maxLen++;
|
||||||
if (cap.length() <= maxLen)
|
if (cap.length() <= maxLen)
|
||||||
return true;
|
return true;
|
||||||
|
if (peer.getIdentity().getPublicKey().getType() != EncType.ELGAMAL_2048)
|
||||||
|
return true;
|
||||||
|
|
||||||
// otherwise, it contains flags we aren't trying to focus on,
|
// otherwise, it contains flags we aren't trying to focus on,
|
||||||
// so don't exclude it based on published capacity
|
// so don't exclude it based on published capacity
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user