beginning of branch i2p.i2p.i2p

This commit is contained in:
cvs_import
2004-04-08 04:41:54 +00:00
committed by zzz
commit 77bd69c5e5
292 changed files with 41035 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
package net.i2p.data.i2np;
/*
* 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 a message containing arbitrary bytes of data
*
* @author jrandom
*/
public class DataMessage extends I2NPMessageImpl {
private final static Log _log = new Log(DataMessage.class);
public final static int MESSAGE_TYPE = 20;
private byte _data[];
public DataMessage() {
_data = null;
}
public byte[] getData() { return _data; }
public void setData(byte data[]) { _data = data; }
public int getSize() { return _data.length; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
int size = (int)DataHelper.readLong(in, 4);
_data = new byte[size];
int read = read(in, _data);
if (read != size)
throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")");
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream((_data != null ? _data.length + 4 : 4));
try {
DataHelper.writeLong(os, 4, (_data != null ? _data.length : 0));
os.write(_data);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getData());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof DataMessage) ) {
DataMessage msg = (DataMessage)object;
return DataHelper.eq(getData(),msg.getData());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[DataMessage: ");
buf.append("\n\tData: ").append(DataHelper.toString(getData(), 64));
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,99 @@
package net.i2p.data.i2np;
/*
* 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.data.Hash;
import net.i2p.util.Log;
/**
* Defines the message a router sends to another router to help integrate into
* the network by searching for routers in a particular keyspace.
*
* @author jrandom
*/
public class DatabaseFindNearestMessage extends I2NPMessageImpl {
private final static Log _log = new Log(DatabaseFindNearestMessage.class);
public final static int MESSAGE_TYPE = 4;
private Hash _key;
private Hash _from;
public DatabaseFindNearestMessage() {
setSearchKey(null);
setFromHash(null);
}
/**
* Defines the key being searched for
*/
public Hash getSearchKey() { return _key; }
public void setSearchKey(Hash key) { _key = key; }
/**
* Contains the SHA256 Hash of the RouterIdentity sending the message
*/
public Hash getFromHash() { return _from; }
public void setFromHash(Hash from) { _from = from; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_key = new Hash();
_key.readBytes(in);
_from = new Hash();
_from.readBytes(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_key == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
_key.writeBytes(os);
_from.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getSearchKey()) +
DataHelper.hashCode(getFromHash());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof DatabaseFindNearestMessage) ) {
DatabaseFindNearestMessage msg = (DatabaseFindNearestMessage)object;
return DataHelper.eq(getSearchKey(),msg.getSearchKey()) &&
DataHelper.eq(getFromHash(),msg.getFromHash());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[DatabaseFindNearestMessage: ");
buf.append("\n\tSearch Key: ").append(getSearchKey());
buf.append("\n\tFrom: ").append(getFromHash());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,165 @@
package net.i2p.data.i2np;
/*
* 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 java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.RouterInfo;
import net.i2p.data.TunnelId;
import net.i2p.util.Log;
/**
* Defines the message a router sends to another router to search for a
* key in the network database.
*
* @author jrandom
*/
public class DatabaseLookupMessage extends I2NPMessageImpl {
private final static Log _log = new Log(DatabaseLookupMessage.class);
public final static int MESSAGE_TYPE = 2;
private Hash _key;
private RouterInfo _from;
private TunnelId _replyTunnel;
private Set _dontIncludePeers;
public DatabaseLookupMessage() {
setSearchKey(null);
setFrom(null);
setDontIncludePeers(null);
}
/**
* Defines the key being searched for
*/
public Hash getSearchKey() { return _key; }
public void setSearchKey(Hash key) { _key = key; }
/**
* Contains the current router info of the router who requested this lookup
*
*/
public RouterInfo getFrom() { return _from; }
public void setFrom(RouterInfo from) { _from = from; }
/**
* Contains the tunnel ID a reply should be sent to
*
*/
public TunnelId getReplyTunnel() { return _replyTunnel; }
public void setReplyTunnel(TunnelId replyTunnel) { _replyTunnel = replyTunnel; }
/**
* Set of peers that a lookup reply should NOT include
*
* @return Set of Hash objects, each of which is the H(routerIdentity) to skip
*/
public Set getDontIncludePeers() { return _dontIncludePeers; }
public void setDontIncludePeers(Set peers) {
if (peers != null)
_dontIncludePeers = new HashSet(peers);
else
_dontIncludePeers = null;
}
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_key = new Hash();
_key.readBytes(in);
_from = new RouterInfo();
_from.readBytes(in);
boolean tunnelSpecified = DataHelper.readBoolean(in).booleanValue();
if (tunnelSpecified) {
_replyTunnel = new TunnelId();
_replyTunnel.readBytes(in);
}
int numPeers = (int)DataHelper.readLong(in, 2);
if ( (numPeers < 0) || (numPeers >= (1<<16) ) )
throw new DataFormatException("Invalid number of peers - " + numPeers);
Set peers = new HashSet(numPeers);
for (int i = 0; i < numPeers; i++) {
Hash peer = new Hash();
peer.readBytes(in);
peers.add(peer);
}
_dontIncludePeers = peers;
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if (_key == null) throw new I2NPMessageException("Key being searched for not specified");
if (_from == null) throw new I2NPMessageException("From address not specified");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
_key.writeBytes(os);
_from.writeBytes(os);
if (_replyTunnel != null) {
DataHelper.writeBoolean(os, Boolean.TRUE);
_replyTunnel.writeBytes(os);
} else {
DataHelper.writeBoolean(os, Boolean.FALSE);
}
if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) {
DataHelper.writeLong(os, 2, 0);
} else {
DataHelper.writeLong(os, 2, _dontIncludePeers.size());
for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) {
Hash peer = (Hash)iter.next();
peer.writeBytes(os);
}
}
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getSearchKey()) +
DataHelper.hashCode(getFrom()) +
DataHelper.hashCode(getReplyTunnel()) +
DataHelper.hashCode(_dontIncludePeers);
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof DatabaseLookupMessage) ) {
DatabaseLookupMessage msg = (DatabaseLookupMessage)object;
return DataHelper.eq(getSearchKey(),msg.getSearchKey()) &&
DataHelper.eq(getFrom(),msg.getFrom()) &&
DataHelper.eq(getReplyTunnel(),msg.getReplyTunnel()) &&
DataHelper.eq(_dontIncludePeers,msg.getDontIncludePeers());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[DatabaseLookupMessage: ");
buf.append("\n\tSearch Key: ").append(getSearchKey());
buf.append("\n\tFrom: ").append(getFrom());
buf.append("\n\tReply Tunnel: ").append(getReplyTunnel());
buf.append("\n\tDont Include Peers: ").append(getDontIncludePeers());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,149 @@
package net.i2p.data.i2np;
/*
* 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.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.RouterInfo;
import net.i2p.util.Log;
/**
* Defines the message a router sends to another router in response to a
* search (DatabaseFindNearest or DatabaseLookup) when it doesn't have the value,
* specifying what routers it would search.
*
* @author jrandom
*/
public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
private final static Log _log = new Log(DatabaseSearchReplyMessage.class);
public final static int MESSAGE_TYPE = 3;
private Hash _key;
private List _routerInfoStructures;
private Hash _from;
public DatabaseSearchReplyMessage() {
setSearchKey(null);
_routerInfoStructures = new ArrayList();
setFromHash(null);
}
/**
* Defines the key being searched for
*/
public Hash getSearchKey() { return _key; }
public void setSearchKey(Hash key) { _key = key; }
public int getNumReplies() { return _routerInfoStructures.size(); }
public RouterInfo getReply(int index) { return (RouterInfo)_routerInfoStructures.get(index); }
public void addReply(RouterInfo info) { _routerInfoStructures.add(info); }
public void addReplies(Collection replies) { _routerInfoStructures.addAll(replies); }
public Hash getFromHash() { return _from; }
public void setFromHash(Hash from) { _from = from; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_key = new Hash();
_key.readBytes(in);
int compressedLength = (int)DataHelper.readLong(in, 2);
byte compressedData[] = new byte[compressedLength];
int read = DataHelper.read(in, compressedData);
if (read != compressedLength)
throw new IOException("Not enough data to decompress");
byte decompressedData[] = DataHelper.decompress(compressedData);
ByteArrayInputStream bais = new ByteArrayInputStream(decompressedData);
int num = (int)DataHelper.readLong(bais, 1);
_routerInfoStructures.clear();
for (int i = 0; i < num; i++) {
RouterInfo info = new RouterInfo();
info.readBytes(bais);
addReply(info);
}
_from = new Hash();
_from.readBytes(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if (_key == null)
throw new I2NPMessageException("Key in reply to not specified");
if (_routerInfoStructures == null)
throw new I2NPMessageException("RouterInfo replies are null");
if (_routerInfoStructures.size() <= 0)
throw new I2NPMessageException("No replies specified in SearchReply! Always include oneself!");
if (_from == null)
throw new I2NPMessageException("No 'from' address specified!");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
_key.writeBytes(os);
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
DataHelper.writeLong(baos, 1, _routerInfoStructures.size());
for (int i = 0; i < getNumReplies(); i++) {
RouterInfo info = getReply(i);
info.writeBytes(baos);
}
byte compressed[] = DataHelper.compress(baos.toByteArray());
DataHelper.writeLong(os, 2, compressed.length);
os.write(compressed);
_from.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public boolean equals(Object object) {
if ( (object != null) && (object instanceof DatabaseSearchReplyMessage) ) {
DatabaseSearchReplyMessage msg = (DatabaseSearchReplyMessage)object;
return DataHelper.eq(getSearchKey(),msg.getSearchKey()) &&
DataHelper.eq(getFromHash(),msg.getFromHash()) &&
DataHelper.eq(_routerInfoStructures,msg._routerInfoStructures);
} else {
return false;
}
}
public int hashCode() {
return DataHelper.hashCode(getSearchKey()) +
DataHelper.hashCode(getFromHash()) +
DataHelper.hashCode(_routerInfoStructures);
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[DatabaseSearchReplyMessage: ");
buf.append("\n\tSearch Key: ").append(getSearchKey());
buf.append("\n\tReplies: # = ").append(getNumReplies());
for (int i = 0; i < getNumReplies(); i++) {
buf.append("\n\t\tReply [").append(i).append("]: ").append(getReply(i));
}
buf.append("\n\tFrom: ").append(getFromHash());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,170 @@
package net.i2p.data.i2np;
/*
* 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.ByteArrayInputStream;
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.data.Hash;
import net.i2p.data.LeaseSet;
import net.i2p.data.RouterInfo;
import net.i2p.util.Log;
/**
* Defines the message a router sends to another router to test the network
* database reachability, as well as the reply message sent back.
*
* @author jrandom
*/
public class DatabaseStoreMessage extends I2NPMessageImpl {
private final static Log _log = new Log(DatabaseStoreMessage.class);
public final static int MESSAGE_TYPE = 1;
private Hash _key;
private int _type;
private LeaseSet _leaseSet;
private RouterInfo _info;
public final static int KEY_TYPE_ROUTERINFO = 0;
public final static int KEY_TYPE_LEASESET = 1;
public DatabaseStoreMessage() {
setValueType(-1);
setKey(null);
setLeaseSet(null);
setRouterInfo(null);
}
/**
* Defines the key in the network database being stored
*
*/
public Hash getKey() { return _key; }
public void setKey(Hash key) { _key = key; }
/**
* Defines the router info value in the network database being stored
*
*/
public RouterInfo getRouterInfo() { return _info; }
public void setRouterInfo(RouterInfo routerInfo) {
_info = routerInfo;
if (_info != null)
setValueType(KEY_TYPE_ROUTERINFO);
}
/**
* Defines the lease set value in the network database being stored
*
*/
public LeaseSet getLeaseSet() { return _leaseSet; }
public void setLeaseSet(LeaseSet leaseSet) {
_leaseSet = leaseSet;
if (_leaseSet != null)
setValueType(KEY_TYPE_LEASESET);
}
/**
* Defines type of key being stored in the network database -
* either KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET
*
*/
public int getValueType() { return _type; }
public void setValueType(int type) { _type = type; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_key = new Hash();
_key.readBytes(in);
_log.debug("Hash read: " + _key.toBase64());
_type = (int)DataHelper.readLong(in, 1);
if (_type == KEY_TYPE_LEASESET) {
_leaseSet = new LeaseSet();
_leaseSet.readBytes(in);
} else if (_type == KEY_TYPE_ROUTERINFO) {
_info = new RouterInfo();
int compressedSize = (int)DataHelper.readLong(in, 2);
byte compressed[] = new byte[compressedSize];
int read = DataHelper.read(in, compressed);
if (read != compressedSize)
throw new I2NPMessageException("Invalid compressed data size");
ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed));
_info.readBytes(bais);
} else {
throw new I2NPMessageException("Invalid type of key read from the structure - " + _type);
}
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if (_key == null) throw new I2NPMessageException("Invalid key");
if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type");
if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set");
if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info");
ByteArrayOutputStream os = new ByteArrayOutputStream(256);
try {
_key.writeBytes(os);
DataHelper.writeLong(os, 1, _type);
if (_type == KEY_TYPE_LEASESET) {
_leaseSet.writeBytes(os);
} else if (_type == KEY_TYPE_ROUTERINFO) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
_info.writeBytes(baos);
byte uncompressed[] = baos.toByteArray();
byte compressed[] = DataHelper.compress(uncompressed);
DataHelper.writeLong(os, 2, compressed.length);
os.write(compressed);
}
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getKey()) +
DataHelper.hashCode(getLeaseSet()) +
DataHelper.hashCode(getRouterInfo()) +
getValueType();
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof DatabaseStoreMessage) ) {
DatabaseStoreMessage msg = (DatabaseStoreMessage)object;
return DataHelper.eq(getKey(),msg.getKey()) &&
DataHelper.eq(getLeaseSet(),msg.getLeaseSet()) &&
DataHelper.eq(getRouterInfo(),msg.getRouterInfo()) &&
DataHelper.eq(getValueType(),msg.getValueType());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[DatabaseStoreMessage: ");
buf.append("\n\tExpiration: ").append(getMessageExpiration());
buf.append("\n\tUnique ID: ").append(getUniqueId());
buf.append("\n\tKey: ").append(getKey());
buf.append("\n\tValue Type: ").append(getValueType());
buf.append("\n\tRouter Info: ").append(getRouterInfo());
buf.append("\n\tLease Set: ").append(getLeaseSet());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,274 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import net.i2p.data.TunnelId;
/**
* Contains the delivery instructions
*
* @author jrandom
*/
public class DeliveryInstructions extends DataStructureImpl {
private final static Log _log = new Log(DeliveryInstructions.class);
private boolean _encrypted;
private SessionKey _encryptionKey;
private int _deliveryMode;
public final static int DELIVERY_MODE_LOCAL = 0;
public final static int DELIVERY_MODE_DESTINATION = 1;
public final static int DELIVERY_MODE_ROUTER = 2;
public final static int DELIVERY_MODE_TUNNEL = 3;
private Hash _destinationHash;
private Hash _routerHash;
private TunnelId _tunnelId;
private boolean _delayRequested;
private long _delaySeconds;
private final static int FLAG_MODE_LOCAL = 0;
private final static int FLAG_MODE_DESTINATION = 1;
private final static int FLAG_MODE_ROUTER = 2;
private final static int FLAG_MODE_TUNNEL = 3;
private final static long FLAG_ENCRYPTED = 128;
private final static long FLAG_MODE = 96;
private final static long FLAG_DELAY = 16;
public DeliveryInstructions() {
setEncrypted(false);
setEncryptionKey(null);
setDeliveryMode(-1);
setDestination(null);
setRouter(null);
setTunnelId(null);
setDelayRequested(false);
setDelaySeconds(0);
}
public boolean getEncrypted() { return _encrypted; }
public void setEncrypted(boolean encrypted) { _encrypted = encrypted; }
public SessionKey getEncryptionKey() { return _encryptionKey; }
public void setEncryptionKey(SessionKey key) { _encryptionKey = key; }
public int getDeliveryMode() { return _deliveryMode; }
public void setDeliveryMode(int mode) { _deliveryMode = mode; }
public Hash getDestination() { return _destinationHash; }
public void setDestination(Hash dest) { _destinationHash = dest; }
public Hash getRouter() { return _routerHash; }
public void setRouter(Hash router) { _routerHash = router; }
public TunnelId getTunnelId() { return _tunnelId; }
public void setTunnelId(TunnelId id) { _tunnelId = id; }
public boolean getDelayRequested() { return _delayRequested; }
public void setDelayRequested(boolean req) { _delayRequested = req; }
public long getDelaySeconds() { return _delaySeconds; }
public void setDelaySeconds(long seconds) { _delaySeconds = seconds; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
long flags = DataHelper.readLong(in, 1);
_log.debug("Read flags: " + flags + " mode: " + flagMode(flags));
if (flagEncrypted(flags)) {
SessionKey k = new SessionKey();
k.readBytes(in);
setEncryptionKey(k);
setEncrypted(true);
} else {
setEncrypted(false);
}
setDeliveryMode(flagMode(flags));
switch (flagMode(flags)) {
case FLAG_MODE_LOCAL:
break;
case FLAG_MODE_DESTINATION:
Hash destHash = new Hash();
destHash.readBytes(in);
setDestination(destHash);
break;
case FLAG_MODE_ROUTER:
Hash routerHash = new Hash();
routerHash.readBytes(in);
setRouter(routerHash);
break;
case FLAG_MODE_TUNNEL:
Hash tunnelRouterHash = new Hash();
tunnelRouterHash.readBytes(in);
setRouter(tunnelRouterHash);
TunnelId id = new TunnelId();
id.readBytes(in);
setTunnelId(id);
break;
}
if (flagDelay(flags)) {
long delay = DataHelper.readLong(in, 4);
setDelayRequested(true);
setDelaySeconds(delay);
} else {
setDelayRequested(false);
}
}
private boolean flagEncrypted(long flags) {
return (0 != (flags & FLAG_ENCRYPTED));
}
private int flagMode(long flags) {
long v = flags & FLAG_MODE;
v >>>= 5;
return (int)v;
}
private boolean flagDelay(long flags) {
return (0 != (flags & FLAG_DELAY));
}
private long getFlags() {
long val = 0L;
if (getEncrypted())
val = val | FLAG_ENCRYPTED;
long fmode = 0;
switch (getDeliveryMode()) {
case FLAG_MODE_LOCAL:
break;
case FLAG_MODE_DESTINATION:
fmode = FLAG_MODE_DESTINATION << 5;
break;
case FLAG_MODE_ROUTER:
fmode = FLAG_MODE_ROUTER << 5;
break;
case FLAG_MODE_TUNNEL:
fmode = FLAG_MODE_TUNNEL << 5;
break;
}
val = val | fmode;
if (getDelayRequested())
val = val | FLAG_DELAY;
_log.debug("getFlags() = " + val);
return val;
}
private byte[] getAdditionalInfo() throws DataFormatException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
try {
if (getEncrypted()) {
if (_encryptionKey == null) throw new DataFormatException("Encryption key is not set");
_encryptionKey.writeBytes(baos);
_log.debug("IsEncrypted");
} else {
_log.debug("Is NOT Encrypted");
}
switch (getDeliveryMode()) {
case FLAG_MODE_LOCAL:
_log.debug("mode = local");
break;
case FLAG_MODE_DESTINATION:
if (_destinationHash == null) throw new DataFormatException("Destination hash is not set");
_destinationHash.writeBytes(baos);
_log.debug("mode = destination, hash = " + _destinationHash);
break;
case FLAG_MODE_ROUTER:
if (_routerHash == null) throw new DataFormatException("Router hash is not set");
_routerHash.writeBytes(baos);
_log.debug("mode = router, routerHash = " + _routerHash);
break;
case FLAG_MODE_TUNNEL:
if ( (_routerHash == null) || (_tunnelId == null) ) throw new DataFormatException("Router hash or tunnel ID is not set");
_routerHash.writeBytes(baos);
_tunnelId.writeBytes(baos);
_log.debug("mode = tunnel, tunnelId = " + _tunnelId.getTunnelId() + ", routerHash = " + _routerHash);
break;
}
if (getDelayRequested()) {
_log.debug("delay requested: " + getDelaySeconds());
DataHelper.writeLong(baos, 4, getDelaySeconds());
} else {
_log.debug("delay NOT requested");
}
} catch (IOException ioe) {
throw new DataFormatException("Unable to write out additional info", ioe);
}
return baos.toByteArray();
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if ( (_deliveryMode < 0) || (_deliveryMode > FLAG_MODE_TUNNEL) ) throw new DataFormatException("Invalid data: mode = " + _deliveryMode);
long flags = getFlags();
_log.debug("Write flags: " + flags + " mode: " + getDeliveryMode() + " =?= " + flagMode(flags));
byte additionalInfo[] = getAdditionalInfo();
DataHelper.writeLong(out, 1, flags);
if (additionalInfo != null) {
out.write(additionalInfo);
out.flush();
}
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof DeliveryInstructions))
return false;
DeliveryInstructions instr = (DeliveryInstructions)obj;
return (getDelayRequested() == instr.getDelayRequested()) &&
(getDelaySeconds() == instr.getDelaySeconds()) &&
(getDeliveryMode() == instr.getDeliveryMode()) &&
(getEncrypted() == instr.getEncrypted()) &&
DataHelper.eq(getDestination(), instr.getDestination()) &&
DataHelper.eq(getEncryptionKey(), instr.getEncryptionKey()) &&
DataHelper.eq(getRouter(), instr.getRouter()) &&
DataHelper.eq(getTunnelId(), instr.getTunnelId());
}
public int hashCode() {
return (int)getDelaySeconds() +
getDeliveryMode() +
DataHelper.hashCode(getDestination()) +
DataHelper.hashCode(getEncryptionKey()) +
DataHelper.hashCode(getRouter()) +
DataHelper.hashCode(getTunnelId());
}
public String toString() {
StringBuffer buf = new StringBuffer(128);
buf.append("[DeliveryInstructions: ");
buf.append("\n\tDelivery mode: ");
switch (getDeliveryMode()) {
case DELIVERY_MODE_LOCAL:
buf.append("local");
break;
case DELIVERY_MODE_DESTINATION:
buf.append("destination");
break;
case DELIVERY_MODE_ROUTER:
buf.append("router");
break;
case DELIVERY_MODE_TUNNEL:
buf.append("tunnel");
break;
}
buf.append("\n\tDelay requested: ").append(getDelayRequested());
buf.append("\n\tDelay seconds: ").append(getDelaySeconds());
buf.append("\n\tDestination: ").append(getDestination());
buf.append("\n\tEncrypted: ").append(getEncrypted());
buf.append("\n\tEncryption key: ").append(getEncryptionKey());
buf.append("\n\tRouter: ").append(getRouter());
buf.append("\n\tTunnelId: ").append(getTunnelId());
return buf.toString();
}
}

View File

@@ -0,0 +1,91 @@
package net.i2p.data.i2np;
/*
* 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 java.util.Date;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
/**
* Defines the message sent back in reply to a message when requested, containing
* the private ack id.
*
* @author jrandom
*/
public class DeliveryStatusMessage extends I2NPMessageImpl {
private final static Log _log = new Log(DeliveryStatusMessage.class);
public final static int MESSAGE_TYPE = 10;
private long _id;
private Date _arrival;
public DeliveryStatusMessage() {
setMessageId(-1);
setArrival(null);
}
public long getMessageId() { return _id; }
public void setMessageId(long id) { _id = id; }
public Date getArrival() { return _arrival; }
public void setArrival(Date arrival) { _arrival = arrival; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_id = DataHelper.readLong(in, 4);
_arrival = DataHelper.readDate(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_id < 0) || (_arrival == null) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
DataHelper.writeLong(os, 4, _id);
DataHelper.writeDate(os, _arrival);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return (int)getMessageId() +
DataHelper.hashCode(getArrival());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof DeliveryStatusMessage) ) {
DeliveryStatusMessage msg = (DeliveryStatusMessage)object;
return DataHelper.eq(getMessageId(),msg.getMessageId()) &&
DataHelper.eq(getArrival(),msg.getArrival());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[DeliveryStatusMessage: ");
buf.append("\n\tMessage ID: ").append(getMessageId());
buf.append("\n\tArrival: ").append(getArrival());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,62 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.PrivateKey;
/**
* Contains the private key which matches the EndPointPublicKey which, in turn,
* is published on the LeaseSet and used to encrypt messages to the router to
* which a Destination is currently connected.
*
* @author jrandom
*/
public class EndPointPrivateKey extends DataStructureImpl {
private final static Log _log = new Log(EndPointPrivateKey.class);
private PrivateKey _key;
public EndPointPrivateKey() { setKey(null); }
public PrivateKey getKey() { return _key; }
public void setKey(PrivateKey key) { _key= key; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_key = new PrivateKey();
_key.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_key == null) throw new DataFormatException("Invalid key");
_key.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof EndPointPublicKey))
return false;
return DataHelper.eq(getKey(), ((EndPointPublicKey)obj).getKey());
}
public int hashCode() {
if (_key == null) return 0;
return getKey().hashCode();
}
public String toString() {
return "[EndPointPrivateKey: " + getKey() + "]";
}
}

View File

@@ -0,0 +1,62 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.PublicKey;
/**
* Contains the public key which matches the EndPointPrivateKey. This is
* published on the LeaseSet and used to encrypt messages to the router to
* which a Destination is currently connected.
*
* @author jrandom
*/
public class EndPointPublicKey extends DataStructureImpl {
private final static Log _log = new Log(EndPointPublicKey.class);
private PublicKey _key;
public EndPointPublicKey() { setKey(null); }
public PublicKey getKey() { return _key; }
public void setKey(PublicKey key) { _key= key; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_key = new PublicKey();
_key.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_key == null) throw new DataFormatException("Invalid key");
_key.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof EndPointPublicKey))
return false;
return DataHelper.eq(getKey(), ((EndPointPublicKey)obj).getKey());
}
public int hashCode() {
if (_key == null) return 0;
return getKey().hashCode();
}
public String toString() {
return "[EndPointPublicKey: " + getKey() + "]";
}
}

