forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p.zzz.test' (head f4edeaaf6cd647f4a69847a09272b54cb51ef758)
to branch 'i2p.i2p' (head 0d7e18b693718b5924035d7a6f638ff0689af589)
This commit is contained in:
@@ -24,6 +24,7 @@ import net.i2p.data.RoutingKeyGenerator;
|
||||
import net.i2p.stat.StatManager;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.FortunaRandomSource;
|
||||
import net.i2p.util.KeyRing;
|
||||
import net.i2p.util.LogManager;
|
||||
import net.i2p.util.PooledRandomSource;
|
||||
import net.i2p.util.RandomSource;
|
||||
@@ -75,6 +76,7 @@ public class I2PAppContext {
|
||||
private RoutingKeyGenerator _routingKeyGenerator;
|
||||
private RandomSource _random;
|
||||
private KeyGenerator _keyGenerator;
|
||||
protected KeyRing _keyRing; // overridden in RouterContext
|
||||
private volatile boolean _statManagerInitialized;
|
||||
private volatile boolean _sessionKeyManagerInitialized;
|
||||
private volatile boolean _namingServiceInitialized;
|
||||
@@ -91,6 +93,7 @@ public class I2PAppContext {
|
||||
private volatile boolean _routingKeyGeneratorInitialized;
|
||||
private volatile boolean _randomInitialized;
|
||||
private volatile boolean _keyGeneratorInitialized;
|
||||
protected volatile boolean _keyRingInitialized; // used in RouterContext
|
||||
|
||||
|
||||
/**
|
||||
@@ -141,12 +144,14 @@ public class I2PAppContext {
|
||||
_elGamalEngine = null;
|
||||
_elGamalAESEngine = null;
|
||||
_logManager = null;
|
||||
_keyRing = null;
|
||||
_statManagerInitialized = false;
|
||||
_sessionKeyManagerInitialized = false;
|
||||
_namingServiceInitialized = false;
|
||||
_elGamalEngineInitialized = false;
|
||||
_elGamalAESEngineInitialized = false;
|
||||
_logManagerInitialized = false;
|
||||
_keyRingInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -512,6 +517,23 @@ public class I2PAppContext {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic hash map
|
||||
*/
|
||||
public KeyRing keyRing() {
|
||||
if (!_keyRingInitialized)
|
||||
initializeKeyRing();
|
||||
return _keyRing;
|
||||
}
|
||||
|
||||
protected void initializeKeyRing() {
|
||||
synchronized (this) {
|
||||
if (_keyRing == null)
|
||||
_keyRing = new KeyRing();
|
||||
_keyRingInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [insert snarky comment here]
|
||||
*
|
||||
|
@@ -9,6 +9,7 @@ package net.i2p.client;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
@@ -28,6 +29,7 @@ import net.i2p.data.i2cp.DestroySessionMessage;
|
||||
import net.i2p.data.i2cp.MessageId;
|
||||
import net.i2p.data.i2cp.ReportAbuseMessage;
|
||||
import net.i2p.data.i2cp.SendMessageMessage;
|
||||
import net.i2p.data.i2cp.SendMessageExpiresMessage;
|
||||
import net.i2p.data.i2cp.SessionConfig;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -91,8 +93,13 @@ class I2CPMessageProducer {
|
||||
*
|
||||
*/
|
||||
public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload, SessionTag tag,
|
||||
SessionKey key, Set tags, SessionKey newKey) throws I2PSessionException {
|
||||
SendMessageMessage msg = new SendMessageMessage();
|
||||
SessionKey key, Set tags, SessionKey newKey, long expires) throws I2PSessionException {
|
||||
SendMessageMessage msg;
|
||||
if (expires > 0) {
|
||||
msg = new SendMessageExpiresMessage();
|
||||
((SendMessageExpiresMessage)msg).setExpiration(new Date(expires));
|
||||
} else
|
||||
msg = new SendMessageMessage();
|
||||
msg.setDestination(dest);
|
||||
msg.setSessionId(session.getSessionId());
|
||||
msg.setNonce(nonce);
|
||||
|
@@ -70,6 +70,7 @@ public interface I2PSession {
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire) throws I2PSessionException;
|
||||
|
||||
/** Receive a message that the router has notified the client about, returning
|
||||
* the payload.
|
||||
|
@@ -550,10 +550,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
|
||||
* Pass off the error to the listener
|
||||
*/
|
||||
void propogateError(String msg, Throwable error) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "Error occurred: " + msg + " - " + error.getMessage());
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + " cause", error);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(getPrefix() + "Error occurred: " + msg + " - " + error.getMessage());
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error(getPrefix() + " cause", error);
|
||||
|
||||
if (_sessionListener != null) _sessionListener.errorOccurred(this, msg, error);
|
||||
}
|
||||
|
@@ -107,15 +107,19 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
return sendMessage(dest, payload, 0, payload.length);
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64));
|
||||
return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, 0, payload.length, keyUsed, tagsSent);
|
||||
return sendMessage(dest, payload, 0, payload.length, keyUsed, tagsSent, 0);
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent)
|
||||
throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0);
|
||||
}
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires)
|
||||
throws I2PSessionException {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message");
|
||||
if (isClosed()) throw new I2PSessionException("Already closed");
|
||||
|
||||
@@ -142,7 +146,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
}
|
||||
_context.statManager().addRateData("i2cp.tx.msgCompressed", compressed, 0);
|
||||
_context.statManager().addRateData("i2cp.tx.msgExpanded", size, 0);
|
||||
return sendBestEffort(dest, payload, keyUsed, tagsSent);
|
||||
return sendBestEffort(dest, payload, keyUsed, tagsSent, expires);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +172,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
|
||||
private static final int NUM_TAGS = 50;
|
||||
|
||||
private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent)
|
||||
private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
|
||||
throws I2PSessionException {
|
||||
SessionKey key = null;
|
||||
SessionKey newKey = null;
|
||||
@@ -176,6 +180,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
Set sentTags = null;
|
||||
int oldTags = 0;
|
||||
long begin = _context.clock().now();
|
||||
/***********
|
||||
if (I2CPMessageProducer.END_TO_END_CRYPTO) {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("begin sendBestEffort");
|
||||
key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey());
|
||||
@@ -220,6 +225,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
} else {
|
||||
// not using end to end crypto, so don't ever bundle any tags
|
||||
}
|
||||
**********/
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("before creating nonce");
|
||||
|
||||
@@ -233,14 +239,14 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Setting key = " + key);
|
||||
|
||||
if (keyUsed != null) {
|
||||
if (I2CPMessageProducer.END_TO_END_CRYPTO) {
|
||||
if (newKey != null)
|
||||
keyUsed.setData(newKey.getData());
|
||||
else
|
||||
keyUsed.setData(key.getData());
|
||||
} else {
|
||||
//if (I2CPMessageProducer.END_TO_END_CRYPTO) {
|
||||
// if (newKey != null)
|
||||
// keyUsed.setData(newKey.getData());
|
||||
// else
|
||||
// keyUsed.setData(key.getData());
|
||||
//} else {
|
||||
keyUsed.setData(SessionKey.INVALID_KEY.getData());
|
||||
}
|
||||
//}
|
||||
}
|
||||
if (tagsSent != null) {
|
||||
if (sentTags != null) {
|
||||
@@ -261,7 +267,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
+ state.getNonce() + " for best effort "
|
||||
+ " sync took " + (inSendingSync-beforeSendingSync)
|
||||
+ " add took " + (afterSendingSync-inSendingSync));
|
||||
_producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey);
|
||||
_producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey, expires);
|
||||
|
||||
// since this is 'best effort', all we're waiting for is a status update
|
||||
// saying that the router received it - in theory, that should come back
|
||||
|
@@ -21,6 +21,7 @@ import net.i2p.data.Lease;
|
||||
import net.i2p.data.LeaseSet;
|
||||
import net.i2p.data.PrivateKey;
|
||||
import net.i2p.data.PublicKey;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SigningPublicKey;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
@@ -78,6 +79,17 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
|
||||
leaseSet.setEncryptionKey(li.getPublicKey());
|
||||
leaseSet.setSigningKey(li.getSigningPublicKey());
|
||||
String sk = session.getOptions().getProperty("i2cp.sessionKey");
|
||||
if (sk != null) {
|
||||
SessionKey key = new SessionKey();
|
||||
try {
|
||||
key.fromBase64(sk);
|
||||
leaseSet.encrypt(key);
|
||||
_context.keyRing().put(session.getMyDestination().calculateHash(), key);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Bad session key: " + sk);
|
||||
}
|
||||
}
|
||||
try {
|
||||
leaseSet.sign(session.getPrivateKey());
|
||||
session.getProducer().createLeaseSet(session, leaseSet, li.getSigningPrivateKey(), li.getPrivateKey());
|
||||
@@ -137,4 +149,4 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
&& DataHelper.eq(_signingPrivKey, li.getSigningPrivateKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -235,7 +236,7 @@ public class DataHelper {
|
||||
int split = line.indexOf('=');
|
||||
if (split <= 0) continue;
|
||||
String key = line.substring(0, split);
|
||||
String val = line.substring(split+1);
|
||||
String val = line.substring(split+1); //.trim() ??????????????
|
||||
// Unescape line breaks after loading.
|
||||
// Remember: "\" needs escaping both for regex and string.
|
||||
val = val.replaceAll("\\\\r","\r");
|
||||
@@ -842,6 +843,29 @@ public class DataHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller should append 'B' or 'b' as appropriate
|
||||
*/
|
||||
public static String formatSize(long bytes) {
|
||||
double val = bytes;
|
||||
int scale = 0;
|
||||
while (val >= 1024) {
|
||||
scale++;
|
||||
val /= 1024;
|
||||
}
|
||||
|
||||
DecimalFormat fmt = new DecimalFormat("##0.00");
|
||||
|
||||
String str = fmt.format(val);
|
||||
switch (scale) {
|
||||
case 1: return str + "K";
|
||||
case 2: return str + "M";
|
||||
case 3: return str + "G";
|
||||
case 4: return str + "T";
|
||||
default: return bytes + "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip out any HTML (simply removing any less than / greater than symbols)
|
||||
*/
|
||||
|
@@ -9,6 +9,7 @@ package net.i2p.data;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -17,13 +18,34 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.DSAEngine;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
/**
|
||||
* Defines the set of leases a destination currently has.
|
||||
*
|
||||
* Support encryption and decryption with a supplied key.
|
||||
* Only the gateways and tunnel IDs in the individual
|
||||
* leases are encrypted.
|
||||
*
|
||||
* Encrypted leases are not indicated as such.
|
||||
* The only way to tell a lease is encrypted is to
|
||||
* determine that the listed gateways do not exist.
|
||||
* Routers wishing to decrypt a leaseset must have the
|
||||
* desthash and key in their keyring.
|
||||
* This is required for the local router as well, since
|
||||
* the encryption is done on the client side of I2CP, the
|
||||
* router must decrypt it back again for local usage
|
||||
* (but not for transmission to the floodfills)
|
||||
*
|
||||
* Decrypted leases are only available through the getLease()
|
||||
* method, so that storage and network transmission via
|
||||
* writeBytes() will output the original encrypted
|
||||
* leases and the original leaseset signature.
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
public class LeaseSet extends DataStructureImpl {
|
||||
@@ -40,6 +62,9 @@ public class LeaseSet extends DataStructureImpl {
|
||||
// Store these since isCurrent() and getEarliestLeaseDate() are called frequently
|
||||
private long _firstExpiration;
|
||||
private long _lastExpiration;
|
||||
private List _decryptedLeases;
|
||||
private boolean _decrypted;
|
||||
private boolean _checked;
|
||||
|
||||
/** This seems like plenty */
|
||||
private final static int MAX_LEASES = 6;
|
||||
@@ -55,6 +80,8 @@ public class LeaseSet extends DataStructureImpl {
|
||||
_receivedAsPublished = false;
|
||||
_firstExpiration = Long.MAX_VALUE;
|
||||
_lastExpiration = 0;
|
||||
_decrypted = false;
|
||||
_checked = false;
|
||||
}
|
||||
|
||||
public Destination getDestination() {
|
||||
@@ -104,11 +131,17 @@ public class LeaseSet extends DataStructureImpl {
|
||||
}
|
||||
|
||||
public int getLeaseCount() {
|
||||
return _leases.size();
|
||||
if (isEncrypted())
|
||||
return _leases.size() - 1;
|
||||
else
|
||||
return _leases.size();
|
||||
}
|
||||
|
||||
public Lease getLease(int index) {
|
||||
return (Lease) _leases.get(index);
|
||||
if (isEncrypted())
|
||||
return (Lease) _decryptedLeases.get(index);
|
||||
else
|
||||
return (Lease) _leases.get(index);
|
||||
}
|
||||
|
||||
public Signature getSignature() {
|
||||
@@ -335,4 +368,139 @@ public class LeaseSet extends DataStructureImpl {
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static final int DATA_LEN = Hash.HASH_LENGTH + 4;
|
||||
private static final int IV_LEN = 16;
|
||||
|
||||
/**
|
||||
* Encrypt the gateway and tunnel ID of each lease, leaving the expire dates unchanged.
|
||||
* This adds an extra dummy lease, because AES data must be padded to 16 bytes.
|
||||
* The fact that it is encrypted is not stored anywhere.
|
||||
* Must be called after all the leases are in place, but before sign().
|
||||
*/
|
||||
public void encrypt(SessionKey key) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("encrypting lease: " + _destination.calculateHash());
|
||||
try {
|
||||
encryp(key);
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error encrypting lease: " + _destination.calculateHash());
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error encrypting lease: " + _destination.calculateHash());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* - Put the {Gateway Hash, TunnelID} pairs for all the leases in a buffer
|
||||
* - Pad with random data to a multiple of 16 bytes
|
||||
* - Use the first part of the dest's public key as an IV
|
||||
* - Encrypt
|
||||
* - Pad with random data to a multiple of 36 bytes
|
||||
* - Add an extra lease
|
||||
* - Replace the Hash and TunnelID in each Lease
|
||||
*/
|
||||
private void encryp(SessionKey key) throws DataFormatException, IOException {
|
||||
int size = _leases.size();
|
||||
if (size < 1 || size > MAX_LEASES-1)
|
||||
throw new IllegalArgumentException("Bad number of leases for encryption");
|
||||
int datalen = ((DATA_LEN * size / 16) + 1) * 16;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(datalen);
|
||||
for (int i = 0; i < size; i++) {
|
||||
((Lease)_leases.get(i)).getGateway().writeBytes(baos);
|
||||
((Lease)_leases.get(i)).getTunnelId().writeBytes(baos);
|
||||
}
|
||||
// pad out to multiple of 16 with random data before encryption
|
||||
int padlen = datalen - (DATA_LEN * size);
|
||||
byte[] pad = new byte[padlen];
|
||||
RandomSource.getInstance().nextBytes(pad);
|
||||
baos.write(pad);
|
||||
byte[] iv = new byte[IV_LEN];
|
||||
System.arraycopy(_destination.getPublicKey().getData(), 0, iv, 0, IV_LEN);
|
||||
byte[] enc = new byte[DATA_LEN * (size + 1)];
|
||||
I2PAppContext.getGlobalContext().aes().encrypt(baos.toByteArray(), 0, enc, 0, key, iv, datalen);
|
||||
// pad out to multiple of 36 with random data after encryption
|
||||
// (even for 4 leases, where 36*4 is a multiple of 16, we add another, just to be consistent)
|
||||
padlen = enc.length - datalen;
|
||||
pad = new byte[padlen];
|
||||
RandomSource.getInstance().nextBytes(pad);
|
||||
System.arraycopy(pad, 0, enc, datalen, padlen);
|
||||
// add the padded lease...
|
||||
Lease padLease = new Lease();
|
||||
padLease.setEndDate(((Lease)_leases.get(0)).getEndDate());
|
||||
_leases.add(padLease);
|
||||
// ...and replace all the gateways and tunnel ids
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(enc);
|
||||
for (int i = 0; i < size+1; i++) {
|
||||
Hash h = new Hash();
|
||||
h.readBytes(bais);
|
||||
((Lease)_leases.get(i)).setGateway(h);
|
||||
TunnelId t = new TunnelId();
|
||||
t.readBytes(bais);
|
||||
((Lease)_leases.get(i)).setTunnelId(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the leases, except for the last one which is partially padding.
|
||||
* Store the new decrypted leases in a backing store,
|
||||
* and keep the original leases so that verify() still works and the
|
||||
* encrypted leaseset can be sent on to others (via writeBytes())
|
||||
*/
|
||||
private void decrypt(SessionKey key) throws DataFormatException, IOException {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("decrypting lease: " + _destination.calculateHash());
|
||||
int size = _leases.size();
|
||||
if (size < 2)
|
||||
throw new DataFormatException("Bad number of leases for decryption");
|
||||
int datalen = DATA_LEN * size;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(datalen);
|
||||
for (int i = 0; i < size; i++) {
|
||||
((Lease)_leases.get(i)).getGateway().writeBytes(baos);
|
||||
((Lease)_leases.get(i)).getTunnelId().writeBytes(baos);
|
||||
}
|
||||
byte[] iv = new byte[IV_LEN];
|
||||
System.arraycopy(_destination.getPublicKey().getData(), 0, iv, 0, IV_LEN);
|
||||
int enclen = ((DATA_LEN * (size - 1) / 16) + 1) * 16;
|
||||
byte[] enc = new byte[enclen];
|
||||
System.arraycopy(baos.toByteArray(), 0, enc, 0, enclen);
|
||||
byte[] dec = new byte[enclen];
|
||||
I2PAppContext.getGlobalContext().aes().decrypt(enc, 0, dec, 0, key, iv, enclen);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(dec);
|
||||
_decryptedLeases = new ArrayList(size - 1);
|
||||
for (int i = 0; i < size-1; i++) {
|
||||
Lease l = new Lease();
|
||||
Hash h = new Hash();
|
||||
h.readBytes(bais);
|
||||
l.setGateway(h);
|
||||
TunnelId t = new TunnelId();
|
||||
t.readBytes(bais);
|
||||
l.setTunnelId(t);
|
||||
l.setEndDate(((Lease)_leases.get(i)).getEndDate());
|
||||
_decryptedLeases.add(l);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if it was encrypted, and we decrypted it successfully.
|
||||
* Decrypts on first call.
|
||||
*/
|
||||
private synchronized boolean isEncrypted() {
|
||||
if (_decrypted)
|
||||
return true;
|
||||
if (_checked || _destination == null)
|
||||
return false;
|
||||
SessionKey key = I2PAppContext.getGlobalContext().keyRing().get(_destination.calculateHash());
|
||||
if (key != null) {
|
||||
try {
|
||||
decrypt(key);
|
||||
_decrypted = true;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error decrypting lease: " + _destination.calculateHash() + dfe);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error decrypting lease: " + _destination.calculateHash() + ioe);
|
||||
}
|
||||
}
|
||||
_checked = true;
|
||||
return _decrypted;
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Handle messages from the server for the client
|
||||
* Handle messages from the server for the client or vice versa
|
||||
*
|
||||
*/
|
||||
public class I2CPMessageHandler {
|
||||
@@ -75,6 +75,8 @@ public class I2CPMessageHandler {
|
||||
return new RequestLeaseSetMessage();
|
||||
case SendMessageMessage.MESSAGE_TYPE:
|
||||
return new SendMessageMessage();
|
||||
case SendMessageExpiresMessage.MESSAGE_TYPE:
|
||||
return new SendMessageExpiresMessage();
|
||||
case SessionStatusMessage.MESSAGE_TYPE:
|
||||
return new SessionStatusMessage();
|
||||
case GetDateMessage.MESSAGE_TYPE:
|
||||
|
103
core/java/src/net/i2p/data/i2cp/ReconfigureSessionMessage.java
Normal file
103
core/java/src/net/i2p/data/i2cp/ReconfigureSessionMessage.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package net.i2p.data.i2cp;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Defines the message a client sends to a router when
|
||||
* updating the config on an existing session.
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
public class ReconfigureSessionMessage extends I2CPMessageImpl {
|
||||
private final static Log _log = new Log(ReconfigureSessionMessage.class);
|
||||
public final static int MESSAGE_TYPE = 2;
|
||||
private SessionId _sessionId;
|
||||
private SessionConfig _sessionConfig;
|
||||
|
||||
public ReconfigureSessionMessage() {
|
||||
_sessionId = null;
|
||||
_sessionConfig = null;
|
||||
}
|
||||
|
||||
public SessionId getSessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
||||
public SessionConfig getSessionConfig() {
|
||||
return _sessionConfig;
|
||||
}
|
||||
|
||||
public void setSessionConfig(SessionConfig config) {
|
||||
_sessionConfig = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
|
||||
try {
|
||||
_sessionId = new SessionId();
|
||||
_sessionId.readBytes(in);
|
||||
_sessionConfig = new SessionConfig();
|
||||
_sessionConfig.readBytes(in);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] doWriteMessage() throws I2CPMessageException, IOException {
|
||||
if (_sessionId == null || _sessionConfig == null)
|
||||
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(64);
|
||||
try {
|
||||
_sessionId.writeBytes(os);
|
||||
_sessionConfig.writeBytes(os);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Error writing out the message data", dfe);
|
||||
}
|
||||
return os.toByteArray();
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return MESSAGE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof ReconfigureSessionMessage)) {
|
||||
ReconfigureSessionMessage msg = (ReconfigureSessionMessage) object;
|
||||
return DataHelper.eq(getSessionId(), msg.getSessionId())
|
||||
&& DataHelper.eq(getSessionConfig(), msg.getSessionConfig());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("[ReconfigureSessionMessage: ");
|
||||
buf.append("\n\tSessionId: ").append(getSessionId());
|
||||
buf.append("\n\tSessionConfig: ").append(getSessionConfig());
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
117
core/java/src/net/i2p/data/i2cp/SendMessageExpiresMessage.java
Normal file
117
core/java/src/net/i2p/data/i2cp/SendMessageExpiresMessage.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package net.i2p.data.i2cp;
|
||||
|
||||
/*
|
||||
* free (adj.): unencumbered; not under the control of others
|
||||
* Written by jrandom in 2003 and released into the public domain
|
||||
* with no warranty of any kind, either expressed or implied.
|
||||
* It probably won't make your computer catch on fire, or eat
|
||||
* your children, but it might. Use at your own risk.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Payload;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Same as SendMessageMessage, but with an expiration to be passed to the router
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
public class SendMessageExpiresMessage extends SendMessageMessage {
|
||||
private final static Log _log = new Log(SendMessageExpiresMessage.class);
|
||||
public final static int MESSAGE_TYPE = 36;
|
||||
private SessionId _sessionId;
|
||||
private Destination _destination;
|
||||
private Payload _payload;
|
||||
private Date _expiration;
|
||||
|
||||
public SendMessageExpiresMessage() {
|
||||
super();
|
||||
setExpiration(null);
|
||||
}
|
||||
|
||||
public Date getExpiration() {
|
||||
return _expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Date d) {
|
||||
_expiration = d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the body into the data structures
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void readMessage(InputStream in, int length, int type) throws I2CPMessageException, IOException {
|
||||
super.readMessage(in, length, type);
|
||||
|
||||
try {
|
||||
_expiration = DataHelper.readDate(in);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Unable to load the message data", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the full message to the stream, including the 4 byte size and 1
|
||||
* byte type header. Override the parent so we can be more mem efficient
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void writeMessage(OutputStream out) throws I2CPMessageException, IOException {
|
||||
if ((getSessionId() == null) || (getDestination() == null) || (getPayload() == null) || (getNonce() <= 0) || (_expiration == null))
|
||||
throw new I2CPMessageException("Unable to write out the message as there is not enough data");
|
||||
int len = 2 + getDestination().size() + getPayload().getSize() + 4 + 4 + DataHelper.DATE_LENGTH;
|
||||
|
||||
try {
|
||||
DataHelper.writeLong(out, 4, len);
|
||||
DataHelper.writeLong(out, 1, getType());
|
||||
getSessionId().writeBytes(out);
|
||||
getDestination().writeBytes(out);
|
||||
getPayload().writeBytes(out);
|
||||
DataHelper.writeLong(out, 4, getNonce());
|
||||
DataHelper.writeDate(out, _expiration);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2CPMessageException("Error writing the msg", dfe);
|
||||
}
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return MESSAGE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if ((object != null) && (object instanceof SendMessageExpiresMessage)) {
|
||||
SendMessageExpiresMessage msg = (SendMessageExpiresMessage) object;
|
||||
return super.equals(object)
|
||||
&& DataHelper.eq(getExpiration(), msg.getExpiration());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append("[SendMessageMessage: ");
|
||||
buf.append("\n\tSessionId: ").append(getSessionId());
|
||||
buf.append("\n\tNonce: ").append(getNonce());
|
||||
buf.append("\n\tDestination: ").append(getDestination());
|
||||
buf.append("\n\tExpiration: ").append(getExpiration());
|
||||
buf.append("\n\tPayload: ").append(getPayload());
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
20
core/java/src/net/i2p/util/KeyRing.java
Normal file
20
core/java/src/net/i2p/util/KeyRing.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package net.i2p.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.SessionKey;
|
||||
|
||||
/**
|
||||
* simple
|
||||
*/
|
||||
public class KeyRing extends ConcurrentHashMap<Hash, SessionKey> {
|
||||
public KeyRing() {
|
||||
super(0);
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException {}
|
||||
}
|
Reference in New Issue
Block a user