forked from I2P_Developers/i2p.i2p
* Datagrams:
- Redefine the repliable datagram signature for non-DSA_SHA1 sig types; was the sig of the SHA-256 of the payload, now the sig of the payload itself. This is an incompatible change but nobody is yet using the new sig types for datagram applications. - Don't pollute the hash cache with hashes of payloads - Check for too-big datagrams - Remove assertion check - Cleanups
This commit is contained in:
@@ -19,6 +19,7 @@ import net.i2p.data.DataFormatException;
|
|||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.data.Signature;
|
import net.i2p.data.Signature;
|
||||||
|
import net.i2p.data.SigningPublicKey;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,16 +35,11 @@ public final class I2PDatagramDissector {
|
|||||||
private final DSAEngine dsaEng = DSAEngine.getInstance();
|
private final DSAEngine dsaEng = DSAEngine.getInstance();
|
||||||
private final SHA256Generator hashGen = SHA256Generator.getInstance();
|
private final SHA256Generator hashGen = SHA256Generator.getInstance();
|
||||||
|
|
||||||
private Hash rxHash;
|
private byte[] rxHash;
|
||||||
|
|
||||||
private Signature rxSign;
|
private Signature rxSign;
|
||||||
|
|
||||||
private Destination rxDest;
|
private Destination rxDest;
|
||||||
|
|
||||||
private final byte[] rxPayload = new byte[DGRAM_BUFSIZE];
|
private final byte[] rxPayload = new byte[DGRAM_BUFSIZE];
|
||||||
|
|
||||||
private int rxPayloadLen;
|
private int rxPayloadLen;
|
||||||
|
|
||||||
private boolean valid;
|
private boolean valid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +52,17 @@ public final class I2PDatagramDissector {
|
|||||||
* Load an I2P repliable datagram into the dissector.
|
* Load an I2P repliable datagram into the dissector.
|
||||||
* Does NOT verify the signature.
|
* Does NOT verify the signature.
|
||||||
*
|
*
|
||||||
|
* Format is:
|
||||||
|
* <ol>
|
||||||
|
* <li>Destination (387+ bytes)
|
||||||
|
* <li>Signature (40+ bytes, type and length as implied by signing key type in the Destination)
|
||||||
|
* <li>Payload
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* For DSA_SHA1 Destinations, the signature is of the SHA-256 Hash of the payload.
|
||||||
|
*
|
||||||
|
* As of 0.9.14, for non-DSA_SHA1 Destinations, the signature is of the payload itself.
|
||||||
|
*
|
||||||
* @param dgram non-null I2P repliable datagram to be loaded
|
* @param dgram non-null I2P repliable datagram to be loaded
|
||||||
*
|
*
|
||||||
* @throws DataFormatException If there's an error in the datagram format
|
* @throws DataFormatException If there's an error in the datagram format
|
||||||
@@ -79,14 +86,21 @@ public final class I2PDatagramDissector {
|
|||||||
rxPayloadLen = dgStream.read(rxPayload);
|
rxPayloadLen = dgStream.read(rxPayload);
|
||||||
|
|
||||||
// calculate the hash of the payload
|
// calculate the hash of the payload
|
||||||
this.rxHash = hashGen.calculateHash(rxPayload, 0, rxPayloadLen);
|
if (type == SigType.DSA_SHA1) {
|
||||||
assert this.hashGen.calculateHash(this.extractPayload()).equals(this.rxHash);
|
if (rxHash == null)
|
||||||
|
rxHash = new byte[Hash.HASH_LENGTH];
|
||||||
|
// non-caching
|
||||||
|
hashGen.calculateHash(rxPayload, 0, rxPayloadLen, rxHash, 0);
|
||||||
|
//assert this.hashGen.calculateHash(this.extractPayload()).equals(this.rxHash);
|
||||||
|
} else {
|
||||||
|
rxHash = null;
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
|
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
|
||||||
log.error("Caught IOException - INCONSISTENT STATE!", e);
|
log.error("Caught IOException - INCONSISTENT STATE!", e);
|
||||||
} catch(AssertionError e) {
|
//} catch(AssertionError e) {
|
||||||
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
|
// Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
|
||||||
log.error("Assertion failed!", e);
|
// log.error("Assertion failed!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
//_log.debug("Datagram payload size: " + rxPayloadLen + "; content:\n"
|
//_log.debug("Datagram payload size: " + rxPayloadLen + "; content:\n"
|
||||||
@@ -125,14 +139,16 @@ public final class I2PDatagramDissector {
|
|||||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||||
* loaded with the loadI2PDatagram() method), verifying the datagram
|
* loaded with the loadI2PDatagram() method), verifying the datagram
|
||||||
* signature.
|
* signature.
|
||||||
|
*
|
||||||
|
* As of 0.9.14, for signature types other than DSA_SHA1, this returns null.
|
||||||
|
*
|
||||||
* @return The hash of the payload of the I2P repliable datagram
|
* @return The hash of the payload of the I2P repliable datagram
|
||||||
* @throws I2PInvalidDatagramException if the signature verification fails
|
* @throws I2PInvalidDatagramException if the signature verification fails
|
||||||
*/
|
*/
|
||||||
public Hash getHash() throws I2PInvalidDatagramException {
|
public Hash getHash() throws I2PInvalidDatagramException {
|
||||||
// make sure it has a valid signature
|
// make sure it has a valid signature
|
||||||
this.verifySignature();
|
this.verifySignature();
|
||||||
|
return extractHash();
|
||||||
return this.extractHash();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,10 +194,18 @@ public final class I2PDatagramDissector {
|
|||||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||||
* loaded with the loadI2PDatagram() method), without verifying the datagram
|
* loaded with the loadI2PDatagram() method), without verifying the datagram
|
||||||
* signature.
|
* signature.
|
||||||
|
*
|
||||||
|
* As of 0.9.14, for signature types other than DSA_SHA1, this returns null.
|
||||||
|
*
|
||||||
* @return The hash of the payload of the I2P repliable datagram
|
* @return The hash of the payload of the I2P repliable datagram
|
||||||
*/
|
*/
|
||||||
public Hash extractHash() {
|
public Hash extractHash() {
|
||||||
return this.rxHash;
|
if (rxHash == null)
|
||||||
|
return null;
|
||||||
|
// make a copy as we will reuse rxHash
|
||||||
|
byte[] hash = new byte[Hash.HASH_LENGTH];
|
||||||
|
System.arraycopy(rxHash, 0, hash, 0, Hash.HASH_LENGTH);
|
||||||
|
return new Hash(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -194,12 +218,21 @@ public final class I2PDatagramDissector {
|
|||||||
if(this.valid)
|
if(this.valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (rxSign == null || rxSign.getData() == null || rxDest == null || rxDest.getSigningPublicKey() == null)
|
if (rxSign == null || rxSign.getData() == null || rxDest == null)
|
||||||
throw new I2PInvalidDatagramException("Datagram not yet read");
|
throw new I2PInvalidDatagramException("Datagram not yet read");
|
||||||
|
|
||||||
// now validate
|
// now validate
|
||||||
if (!this.dsaEng.verifySignature(rxSign, rxHash.getData(), rxDest.getSigningPublicKey()))
|
SigningPublicKey spk = rxDest.getSigningPublicKey();
|
||||||
throw new I2PInvalidDatagramException("Incorrect I2P repliable datagram signature");
|
SigType type = spk.getType();
|
||||||
|
if (type == null)
|
||||||
|
throw new I2PInvalidDatagramException("unsupported sig type");
|
||||||
|
if (type == SigType.DSA_SHA1) {
|
||||||
|
if (!this.dsaEng.verifySignature(rxSign, rxHash, spk))
|
||||||
|
throw new I2PInvalidDatagramException("Incorrect I2P repliable datagram signature");
|
||||||
|
} else {
|
||||||
|
if (!this.dsaEng.verifySignature(rxSign, rxPayload, 0, rxPayloadLen, spk))
|
||||||
|
throw new I2PInvalidDatagramException("Incorrect I2P repliable datagram signature");
|
||||||
|
}
|
||||||
|
|
||||||
// set validated
|
// set validated
|
||||||
this.valid = true;
|
this.valid = true;
|
||||||
|
@@ -16,8 +16,12 @@ import net.i2p.client.I2PSession;
|
|||||||
import net.i2p.crypto.DSAEngine;
|
import net.i2p.crypto.DSAEngine;
|
||||||
import net.i2p.crypto.SHA256Generator;
|
import net.i2p.crypto.SHA256Generator;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.data.Signature;
|
||||||
import net.i2p.data.SigningPrivateKey;
|
import net.i2p.data.SigningPrivateKey;
|
||||||
|
import net.i2p.crypto.SigType;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.SimpleByteCache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for creating I2P repliable datagrams. Note that objects of this class
|
* Class for creating I2P repliable datagrams. Note that objects of this class
|
||||||
@@ -44,9 +48,9 @@ public final class I2PDatagramMaker {
|
|||||||
* @param session I2PSession used to send I2PDatagrams through
|
* @param session I2PSession used to send I2PDatagrams through
|
||||||
*/
|
*/
|
||||||
public I2PDatagramMaker(I2PSession session) {
|
public I2PDatagramMaker(I2PSession session) {
|
||||||
this();
|
|
||||||
this.setI2PDatagramMaker(session);
|
this.setI2PDatagramMaker(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new I2PDatagramMaker that is null.
|
* Construct a new I2PDatagramMaker that is null.
|
||||||
* Use setI2PDatagramMaker to set the parameters.
|
* Use setI2PDatagramMaker to set the parameters.
|
||||||
@@ -59,22 +63,53 @@ public final class I2PDatagramMaker {
|
|||||||
sxPrivKey = session.getPrivateKey();
|
sxPrivKey = session.getPrivateKey();
|
||||||
sxDestBytes = session.getMyDestination().toByteArray();
|
sxDestBytes = session.getMyDestination().toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a repliable I2P datagram containing the specified payload.
|
* Make a repliable I2P datagram containing the specified payload.
|
||||||
*
|
*
|
||||||
|
* Format is:
|
||||||
|
* <ol>
|
||||||
|
* <li>Destination (387+ bytes)
|
||||||
|
* <li>Signature (40+ bytes, type and length as implied by signing key type in the Destination)
|
||||||
|
* <li>Payload
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* Maximum datagram size is 32768, so maximum payload size is 32341, or less for
|
||||||
|
* non-DSA_SHA1 destinations. Practical maximum is a few KB less due to
|
||||||
|
* ElGamal/AES overhead. 10 KB or less is recommended for best results.
|
||||||
|
*
|
||||||
|
* For DSA_SHA1 Destinations, the signature is of the SHA-256 Hash of the payload.
|
||||||
|
*
|
||||||
|
* As of 0.9.14, for non-DSA_SHA1 Destinations, the signature is of the payload itself.
|
||||||
|
*
|
||||||
* @param payload non-null Bytes to be contained in the I2P datagram.
|
* @param payload non-null Bytes to be contained in the I2P datagram.
|
||||||
|
* @return null on error
|
||||||
|
* @throws IllegalArgumentException if payload is too big
|
||||||
|
* @throws IllegalStateException if Destination signature type unsupported
|
||||||
*/
|
*/
|
||||||
public byte[] makeI2PDatagram(byte[] payload) {
|
public byte[] makeI2PDatagram(byte[] payload) {
|
||||||
sxDGram.reset();
|
sxDGram.reset();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sxDGram.write(sxDestBytes);
|
sxDGram.write(sxDestBytes);
|
||||||
|
SigType type = sxPrivKey.getType();
|
||||||
|
if (type == null)
|
||||||
|
throw new IllegalStateException("Unsupported sig type");
|
||||||
|
|
||||||
dsaEng.sign(hashGen.calculateHash(payload).toByteArray(),
|
Signature sig;
|
||||||
sxPrivKey).writeBytes(sxDGram);
|
if (type == SigType.DSA_SHA1) {
|
||||||
|
byte[] hash = SimpleByteCache.acquire(Hash.HASH_LENGTH);
|
||||||
|
// non-caching
|
||||||
|
hashGen.calculateHash(payload, 0, payload.length, hash, 0);
|
||||||
|
sig = dsaEng.sign(hash, sxPrivKey);
|
||||||
|
SimpleByteCache.release(hash);
|
||||||
|
} else {
|
||||||
|
sig = dsaEng.sign(payload, sxPrivKey);
|
||||||
|
}
|
||||||
|
sig.writeBytes(sxDGram);
|
||||||
sxDGram.write(payload);
|
sxDGram.write(payload);
|
||||||
|
if (sxDGram.size() > DGRAM_BUFSIZE)
|
||||||
|
throw new IllegalArgumentException("Too big");
|
||||||
return sxDGram.toByteArray();
|
return sxDGram.toByteArray();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramMaker.class);
|
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramMaker.class);
|
||||||
|
@@ -10,6 +10,9 @@ in turn, use the {@link net.i2p.client.datagram.I2PDatagramMaker} to build a
|
|||||||
message that can be parsed. </p>
|
message that can be parsed. </p>
|
||||||
|
|
||||||
<p>The datagram format implemented here includes
|
<p>The datagram format implemented here includes
|
||||||
the sender's {@link net.i2p.data.Destination}, the payload, and a hash of the
|
the sender's {@link net.i2p.data.Destination}, the payload, and a signature
|
||||||
payload (signed by the sender's {@link net.i2p.data.SigningPrivateKey}).</p>
|
(signed by the sender's {@link net.i2p.data.SigningPrivateKey}).
|
||||||
|
For DSA_SHA1 destinations, the signature is of the SHA-256 Hash of the payload.
|
||||||
|
For other destination types, the signature is of the payload itself.
|
||||||
|
</p>
|
||||||
</body></html>
|
</body></html>
|
||||||
|
@@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 14;
|
public final static long BUILD = 15;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
Reference in New Issue
Block a user