View File

@@ -0,0 +1,171 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.Certificate;
import java.util.Date;
/**
* Contains one deliverable message encrypted to a router along with instructions
* and a certificate 'paying for' the delivery.
*
* @author jrandom
*/
public class GarlicClove extends DataStructureImpl {
private final static Log _log = new Log(GarlicClove.class);
private DeliveryInstructions _instructions;
private I2NPMessage _msg;
private long _cloveId;
private Date _expiration;
private Certificate _certificate;
private int _replyAction;
private SourceRouteBlock _sourceRouteBlock;
/** No action requested with the source route block */
public final static int ACTION_NONE = 0;
/**
* A DeliveryStatusMessage is requested with the source route block using
* the cloveId as the id received
*
*/
public final static int ACTION_STATUS = 1;
/**
* No DeliveryStatusMessage is requested, but the source route block is
* included for message specific replies
*
*/
public final static int ACTION_MESSAGE_SPECIFIC = 2;
public GarlicClove() {
setInstructions(null);
setData(null);
setCloveId(-1);
setExpiration(null);
setCertificate(null);
setSourceRouteBlockAction(ACTION_NONE);
setSourceRouteBlock(null);
}
public DeliveryInstructions getInstructions() { return _instructions; }
public void setInstructions(DeliveryInstructions instr) { _instructions = instr; }
public I2NPMessage getData() { return _msg; }
public void setData(I2NPMessage msg) { _msg = msg; }
public long getCloveId() { return _cloveId; }
public void setCloveId(long id) { _cloveId = id; }
public Date getExpiration() { return _expiration; }
public void setExpiration(Date exp) { _expiration = exp; }
public Certificate getCertificate() { return _certificate; }
public void setCertificate(Certificate cert) { _certificate = cert; }
public int getSourceRouteBlockAction() { return _replyAction; }
public void setSourceRouteBlockAction(int action) { _replyAction = action; }
public SourceRouteBlock getSourceRouteBlock() { return _sourceRouteBlock; }
public void setSourceRouteBlock(SourceRouteBlock block) { _sourceRouteBlock = block; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_instructions = new DeliveryInstructions();
_instructions.readBytes(in);
_log.debug("Read instructions: " + _instructions);
try {
_msg = new I2NPMessageHandler().readMessage(in);
} catch (I2NPMessageException ime) {
throw new DataFormatException("Unable to read the message from a garlic clove", ime);
}
_cloveId = DataHelper.readLong(in, 4);
_expiration = DataHelper.readDate(in);
_log.debug("CloveID read: " + _cloveId + " expiration read: " + _expiration);
_certificate = new Certificate();
_certificate.readBytes(in);
_log.debug("Read cert: " + _certificate);
int replyStyle = (int)DataHelper.readLong(in, 1);
setSourceRouteBlockAction(replyStyle);
if (replyStyle != ACTION_NONE) {
_sourceRouteBlock = new SourceRouteBlock();
_sourceRouteBlock.readBytes(in);
}
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
StringBuffer error = new StringBuffer();
if (_instructions == null)
error.append("No instructions ");
if (_msg == null)
error.append("No message ");
if (_cloveId < 0)
error.append("CloveID < 0 [").append(_cloveId).append("] ");
if (_expiration == null)
error.append("Expiration is null ");
if (_certificate == null)
error.append("Certificate is null ");
if (_replyAction < 0)
error.append("Reply action is < 0 [").append(_replyAction).append("] ");;
if (error.length() > 0)
throw new DataFormatException(error.toString());
if ( (_replyAction != 0) && (_sourceRouteBlock == null) )
throw new DataFormatException("Source route block must be specified for non-null action");
_instructions.writeBytes(out);
_log.debug("Wrote instructions: " + _instructions);
_msg.writeBytes(out);
DataHelper.writeLong(out, 4, _cloveId);
DataHelper.writeDate(out, _expiration);
_log.debug("CloveID written: " + _cloveId + " expiration written: " + _expiration);
_certificate.writeBytes(out);
_log.debug("Written cert: " + _certificate);
DataHelper.writeLong(out, 1, _replyAction);
if ( (_replyAction != 0) && (_sourceRouteBlock != null) )
_sourceRouteBlock.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof GarlicClove))
return false;
GarlicClove clove = (GarlicClove)obj;
return DataHelper.eq(getCertificate(), clove.getCertificate()) &&
DataHelper.eq(getCloveId(), clove.getCloveId()) &&
DataHelper.eq(getData(), clove.getData()) &&
DataHelper.eq(getExpiration(), clove.getExpiration()) &&
DataHelper.eq(getInstructions(), clove.getInstructions()) &&
DataHelper.eq(getSourceRouteBlock(), clove.getSourceRouteBlock()) &&
(getSourceRouteBlockAction() == clove.getSourceRouteBlockAction());
}
public int hashCode() {
return DataHelper.hashCode(getCertificate()) +
(int)getCloveId() +
DataHelper.hashCode(getData()) +
DataHelper.hashCode(getExpiration()) +
DataHelper.hashCode(getInstructions()) +
DataHelper.hashCode(getSourceRouteBlock()) +
getSourceRouteBlockAction();
}
public String toString() {
StringBuffer buf = new StringBuffer(128);
buf.append("[GarlicClove: ");
buf.append("\n\tInstructions: ").append(getInstructions());
buf.append("\n\tCertificate: ").append(getCertificate());
buf.append("\n\tClove ID: ").append(getCloveId());
buf.append("\n\tExpiration: ").append(getExpiration());
buf.append("\n\tSource route style: ").append(getSourceRouteBlockAction());
buf.append("\n\tSource route block: ").append(getSourceRouteBlock());
buf.append("\n\tData: ").append(getData());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,84 @@
package net.i2p.data.i2np;
/*
* 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 wrapped garlic message
*
* @author jrandom
*/
public class GarlicMessage extends I2NPMessageImpl {
private final static Log _log = new Log(GarlicMessage.class);
public final static int MESSAGE_TYPE = 11;
private byte[] _data;
public GarlicMessage() {
setData(null);
}
public byte[] getData() { return _data; }
public void setData(byte[] data) { _data = data; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
long len = DataHelper.readLong(in, 4);
_data = new byte[(int)len];
int read = read(in, _data);
if (read != len)
throw new I2NPMessageException("Incorrect size read");
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
DataHelper.writeLong(os, 4, _data.length);
os.write(_data);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getData());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof GarlicMessage) ) {
GarlicMessage msg = (GarlicMessage)object;
return DataHelper.eq(getData(),msg.getData());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[GarlicMessage: ");
buf.append("\n\tData length: ").append(getData().length).append(" bytes");
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,51 @@
package net.i2p.data.i2np;
/*
* 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.util.Date;
import net.i2p.data.DataStructure;
/**
* Base interface for all I2NP messages
*
* @author jrandom
*/
public interface I2NPMessage extends DataStructure {
/**
* Read the body into the data structures, after the initial type byte, using
* the current class's format as defined by the I2NP specification
*
* @param in stream to read from
* @param type I2NP message type
* @throws I2NPMessageException if the stream doesn't contain a valid message
* that this class can read.
* @throws IOException if there is a problem reading from the stream
*/
public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException;
/**
* Return the unique identifier for this type of I2NP message, as defined in
* the I2NP spec
*/
public int getType();
/**
* Replay resistent message Id
*/
public long getUniqueId();
/**
* Date after which the message should be dropped (and the associated uniqueId forgotten)
*
*/
public Date getMessageExpiration();
}

View File

@@ -0,0 +1,28 @@
package net.i2p.data.i2np;
/*
* 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 net.i2p.I2PException;
import net.i2p.util.Log;
/**
* Represent an error serializing or deserializing an APIMessage
*
* @author jrandom
*/
public class I2NPMessageException extends I2PException {
private final static Log _log = new Log(I2NPMessageException.class);
public I2NPMessageException(String message, Throwable parent) {
super(message, parent);
}
public I2NPMessageException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,92 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.IOException;
import java.io.FileInputStream;
import net.i2p.data.DataHelper;
import net.i2p.data.DataFormatException;
import net.i2p.util.Log;
import net.i2p.util.Clock;
/**
* Handle messages from router to router
*
*/
public class I2NPMessageHandler {
private final static Log _log = new Log(I2NPMessageHandler.class);
private long _lastReadBegin;
private long _lastReadEnd;
public I2NPMessageHandler() {}
/**
* Read an I2NPMessage from the stream and return the fully populated object.
*
* @throws IOException if there is an IO problem reading from the stream
* @throws I2NPMessageException if there is a problem handling the particular
* message - if it is an unknown type or has improper formatting, etc.
*/
public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException {
try {
int type = (int)DataHelper.readLong(in, 1);
_lastReadBegin = Clock.getInstance().now();
I2NPMessage msg = createMessage(in, type);
msg.readBytes(in, type);
_lastReadEnd = Clock.getInstance().now();
return msg;
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the message", dfe);
}
}
public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; }
/**
* Yes, this is fairly ugly, but its the only place it ever happens.
*
*/
private static I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException {
switch (type) {
case DatabaseStoreMessage.MESSAGE_TYPE:
return new DatabaseStoreMessage();
case DatabaseLookupMessage.MESSAGE_TYPE:
return new DatabaseLookupMessage();
case DatabaseSearchReplyMessage.MESSAGE_TYPE:
return new DatabaseSearchReplyMessage();
case DeliveryStatusMessage.MESSAGE_TYPE:
return new DeliveryStatusMessage();
case GarlicMessage.MESSAGE_TYPE:
return new GarlicMessage();
case TunnelMessage.MESSAGE_TYPE:
return new TunnelMessage();
case DataMessage.MESSAGE_TYPE:
return new DataMessage();
case SourceRouteReplyMessage.MESSAGE_TYPE:
return new SourceRouteReplyMessage();
case TunnelCreateMessage.MESSAGE_TYPE:
return new TunnelCreateMessage();
case TunnelCreateStatusMessage.MESSAGE_TYPE:
return new TunnelCreateStatusMessage();
default:
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
}
}
public static void main(String args[]) {
try {
I2NPMessage msg = new I2NPMessageHandler().readMessage(new FileInputStream(args[0]));
System.out.println(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,104 @@
package net.i2p.data.i2np;
/*
* 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.DataStructureImpl;
import net.i2p.util.Log;
import net.i2p.util.Clock;
import net.i2p.util.RandomSource;
/**
* Defines the base message implementation.
*
* @author jrandom
*/
public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPMessage {
private final static Log _log = new Log(I2NPMessageImpl.class);
private Date _expiration;
private long _uniqueId;
public final static long DEFAULT_EXPIRATION_MS = 1*60*1000; // 1 minute by default
public I2NPMessageImpl() {
_expiration = new Date(Clock.getInstance().now() + DEFAULT_EXPIRATION_MS);
_uniqueId = RandomSource.getInstance().nextInt(Integer.MAX_VALUE);
}
/**
* Write out the payload part of the message (not including the initial
* 1 byte type)
*
*/
protected abstract byte[] writeMessage() throws I2NPMessageException, IOException;
/**
* Read the body into the data structures, after the initial type byte and
* the uniqueId / expiration, using the current class's format as defined by
* the I2NP specification
*
* @param in stream to read from
* @param type I2NP message type
* @throws I2NPMessageException if the stream doesn't contain a valid message
* that this class can read.
* @throws IOException if there is a problem reading from the stream
*/
protected abstract void readMessage(InputStream in, int type) throws I2NPMessageException, IOException;
public void readBytes(InputStream in) throws DataFormatException, IOException {
try {
readBytes(in, -1);
} catch (I2NPMessageException ime) {
throw new DataFormatException("Bad bytes", ime);
}
}
public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException {
try {
if (type < 0)
type = (int)DataHelper.readLong(in, 1);
_uniqueId = DataHelper.readLong(in, 4);
_expiration = DataHelper.readDate(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the message header", dfe);
}
_log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
readMessage(in, type);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
try {
DataHelper.writeLong(out, 1, getType());
DataHelper.writeLong(out, 4, _uniqueId);
DataHelper.writeDate(out, _expiration);
_log.debug("Writing bytes: type = " + getType() + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
byte[] data = writeMessage();
out.write(data);
} catch (I2NPMessageException ime) {
throw new DataFormatException("Error writing out the I2NP message data", ime);
}
}
/**
* Replay resistent message Id
*/
public long getUniqueId() { return _uniqueId; }
public void setUniqueId(long id) { _uniqueId = id; }
/**
* Date after which the message should be dropped (and the associated uniqueId forgotten)
*
*/
public Date getMessageExpiration() { return _expiration; }
public void setMessageExpiration(Date exp) { _expiration = exp; }
}

View File

@@ -0,0 +1,139 @@
package net.i2p.data.i2np;
/*
* 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 net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
* The I2NPMessageReader reads an InputStream (using
* {@link I2NPMessageHandler I2NPMessageHandler}) and passes out events to a registered
* listener, where events are either messages being received, exceptions being
* thrown, or the connection being closed. Routers should use this rather
* than read from the stream themselves.
*
* @author jrandom
*/
public class I2NPMessageReader {
private final static Log _log = new Log(I2NPMessageReader.class);
private InputStream _stream;
private I2NPMessageEventListener _listener;
private I2NPMessageReaderRunner _reader;
private Thread _readerThread;
public I2NPMessageReader(InputStream stream, I2NPMessageEventListener lsnr) {
this(stream, lsnr, "I2NP Reader");
}
public I2NPMessageReader(InputStream stream, I2NPMessageEventListener lsnr, String name) {
_stream = stream;
setListener(lsnr);
_reader = new I2NPMessageReaderRunner();
_readerThread = new I2PThread(_reader);
_readerThread.setName(name);
_readerThread.setDaemon(true);
}
public void setListener(I2NPMessageEventListener lsnr) { _listener = lsnr; }
public I2NPMessageEventListener getListener() { return _listener; }
/**
* Instruct the reader to begin reading messages off the stream
*
*/
public void startReading() { _readerThread.start(); }
/**
* Have the already started reader pause its reading indefinitely
*
*/
public void pauseReading() { _reader.pauseRunner(); }
/**
* Resume reading after a pause
*
*/
public void resumeReading() { _reader.resumeRunner(); }
/**
* Cancel reading.
*
*/
public void stopReading() { _reader.cancelRunner(); }
/**
* Defines the different events the reader produces while reading the stream
*
*/
public static interface I2NPMessageEventListener {
/**
* Notify the listener that a message has been received from the given
* reader
*
*/
public void messageReceived(I2NPMessageReader reader, I2NPMessage message, long msToRead);
/**
* Notify the listener that an exception was thrown while reading from the given
* reader
*
*/
public void readError(I2NPMessageReader reader, Exception error);
/**
* Notify the listener that the stream the given reader was running off
* closed
*
*/
public void disconnected(I2NPMessageReader reader);
}
private class I2NPMessageReaderRunner implements Runnable {
private boolean _doRun;
private boolean _stayAlive;
private I2NPMessageHandler _handler;
public I2NPMessageReaderRunner() {
_doRun = true;
_stayAlive = true;
_handler = new I2NPMessageHandler();
}
public void pauseRunner() { _doRun = false; }
public void resumeRunner() { _doRun = true; }
public void cancelRunner() {
_doRun = false;
_stayAlive = false;
}
public void run() {
while (_stayAlive) {
while (_doRun) {
// do read
try {
I2NPMessage msg = _handler.readMessage(_stream);
if (msg != null) {
long msToRead = _handler.getLastReadTime();
_listener.messageReceived(I2NPMessageReader.this, msg, msToRead);
}
} catch (I2NPMessageException ime) {
//_log.warn("Error handling message", ime);
_listener.readError(I2NPMessageReader.this, ime);
_listener.disconnected(I2NPMessageReader.this);
cancelRunner();
} catch (IOException ioe) {
_log.warn("IO Error handling message", ioe);
_listener.disconnected(I2NPMessageReader.this);
cancelRunner();
}
}
if (!_doRun) {
// pause .5 secs when we're paused
try { Thread.sleep(500); } catch (InterruptedException ie) {}
}
}
// boom bye bye bad bwoy
}
}
}

View File

@@ -0,0 +1,225 @@
package net.i2p.data.i2np;
/*
* 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 java.io.OutputStream;
import java.util.Date;
import net.i2p.crypto.ElGamalAESEngine;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.SessionKeyManager;
import net.i2p.data.Certificate;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.util.Log;
/**
* Defines a single hop of a source routed message, as usable for building a
* SourceRouteReplyMessage
*
* @author jrandom
*/
public class SourceRouteBlock extends DataStructureImpl {
private final static Log _log = new Log(SourceRouteBlock.class);
private Hash _router;
private byte[] _data;
private SessionKey _key;
private byte[] _tag;
private DeliveryInstructions _decryptedInstructions;
private long _decryptedMessageId;
private Certificate _decryptedCertificate;
private long _decryptedExpiration;
public SourceRouteBlock() {
setRouter(null);
setData(null);
setKey(null);
setTag((byte[])null);
_decryptedInstructions = null;
_decryptedMessageId = -1;
_decryptedCertificate = null;
_decryptedExpiration = -1;
}
/**
* Get the router through which replies using this source route block must
* be sent (as the getData() is encrypted for their eyes only)
*
*/
public Hash getRouter() { return _router; }
public void setRouter(Hash router) { _router= router; }
/**
* Get the encrypted header. After decryption (via ElGamal+AES as defined
* in the data structures spec), this array contains:
* DeliveryInstructions
* 4 byte Integer for a message ID
* Certificate
* Date of expiration for replies
*
*/
public byte[] getData() { return _data; }
private void setData(byte data[]) { _data = data; }
/**
* Retrieve the session key which may be used in conjunction with the tag
* to encrypt a garlic message and send it as a reply to this message.
* The encryption would follow scenario 2 of the ElGamal+AES encryption method
* defined in the data structures spec.
*
*/
public SessionKey getKey() { return _key; }
public void setKey(SessionKey key) { _key = key; }
/**
* Get the tag made available for use in conjunction with the getKey() to
* ElGamal+AES encrypt a garlic message without knowing the public key to
* which the message is destined
*
*/
public byte[] getTag() { return _tag; }
public void setTag(SessionTag tag) { setTag(tag.getData()); }
public void setTag(byte tag[]) {
if ( (tag != null) && (tag.length != SessionTag.BYTE_LENGTH) )
throw new IllegalArgumentException("Tag must be either null or 32 bytes");
_tag = tag;
}
/**
* After decryptData, this contains the delivery instructions for this block
*/
public DeliveryInstructions getDecryptedInstructions() { return _decryptedInstructions; }
/**
* After decryptData, this contains the message ID to be used with this block
*/
public long getDecryptedMessageId() { return _decryptedMessageId; }
/**
* After decryptData, this contains the Certificate 'paying' for the forwarding according to
* this block
*/
public Certificate getDecryptedCertificate() { return _decryptedCertificate; }
/**
* After decryptData, this contains the date after which this block should not be forwarded
*/
public long getDecryptedExpiration() { return _decryptedExpiration; }
/**
* Set the raw data with the formatted and encrypted options specified
*
* @param instructions Where a message bearing this block should be sent
* @param messageId ID of the message for this block (not repeatable)
* @param expiration date after which this block expires
* @param replyThrough Encryption key of the router to whom this block is specified (not
* the router specified in the delivery instructions!)
*
* @throws DataFormatException if the data is invalid or could not be encrypted
*/
public void setData(DeliveryInstructions instructions, long messageId, Certificate cert, long expiration, PublicKey replyThrough) throws DataFormatException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
_decryptedInstructions = instructions;
_decryptedMessageId = messageId;
_decryptedCertificate = cert;
_decryptedExpiration = expiration;
instructions.writeBytes(baos);
DataHelper.writeLong(baos, 4, messageId);
cert.writeBytes(baos);
DataHelper.writeDate(baos, new Date(expiration));
int paddedSize = 256;
SessionKey sessKey = null;
SessionTag tag = null;
if (instructions.getDelayRequested()) {
// always use a new key if we're delaying, since the reply block may not be used within the
// window of a session
sessKey = KeyGenerator.getInstance().generateSessionKey();
tag = null;
_log.debug("Delay requested - creating a new session key");
} else {
sessKey = SessionKeyManager.getInstance().getCurrentKey(replyThrough);
if (sessKey == null) {
sessKey = KeyGenerator.getInstance().generateSessionKey();
tag = null;
_log.debug("No delay requested, but no session key is known");
} else {
tag = SessionKeyManager.getInstance().consumeNextAvailableTag(replyThrough, sessKey);
}
}
byte encData[] = ElGamalAESEngine.encrypt(baos.toByteArray(), replyThrough, sessKey, null, tag, paddedSize);
setData(encData);
} catch (IOException ioe) {
throw new DataFormatException("Error writing out the source route block data", ioe);
} catch (DataFormatException dfe) {
throw new DataFormatException("Error writing out the source route block data", dfe);
}
}
public void readBytes(InputStream in) throws DataFormatException, IOException {
_router = new Hash();
_router.readBytes(in);
int size = (int)DataHelper.readLong(in, 2);
_data = new byte[size];
int read = read(in, _data);
if (read != _data.length)
throw new DataFormatException("Incorrect # of bytes read for source route block: " + read);
_key = new SessionKey();
_key.readBytes(in);
_tag = new byte[32];
read = read(in, _tag);
if (read != _tag.length)
throw new DataFormatException("Incorrect # of bytes read for session tag: " + read);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if ( (_router == null) || (_data == null) || (_key == null) || (_tag == null) || (_tag.length != 32) )
throw new DataFormatException("Insufficient data to write");
_router.writeBytes(out);
DataHelper.writeLong(out, 2, _data.length);
out.write(_data);
_key.writeBytes(out);
out.write(_tag);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof SourceRouteBlock))
return false;
SourceRouteBlock block = (SourceRouteBlock)obj;
return DataHelper.eq(getRouter(), block.getRouter()) &&
DataHelper.eq(getData(), block.getData()) &&
DataHelper.eq(getKey(), block.getKey()) &&
DataHelper.eq(getTag(), block.getTag());
}
public int hashCode() {
return DataHelper.hashCode(getRouter()) +
DataHelper.hashCode(getData()) +
DataHelper.hashCode(getKey()) +
DataHelper.hashCode(getTag());
}
public String toString() {
StringBuffer buf = new StringBuffer(128);
buf.append("[SourceRouteBlock: ");
buf.append("\n\tRouter: ").append(getRouter());
buf.append("\n\tData: ").append(DataHelper.toString(getData(), getData().length));
buf.append("\n\tTag: ").append(DataHelper.toString(getTag(), (getTag() != null ? getTag().length : 0)));
buf.append("\n\tKey: ").append(getKey());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,159 @@
package net.i2p.data.i2np;
/*
* 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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import net.i2p.crypto.ElGamalAESEngine;
import net.i2p.data.Certificate;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.PrivateKey;
import net.i2p.util.Log;
/**
* Defines a message directed by a source route block to deliver a message to an
* unknown location.
*
* @author jrandom
*/
public class SourceRouteReplyMessage extends I2NPMessageImpl {
private final static Log _log = new Log(SourceRouteReplyMessage.class);
public final static int MESSAGE_TYPE = 13;
private byte _encryptedHeader[];
private I2NPMessage _message;
private DeliveryInstructions _decryptedInstructions;
private long _decryptedMessageId;
private Certificate _decryptedCertificate;
private long _decryptedExpiration;
public SourceRouteReplyMessage() {
_encryptedHeader = null;
_message = null;
_decryptedInstructions = null;
_decryptedMessageId = -1;
_decryptedCertificate = null;
_decryptedExpiration = -1;
}
/**
* Retrieve the message being sent as a reply
*/
public I2NPMessage getMessage() { return _message; }
public void setMessage(I2NPMessage message) { _message = message; }
public void setEncryptedHeader(byte header[]) { _encryptedHeader = header; }
/**
* After decryptHeader, this contains the delivery instructions for this block
*/
public DeliveryInstructions getDecryptedInstructions() { return _decryptedInstructions; }
/**
* After decryptHeader, this contains the message ID to be used with this block
*/
public long getDecryptedMessageId() { return _decryptedMessageId; }
/**
* After decryptHeader, this contains the Certificate 'paying' for the forwarding according to
* this block
*/
public Certificate getDecryptedCertificate() { return _decryptedCertificate; }
/**
* After decryptHeader, this contains the date after which this block should not be forwarded
*/
public long getDecryptedExpiration() { return _decryptedExpiration; }
/**
* Decrypt the header and store it in the various getDecryptedXYZ() properties
*
* @throws DataFormatException if the decryption fails or if the data is somehow malformed
*/
public void decryptHeader(PrivateKey key) throws DataFormatException {
if ( (_encryptedHeader == null) || (_encryptedHeader.length <= 0) )
throw new DataFormatException("No header to decrypt");
byte decr[] = ElGamalAESEngine.decrypt(_encryptedHeader, key);
if (decr == null)
throw new DataFormatException("Decrypted data is null");
try {
ByteArrayInputStream bais = new ByteArrayInputStream(decr);
_decryptedInstructions = new DeliveryInstructions();
_decryptedInstructions.readBytes(bais);
_decryptedMessageId = DataHelper.readLong(bais, 4);
_decryptedCertificate = new Certificate();
_decryptedCertificate.readBytes(bais);
_decryptedExpiration = DataHelper.readDate(bais).getTime();
} catch (IOException ioe) {
throw new DataFormatException("Error reading the source route reply header", ioe);
} catch (DataFormatException dfe) {
throw new DataFormatException("Error reading the source route reply header", dfe);
}
}
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
int headerSize = (int)DataHelper.readLong(in, 2);
_encryptedHeader = new byte[headerSize];
int read = read(in, _encryptedHeader);
if (read != headerSize)
throw new DataFormatException("Not enough bytes to read the header (read = " + read + ", required = " + headerSize + ")");
_message = new I2NPMessageHandler().readMessage(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_encryptedHeader == null) || (_message == null) )
throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
try {
DataHelper.writeLong(os, 2, _encryptedHeader.length);
os.write(_encryptedHeader);
_message.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(_encryptedHeader) +
DataHelper.hashCode(_message);
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof SourceRouteReplyMessage) ) {
SourceRouteReplyMessage msg = (SourceRouteReplyMessage)object;
return DataHelper.eq(_message,msg._message) &&
DataHelper.eq(_encryptedHeader,msg._encryptedHeader);
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[SourceRouteReplyMessage: ");
buf.append("\n\tHeader: ").append(DataHelper.toString(_encryptedHeader, 64));
buf.append("\n\tMessage: ").append(_message);
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,61 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.SessionKey;
/**
* Contains the session key used by the owner/creator of the tunnel to modify
* its operational settings.
*
* @author jrandom
*/
public class TunnelConfigurationSessionKey extends DataStructureImpl {
private final static Log _log = new Log(TunnelConfigurationSessionKey.class);
private SessionKey _key;
public TunnelConfigurationSessionKey() { setKey(null); }
public SessionKey getKey() { return _key; }
public void setKey(SessionKey key) { _key= key; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_key = new SessionKey();
_key.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_key == null) throw new DataFormatException("Invalid key");
_key.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof TunnelConfigurationSessionKey))
return false;
return DataHelper.eq(getKey(), ((TunnelConfigurationSessionKey)obj).getKey());
}
public int hashCode() {
if (_key == null) return 0;
return getKey().hashCode();
}
public String toString() {
return "[TunnelConfigurationSessionKey: " + getKey() + "]";
}
}

View File

@@ -0,0 +1,312 @@
package net.i2p.data.i2np;
/*
* 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.Certificate;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.TunnelId;
import net.i2p.util.Log;
/**
* Defines the message sent to a router to request that it participate in a
* tunnel using the included configuration settings.
*
* @author jrandom
*/
public class TunnelCreateMessage extends I2NPMessageImpl {
private final static Log _log = new Log(TunnelCreateMessage.class);
public final static int MESSAGE_TYPE = 6;
private int _participantType;
private Hash _nextRouter;
private TunnelId _tunnelId;
private long _tunnelDuration;
private TunnelConfigurationSessionKey _configKey;
private long _maxPeakMessagesPerMin;
private long _maxAvgMessagesPerMin;
private long _maxPeakBytesPerMin;
private long _maxAvgBytesPerMin;
private boolean _includeDummyTraffic;
private boolean _reorderMessages;
private TunnelSigningPublicKey _verificationPubKey;
private TunnelSigningPrivateKey _verificationPrivKey;
private TunnelSessionKey _tunnelKey;
private Certificate _certificate;
private SourceRouteBlock _replyBlock;
public static final int PARTICIPANT_TYPE_GATEWAY = 1;
public static final int PARTICIPANT_TYPE_ENDPOINT = 2;
public static final int PARTICIPANT_TYPE_OTHER = 3;
private final static long FLAG_DUMMY = 1 << 7;
private final static long FLAG_REORDER = 1 << 6;
public TunnelCreateMessage() {
setParticipantType(-1);
setNextRouter(null);
setTunnelId(null);
setTunnelDurationSeconds(-1);
setConfigurationKey(null);
setMaxPeakMessagesPerMin(-1);
setMaxAvgMessagesPerMin(-1);
setMaxPeakBytesPerMin(-1);
setMaxAvgBytesPerMin(-1);
setIncludeDummyTraffic(false);
setReorderMessages(false);
setVerificationPublicKey(null);
setVerificationPrivateKey(null);
setTunnelKey(null);
setCertificate(null);
setReplyBlock(null);
}
public void setParticipantType(int type) { _participantType = type; }
public int getParticipantType() { return _participantType; }
public void setNextRouter(Hash routerIdentityHash) { _nextRouter = routerIdentityHash; }
public Hash getNextRouter() { return _nextRouter; }
public void setTunnelId(TunnelId id) { _tunnelId = id; }
public TunnelId getTunnelId() { return _tunnelId; }
public void setTunnelDurationSeconds(long durationSeconds) { _tunnelDuration = durationSeconds; }
public long getTunnelDurationSeconds() { return _tunnelDuration; }
public void setConfigurationKey(TunnelConfigurationSessionKey key) { _configKey = key; }
public TunnelConfigurationSessionKey getConfigurationKey() { return _configKey; }
public void setMaxPeakMessagesPerMin(long msgs) { _maxPeakMessagesPerMin = msgs; }
public long getMaxPeakMessagesPerMin() { return _maxPeakMessagesPerMin; }
public void setMaxAvgMessagesPerMin(long msgs) { _maxAvgMessagesPerMin = msgs; }
public long getMaxAvgMessagesPerMin() { return _maxAvgMessagesPerMin; }
public void setMaxPeakBytesPerMin(long bytes) { _maxPeakBytesPerMin = bytes; }
public long getMaxPeakBytesPerMin() { return _maxPeakBytesPerMin; }
public void setMaxAvgBytesPerMin(long bytes) { _maxAvgBytesPerMin = bytes; }
public long getMaxAvgBytesPerMin() { return _maxAvgBytesPerMin; }
public void setIncludeDummyTraffic(boolean include) { _includeDummyTraffic = include; }
public boolean getIncludeDummyTraffic() { return _includeDummyTraffic; }
public void setReorderMessages(boolean reorder) { _reorderMessages = reorder; }
public boolean getReorderMessages() { return _reorderMessages; }
public void setVerificationPublicKey(TunnelSigningPublicKey key) { _verificationPubKey = key; }
public TunnelSigningPublicKey getVerificationPublicKey() { return _verificationPubKey; }
public void setVerificationPrivateKey(TunnelSigningPrivateKey key) { _verificationPrivKey = key; }
public TunnelSigningPrivateKey getVerificationPrivateKey() { return _verificationPrivKey; }
public void setTunnelKey(TunnelSessionKey key) { _tunnelKey = key; }
public TunnelSessionKey getTunnelKey() { return _tunnelKey; }
public void setCertificate(Certificate cert) { _certificate = cert; }
public Certificate getCertificate() { return _certificate; }
public void setReplyBlock(SourceRouteBlock block) { _replyBlock = block; }
public SourceRouteBlock getReplyBlock() { return _replyBlock; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_participantType = (int)DataHelper.readLong(in, 1);
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
_nextRouter = new Hash();
_nextRouter.readBytes(in);
}
_tunnelId = new TunnelId();
_tunnelId.readBytes(in);
_tunnelDuration = DataHelper.readLong(in, 4);
_configKey = new TunnelConfigurationSessionKey();
_configKey.readBytes(in);
_maxPeakMessagesPerMin = DataHelper.readLong(in, 4);
_maxAvgMessagesPerMin = DataHelper.readLong(in, 4);
_maxPeakBytesPerMin = DataHelper.readLong(in, 4);
_maxAvgBytesPerMin = DataHelper.readLong(in, 4);
int flags = (int)DataHelper.readLong(in, 1);
_includeDummyTraffic = flagsIncludeDummy(flags);
_reorderMessages = flagsReorder(flags);
_verificationPubKey = new TunnelSigningPublicKey();
_verificationPubKey.readBytes(in);
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
_verificationPrivKey = new TunnelSigningPrivateKey();
_verificationPrivKey.readBytes(in);
}
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
_tunnelKey = new TunnelSessionKey();
_tunnelKey.readBytes(in);
}
_certificate = new Certificate();
_certificate.readBytes(in);
_replyBlock = new SourceRouteBlock();
_replyBlock.readBytes(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
DataHelper.writeLong(os, 1, _participantType);
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
_nextRouter.writeBytes(os);
}
_tunnelId.writeBytes(os);
DataHelper.writeLong(os, 4, _tunnelDuration);
_configKey.writeBytes(os);
DataHelper.writeLong(os, 4, _maxPeakMessagesPerMin);
DataHelper.writeLong(os, 4, _maxAvgMessagesPerMin);
DataHelper.writeLong(os, 4, _maxPeakBytesPerMin);
DataHelper.writeLong(os, 4, _maxAvgBytesPerMin);
long flags = getFlags();
DataHelper.writeLong(os, 1, flags);
_verificationPubKey.writeBytes(os);
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
_verificationPrivKey.writeBytes(os);
}
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
_tunnelKey.writeBytes(os);
}
_certificate.writeBytes(os);
_replyBlock.writeBytes(os);
} catch (Throwable t) {
throw new I2NPMessageException("Error writing out the message data", t);
}
/*
try {
DataHelper.writeLong(os, 1, _participantType);
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
if (_nextRouter == null)
throw new I2NPMessageException("Next router is not defined");
_nextRouter.writeBytes(os);
}
if (_tunnelId == null)
throw new I2NPMessageException("Tunnel ID is not defined");
_tunnelId.writeBytes(os);
if (_tunnelDuration < 0)
throw new I2NPMessageException("Tunnel duration is negative");
DataHelper.writeLong(os, 4, _tunnelDuration);
if (_configKey == null)
throw new I2NPMessageException("Configuration key is not defined");
_configKey.writeBytes(os);
if ( (_maxPeakMessagesPerMin < 0) || (_maxAvgMessagesPerMin < 0) ||
(_maxAvgMessagesPerMin < 0) || (_maxAvgBytesPerMin < 0) )
throw new I2NPMessageException("Negative limits defined");
long flags = getFlags();
DataHelper.writeLong(os, 1, flags);
if (_verificationPubKey == null)
throw new I2NPMessageException("Verification public key is not defined");
_verificationPubKey.writeBytes(os);
if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
if (_verificationPrivKey == null)
throw new I2NPMessageException("Verification private key is needed and not defined");
_verificationPrivKey.writeBytes(os);
}
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
if (_tunnelKey == null)
throw new I2NPMessageException("Tunnel key is needed and not defined");
_tunnelKey.writeBytes(os);
}
if (_certificate == null)
throw new I2NPMessageException("Certificate is not defined");
_certificate.writeBytes(os);
if (_replyBlock == null)
throw new I2NPMessageException("Reply block not defined");
_replyBlock.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
*/
return os.toByteArray();
}
private boolean flagsIncludeDummy(long flags) {
return (0 != (flags & FLAG_DUMMY));
}
private boolean flagsReorder(long flags) {
return (0 != (flags & FLAG_REORDER));
}
private long getFlags() {
long val = 0L;
if (getIncludeDummyTraffic())
val = val | FLAG_DUMMY;
if (getReorderMessages())
val = val | FLAG_REORDER;
return val;
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return (int)(DataHelper.hashCode(getCertificate()) +
DataHelper.hashCode(getConfigurationKey()) +
DataHelper.hashCode(getNextRouter()) +
DataHelper.hashCode(getReplyBlock()) +
DataHelper.hashCode(getTunnelId()) +
DataHelper.hashCode(getTunnelKey()) +
DataHelper.hashCode(getVerificationPrivateKey()) +
DataHelper.hashCode(getVerificationPublicKey()) +
(getIncludeDummyTraffic() ? 1 : 0) +
getMaxAvgBytesPerMin() +
getMaxAvgMessagesPerMin() +
getMaxPeakBytesPerMin() +
getMaxPeakMessagesPerMin() +
getParticipantType() +
(getReorderMessages() ? 1 : 0) +
getTunnelDurationSeconds());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof TunnelCreateMessage) ) {
TunnelCreateMessage msg = (TunnelCreateMessage)object;
return DataHelper.eq(getCertificate(), msg.getCertificate()) &&
DataHelper.eq(getConfigurationKey(), msg.getConfigurationKey()) &&
DataHelper.eq(getNextRouter(), msg.getNextRouter()) &&
DataHelper.eq(getReplyBlock(), msg.getReplyBlock()) &&
DataHelper.eq(getTunnelId(), msg.getTunnelId()) &&
DataHelper.eq(getTunnelKey(), msg.getTunnelKey()) &&
DataHelper.eq(getVerificationPrivateKey(), msg.getVerificationPrivateKey()) &&
DataHelper.eq(getVerificationPublicKey(), msg.getVerificationPublicKey()) &&
(getIncludeDummyTraffic() == msg.getIncludeDummyTraffic()) &&
(getMaxAvgBytesPerMin() == msg.getMaxAvgBytesPerMin()) &&
(getMaxAvgMessagesPerMin() == msg.getMaxAvgMessagesPerMin()) &&
(getMaxPeakBytesPerMin() == msg.getMaxPeakBytesPerMin()) &&
(getMaxPeakMessagesPerMin() == msg.getMaxPeakMessagesPerMin()) &&
(getParticipantType() == msg.getParticipantType()) &&
(getReorderMessages() == msg.getReorderMessages()) &&
(getTunnelDurationSeconds() == msg.getTunnelDurationSeconds());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[TunnelCreateMessage: ");
buf.append("\n\tParticipant Type: ").append(getParticipantType());
buf.append("\n\tCertificate: ").append(getCertificate());
buf.append("\n\tConfiguration Key: ").append(getConfigurationKey());
buf.append("\n\tNext Router: ").append(getNextRouter());
buf.append("\n\tReply Block: ").append(getReplyBlock());
buf.append("\n\tTunnel ID: ").append(getTunnelId());
buf.append("\n\tTunnel Key: ").append(getTunnelKey());
buf.append("\n\tVerification Private Key: ").append(getVerificationPrivateKey());
buf.append("\n\tVerification Public Key: ").append(getVerificationPublicKey());
buf.append("\n\tInclude Dummy Traffic: ").append(getIncludeDummyTraffic());
buf.append("\n\tMax Avg Bytes / Minute: ").append(getMaxAvgBytesPerMin());
buf.append("\n\tMax Peak Bytes / Minute: ").append(getMaxPeakBytesPerMin());
buf.append("\n\tMax Avg Messages / Minute: ").append(getMaxAvgMessagesPerMin());
buf.append("\n\tMax Peak Messages / Minute: ").append(getMaxPeakMessagesPerMin());
buf.append("\n\tReorder Messages: ").append(getReorderMessages());
buf.append("\n\tTunnel Duration (seconds): ").append(getTunnelDurationSeconds());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,113 @@
package net.i2p.data.i2np;
/*
* 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.data.Hash;
import net.i2p.data.TunnelId;
import net.i2p.util.Log;
/**
* Defines the message a router sends to another router in reply to a
* TunnelCreateMessage
*
* @author jrandom
*/
public class TunnelCreateStatusMessage extends I2NPMessageImpl {
private final static Log _log = new Log(TunnelCreateStatusMessage.class);
public final static int MESSAGE_TYPE = 7;
private TunnelId _tunnelId;
private int _status;
private Hash _from;
public final static int STATUS_SUCCESS = 0;
public final static int STATUS_FAILED_DUPLICATE_ID = 1;
public final static int STATUS_FAILED_OVERLOADED = 2;
public final static int STATUS_FAILED_CERTIFICATE = 3;
public final static int STATUS_FAILED_DELETED = 100;
public TunnelCreateStatusMessage() {
setTunnelId(null);
setStatus(-1);
setFromHash(null);
}
public TunnelId getTunnelId() { return _tunnelId; }
public void setTunnelId(TunnelId id) { _tunnelId = id; }
public int getStatus() { return _status; }
public void setStatus(int status) { _status = status; }
/**
* Contains the SHA256 Hash of the RouterIdentity sending the message
*/
public Hash getFromHash() { return _from; }
public void setFromHash(Hash from) { _from = from; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_tunnelId = new TunnelId();
_tunnelId.readBytes(in);
_status = (int)DataHelper.readLong(in, 1);
_from = new Hash();
_from.readBytes(in);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
_tunnelId.writeBytes(os);
DataHelper.writeLong(os, 1, (_status < 0 ? 255 : _status));
_from.writeBytes(os);
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
return os.toByteArray();
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getTunnelId()) +
getStatus() +
DataHelper.hashCode(getFromHash());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof TunnelCreateStatusMessage) ) {
TunnelCreateStatusMessage msg = (TunnelCreateStatusMessage)object;
return DataHelper.eq(getTunnelId(),msg.getTunnelId()) &&
DataHelper.eq(getFromHash(),msg.getFromHash()) &&
(getStatus() == msg.getStatus());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[TunnelCreateStatusMessage: ");
buf.append("\n\tTunnel ID: ").append(getTunnelId());
buf.append("\n\tStatus: ").append(getStatus());
buf.append("\n\tFrom: ").append(getFromHash());
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,145 @@
package net.i2p.data.i2np;
/*
* 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.data.TunnelId;
import net.i2p.util.Log;
/**
* Defines the message sent between routers for tunnel delivery
*
* @author jrandom
*/
public class TunnelMessage extends I2NPMessageImpl {
private final static Log _log = new Log(TunnelMessage.class);
public final static int MESSAGE_TYPE = 8;
private TunnelId _tunnelId;
private long _size;
private byte[] _data;
private TunnelVerificationStructure _verification;
private byte[] _encryptedInstructions;
private final static int FLAG_INCLUDESTRUCTURE = 0;
private final static int FLAG_DONT_INCLUDESTRUCTURE = 1;
public TunnelMessage() {
setTunnelId(null);
setData(null);
setVerificationStructure(null);
setEncryptedDeliveryInstructions(null);
}
public TunnelId getTunnelId() { return _tunnelId; }
public void setTunnelId(TunnelId id) { _tunnelId = id; }
public byte[] getData() { return _data; }
public void setData(byte data[]) { _data = data; }
public TunnelVerificationStructure getVerificationStructure() { return _verification; }
public void setVerificationStructure(TunnelVerificationStructure verification) { _verification = verification; }
public byte[] getEncryptedDeliveryInstructions() { return _encryptedInstructions; }
public void setEncryptedDeliveryInstructions(byte instructions[]) { _encryptedInstructions = instructions; }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
try {
_tunnelId = new TunnelId();
_tunnelId.readBytes(in);
_log.debug("Read tunnel message for tunnel " + _tunnelId);
_size = DataHelper.readLong(in, 4);
_log.debug("Read tunnel message size: " + _size);
if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size);
_data = new byte[(int)_size];
int read = read(in, _data);
if (read != _size)
throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size);
int includeVerification = (int)DataHelper.readLong(in, 1);
if (includeVerification == FLAG_INCLUDESTRUCTURE) {
_verification = new TunnelVerificationStructure();
_verification.readBytes(in);
int len = (int)DataHelper.readLong(in, 2);
_encryptedInstructions = new byte[len];
read = read(in, _encryptedInstructions);
if (read != len)
throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")");
}
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe);
}
}
protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) )
throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try {
_tunnelId.writeBytes(os);
_log.debug("Writing tunnel message for tunnel " + _tunnelId);
DataHelper.writeLong(os, 4, _data.length);
_log.debug("Writing tunnel message length: " + _data.length);
os.write(_data);
_log.debug("Writing tunnel message data");
if ( (_verification == null) || (_encryptedInstructions == null) ) {
DataHelper.writeLong(os, 1, FLAG_DONT_INCLUDESTRUCTURE);
_log.debug("Writing DontIncludeStructure flag");
} else {
DataHelper.writeLong(os, 1, FLAG_INCLUDESTRUCTURE);
_log.debug("Writing IncludeStructure flag, then the verification structure, then the E(instr).length [" + _encryptedInstructions.length + "], then the E(instr)");
_verification.writeBytes(os);
DataHelper.writeLong(os, 2, _encryptedInstructions.length);
os.write(_encryptedInstructions);
}
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe);
}
byte rv[] = os.toByteArray();
_log.debug("Overall data being written: " + rv.length);
return rv;
}
public int getType() { return MESSAGE_TYPE; }
public int hashCode() {
return DataHelper.hashCode(getTunnelId()) +
DataHelper.hashCode(_data) +
DataHelper.hashCode(getVerificationStructure()) +
DataHelper.hashCode(getEncryptedDeliveryInstructions());
}
public boolean equals(Object object) {
if ( (object != null) && (object instanceof TunnelMessage) ) {
TunnelMessage msg = (TunnelMessage)object;
return DataHelper.eq(getTunnelId(),msg.getTunnelId()) &&
DataHelper.eq(getVerificationStructure(),msg.getVerificationStructure()) &&
DataHelper.eq(getData(),msg.getData()) &&
DataHelper.eq(getEncryptedDeliveryInstructions(), msg.getEncryptedDeliveryInstructions());
} else {
return false;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[TunnelMessage: ");
buf.append("\n\tTunnel ID: ").append(getTunnelId());
buf.append("\n\tVerification Structure: ").append(getVerificationStructure());
buf.append("\n\tEncrypted Instructions: ").append(getEncryptedDeliveryInstructions());
buf.append("\n\tData size: ").append(getData().length);
buf.append("]");
return buf.toString();
}
}

View File

@@ -0,0 +1,61 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.SessionKey;
/**
* Contains the session key used by the tunnel gateway to encrypt the DeliveryInstructions
* and used by the tunnel end point to decrypt those instructions.
*
* @author jrandom
*/
public class TunnelSessionKey extends DataStructureImpl {
private final static Log _log = new Log(TunnelSessionKey.class);
private SessionKey _key;
public TunnelSessionKey() { setKey(null); }
public SessionKey getKey() { return _key; }
public void setKey(SessionKey key) { _key= key; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_key = new SessionKey();
_key.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_key == null) throw new DataFormatException("Invalid key");
_key.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof TunnelSessionKey))
return false;
return DataHelper.eq(getKey(), ((TunnelSessionKey)obj).getKey());
}
public int hashCode() {
if (_key == null) return 0;
return getKey().hashCode();
}
public String toString() {
return "[TunnelSessionKey: " + getKey() + "]";
}
}

View File

@@ -0,0 +1,62 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.SigningPrivateKey;
/**
* Contains the private key which constructs a signature for the TunnelMessage
* which every participant in a tunnel uses to verify the
* TunnelVerificationStructure with.
*
* @author jrandom
*/
public class TunnelSigningPrivateKey extends DataStructureImpl {
private final static Log _log = new Log(EndPointPrivateKey.class);
private SigningPrivateKey _key;
public TunnelSigningPrivateKey() { setKey(null); }
public SigningPrivateKey getKey() { return _key; }
public void setKey(SigningPrivateKey key) { _key= key; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_key = new SigningPrivateKey();
_key.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_key == null) throw new DataFormatException("Invalid key");
_key.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof TunnelSigningPrivateKey))
return false;
return DataHelper.eq(getKey(), ((TunnelSigningPrivateKey)obj).getKey());
}
public int hashCode() {
if (_key == null) return 0;
return getKey().hashCode();
}
public String toString() {
return "[EndPointPrivateKey: " + getKey() + "]";
}
}

View File

@@ -0,0 +1,61 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.SigningPublicKey;
/**
* Contains the public key which every participant in a tunnel uses to verify
* the TunnelVerificationStructure for TunnelMessages that pass by.
*
* @author jrandom
*/
public class TunnelSigningPublicKey extends DataStructureImpl {
private final static Log _log = new Log(TunnelSigningPublicKey.class);
private SigningPublicKey _key;
public TunnelSigningPublicKey() { setKey(null); }
public SigningPublicKey getKey() { return _key; }
public void setKey(SigningPublicKey key) { _key= key; }
public void readBytes(InputStream in) throws DataFormatException, IOException {
_key = new SigningPublicKey();
_key.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_key == null) throw new DataFormatException("Invalid key");
_key.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof TunnelSigningPublicKey))
return false;
return DataHelper.eq(getKey(), ((TunnelSigningPublicKey)obj).getKey());
}
public int hashCode() {
if (_key == null) return 0;
return getKey().hashCode();
}
public String toString() {
return "[TunnelSigningPublicKey: " + getKey() + "]";
}
}

View File

@@ -0,0 +1,90 @@
package net.i2p.data.i2np;
/*
* 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.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import net.i2p.util.Log;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
import net.i2p.data.DataFormatException;
import net.i2p.data.Hash;
import net.i2p.data.Signature;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.crypto.DSAEngine;
/**
*
* @author jrandom
*/
public class TunnelVerificationStructure extends DataStructureImpl {
private final static Log _log = new Log(TunnelVerificationStructure.class);
private Hash _msgHash;
private Signature _authSignature;
public TunnelVerificationStructure() {
setMessageHash(null);
setAuthorizationSignature(null);
}
public Hash getMessageHash() { return _msgHash; }
public void setMessageHash(Hash hash) { _msgHash = hash; }
public Signature getAuthorizationSignature() { return _authSignature; }
public void setAuthorizationSignature(Signature sig) { _authSignature = sig; }
public void sign(SigningPrivateKey key) {
if (_msgHash != null) {
Signature sig = DSAEngine.getInstance().sign(_msgHash.getData(), key);
setAuthorizationSignature(sig);
}
}
public boolean verifySignature(SigningPublicKey key) {
if (_msgHash == null) return false;
return DSAEngine.getInstance().verifySignature(_authSignature, _msgHash.getData(), key);
}
public void readBytes(InputStream in) throws DataFormatException, IOException {
_msgHash = new Hash();
_msgHash.readBytes(in);
_authSignature = new Signature();
_authSignature.readBytes(in);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_authSignature == null) {
_authSignature = new Signature();
_authSignature.setData(Signature.FAKE_SIGNATURE);
}
if ( (_msgHash == null) || (_authSignature == null) ) throw new DataFormatException("Invalid data");
_msgHash.writeBytes(out);
_authSignature.writeBytes(out);
}
public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof TunnelVerificationStructure))
return false;
TunnelVerificationStructure str = (TunnelVerificationStructure)obj;
return DataHelper.eq(getMessageHash(), str.getMessageHash()) &&
DataHelper.eq(getAuthorizationSignature(), str.getAuthorizationSignature());
}
public int hashCode() {
if ( (_msgHash == null) || (_authSignature == null) ) return 0;
return getMessageHash().hashCode() + getAuthorizationSignature().hashCode();
}
public String toString() {
return "[TunnelVerificationStructure: " + getMessageHash() + " " + getAuthorizationSignature() + "]";
}
}