use of net.i2p.crypto.TagSetHandle in project i2p.i2p by i2p.
the class SessionEncryptionTest method testSessions.
/**
* Run tagsIncluded useTag rekey
* 1 yes (2) no no
* 2 no yes no
* 3 yes (2) yes no
* 4 no yes no
* 5 no yes no
*/
public void testSessions() throws Exception {
Object[] keys = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey) keys[0];
PrivateKey privKey = (PrivateKey) keys[1];
SessionKeyManager skm = new TransientSessionKeyManager(_context);
SessionKey curKey = skm.createSession(pubKey);
SessionTag tag1 = new SessionTag(true);
SessionTag tag2 = new SessionTag(true);
SessionTag tag3 = new SessionTag(true);
SessionTag tag4 = new SessionTag(true);
HashSet<SessionTag> firstTags = new HashSet<SessionTag>();
firstTags.add(tag1);
firstTags.add(tag2);
HashSet<SessionTag> secondTags = new HashSet<SessionTag>();
secondTags.add(tag3);
secondTags.add(tag4);
byte[] msg1 = DataHelper.getASCII("msg 1");
byte[] msg2 = DataHelper.getASCII("msg 2");
byte[] msg3 = DataHelper.getASCII("msg 3");
byte[] msg4 = DataHelper.getASCII("msg 4");
byte[] msg5 = DataHelper.getASCII("msg 5");
byte[] emsg1 = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, firstTags, null, 64);
byte[] dmsg1 = _context.elGamalAESEngine().decrypt(emsg1, privKey, skm);
assertTrue(DataHelper.eq(dmsg1, msg1));
TagSetHandle tsh = skm.tagsDelivered(pubKey, curKey, firstTags);
skm.tagsAcked(pubKey, curKey, tsh);
curKey = skm.getCurrentKey(pubKey);
SessionTag curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
byte[] emsg2 = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, null, curTag, 64);
byte[] dmsg2 = _context.elGamalAESEngine().decrypt(emsg2, privKey, skm);
assertTrue(DataHelper.eq(dmsg2, msg2));
curKey = skm.getCurrentKey(pubKey);
curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
assertNotNull(curKey);
byte[] emsg3 = _context.elGamalAESEngine().encrypt(msg3, pubKey, curKey, secondTags, curTag, 64);
byte[] dmsg3 = _context.elGamalAESEngine().decrypt(emsg3, privKey, skm);
assertTrue(DataHelper.eq(dmsg3, msg3));
tsh = skm.tagsDelivered(pubKey, curKey, secondTags);
skm.tagsAcked(pubKey, curKey, tsh);
curKey = skm.getCurrentKey(pubKey);
curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
assertNotNull(curKey);
byte[] emsg4 = _context.elGamalAESEngine().encrypt(msg4, pubKey, curKey, null, curTag, 64);
byte[] dmsg4 = _context.elGamalAESEngine().decrypt(emsg4, privKey, skm);
assertTrue(DataHelper.eq(dmsg4, msg4));
curKey = skm.getCurrentKey(pubKey);
curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
assertNotNull(curKey);
byte[] emsg5 = _context.elGamalAESEngine().encrypt(msg5, pubKey, curKey, null, curTag, 64);
byte[] dmsg5 = _context.elGamalAESEngine().decrypt(emsg5, privKey, skm);
assertTrue(DataHelper.eq(dmsg5, msg5));
}
use of net.i2p.crypto.TagSetHandle in project i2p.i2p by i2p.
the class SessionEncryptionTest method testRekeying.
/**
* Run tagsIncluded useTag rekey
* 1 yes (2) no no
* 2 no yes no
* 3 yes (2) yes yes
* 4 no yes no
* 5 no yes no
*/
public void testRekeying() throws Exception {
Object[] keys = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey) keys[0];
PrivateKey privKey = (PrivateKey) keys[1];
SessionKeyManager skm = new TransientSessionKeyManager(_context);
SessionKey curKey = skm.createSession(pubKey);
SessionKey nextKey = KeyGenerator.getInstance().generateSessionKey();
SessionTag tag1 = new SessionTag(true);
SessionTag tag2 = new SessionTag(true);
SessionTag tag3 = new SessionTag(true);
SessionTag tag4 = new SessionTag(true);
HashSet<SessionTag> firstTags = new HashSet<SessionTag>();
firstTags.add(tag1);
firstTags.add(tag2);
HashSet<SessionTag> secondTags = new HashSet<SessionTag>();
secondTags.add(tag3);
secondTags.add(tag4);
byte[] msg1 = DataHelper.getASCII("msg 1");
byte[] msg2 = DataHelper.getASCII("msg 2");
byte[] msg3 = DataHelper.getASCII("msg 3");
byte[] msg4 = DataHelper.getASCII("msg 4");
byte[] msg5 = DataHelper.getASCII("msg 5");
byte[] emsg1 = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, firstTags, null, 64);
byte[] dmsg1 = _context.elGamalAESEngine().decrypt(emsg1, privKey, skm);
assertTrue(DataHelper.eq(dmsg1, msg1));
TagSetHandle tsh = skm.tagsDelivered(pubKey, curKey, firstTags);
skm.tagsAcked(pubKey, curKey, tsh);
curKey = skm.getCurrentKey(pubKey);
SessionTag curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
byte[] emsg2 = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, null, curTag, 64);
byte[] dmsg2 = _context.elGamalAESEngine().decrypt(emsg2, privKey, skm);
assertTrue(DataHelper.eq(dmsg2, msg2));
curKey = skm.getCurrentKey(pubKey);
curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
assertNotNull(curKey);
byte[] emsg3 = _context.elGamalAESEngine().encrypt(msg3, pubKey, curKey, secondTags, curTag, nextKey, 64);
byte[] dmsg3 = _context.elGamalAESEngine().decrypt(emsg3, privKey, skm);
assertTrue(DataHelper.eq(dmsg3, msg3));
// note nextKey not curKey
tsh = skm.tagsDelivered(pubKey, nextKey, secondTags);
skm.tagsAcked(pubKey, nextKey, tsh);
curKey = skm.getCurrentKey(pubKey);
curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
assertNotNull(curKey);
byte[] emsg4 = _context.elGamalAESEngine().encrypt(msg4, pubKey, curKey, null, curTag, 64);
byte[] dmsg4 = _context.elGamalAESEngine().decrypt(emsg4, privKey, skm);
assertTrue(DataHelper.eq(dmsg4, msg4));
curKey = skm.getCurrentKey(pubKey);
curTag = skm.consumeNextAvailableTag(pubKey, curKey);
assertNotNull(curTag);
assertNotNull(curKey);
byte[] emsg5 = _context.elGamalAESEngine().encrypt(msg5, pubKey, curKey, null, curTag, 64);
byte[] dmsg5 = _context.elGamalAESEngine().decrypt(emsg5, privKey, skm);
assertTrue(DataHelper.eq(dmsg5, msg5));
}
use of net.i2p.crypto.TagSetHandle in project i2p.i2p by i2p.
the class SessionEncryptionTest method testLongSession.
/**
* 20 tags every 10 messages, rekey every 50
*/
public void testLongSession() throws Exception {
Object[] keys = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey) keys[0];
PrivateKey privKey = (PrivateKey) keys[1];
SessionKeyManager skm = new TransientSessionKeyManager(_context);
SessionKey curKey = skm.createSession(pubKey);
for (int i = 0; i < 1000; i++) {
Set<SessionTag> tags = null;
SessionKey nextKey = null;
curKey = skm.getCurrentKey(pubKey);
SessionTag curTag = skm.consumeNextAvailableTag(pubKey, curKey);
int availTags = skm.getAvailableTags(pubKey, curKey);
if ((availTags < 1)) {
tags = generateNewTags(50);
}
if (i % 50 == 0)
nextKey = KeyGenerator.getInstance().generateSessionKey();
byte[] msg = DataHelper.getASCII("msg " + i);
byte[] emsg = _context.elGamalAESEngine().encrypt(msg, pubKey, curKey, tags, curTag, nextKey, 64);
byte[] dmsg = _context.elGamalAESEngine().decrypt(emsg, privKey, skm);
assertTrue(DataHelper.eq(dmsg, msg));
if ((tags != null) && (tags.size() > 0)) {
if (nextKey == null) {
TagSetHandle tsh = skm.tagsDelivered(pubKey, curKey, tags);
skm.tagsAcked(pubKey, curKey, tsh);
} else {
TagSetHandle tsh = skm.tagsDelivered(pubKey, nextKey, tags);
skm.tagsAcked(pubKey, nextKey, tsh);
}
}
}
}
use of net.i2p.crypto.TagSetHandle in project i2p.i2p by i2p.
the class OutboundClientMessageOneShotJob method send.
/**
* Send the message to the specified tunnel by creating a new garlic message containing
* the (already created) payload clove as well as a new delivery status message. This garlic
* message is sent out one of our tunnels, destined for the lease (tunnel+router) specified, and the delivery
* status message is targetting one of our free inbound tunnels as well. We use a new
* reply selector to keep an eye out for that delivery status message's token
*/
private void send() {
synchronized (this) {
if (_finished != Result.NONE) {
if (_log.shouldLog(Log.WARN))
_log.warn(OutboundClientMessageOneShotJob.this.getJobId() + ": SEND-AFTER-" + _finished);
return;
}
}
long now = getContext().clock().now();
if (now >= _overallExpiration) {
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_EXPIRED);
return;
}
_outTunnel = selectOutboundTunnel(_to);
if (_outTunnel == null) {
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Could not find any outbound tunnels to send the payload through... this might take a while");
getContext().statManager().addRateData("client.dispatchNoTunnels", now - _start);
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_NO_TUNNELS);
return;
}
// boolean wantACK = _wantACK || existingTags <= 30 || getContext().random().nextInt(100) < 5;
// what's the point of 5% random? possible improvements or replacements:
// DONE (getNextLease() is called before this): wantACK if we changed their inbound lease (getNextLease() sets _wantACK)
// DONE (selectOutboundTunnel() moved above here): wantACK if we changed our outbound tunnel (selectOutboundTunnel() sets _wantACK)
// DONE (added new cache): wantACK if we haven't in last 1m (requires a new static cache probably)
Long lastReplyRequestSent = _cache.lastReplyRequestCache.get(_hashPair);
boolean shouldRequestReply = lastReplyRequestSent == null || lastReplyRequestSent.longValue() < now - REPLY_REQUEST_INTERVAL;
int sendFlags = _clientMessage.getFlags();
// Per-message flag > 0 overrides per-session option
int tagsRequired = SendMessageOptions.getTagThreshold(sendFlags);
boolean wantACK = _wantACK || shouldRequestReply || GarlicMessageBuilder.needsTags(getContext(), _leaseSet.getEncryptionKey(), _from.calculateHash(), tagsRequired);
LeaseSet replyLeaseSet;
// Per-message flag == false overrides session option which is default true
String allow = _clientMessage.getSenderConfig().getOptions().getProperty(BUNDLE_REPLY_LEASESET);
boolean allowLeaseBundle = SendMessageOptions.getSendLeaseSet(sendFlags) && (allow == null || Boolean.parseBoolean(allow));
if (allowLeaseBundle) {
// If we want an ack, bundle a leaseSet...
// replyLeaseSet = getReplyLeaseSet(wantACK);
// Only when necessary. We don't need to force.
// ACKs find their own way back, they don't need a leaseset.
replyLeaseSet = getReplyLeaseSet(false);
// ... and vice versa (so we know he got it)
if (replyLeaseSet != null)
wantACK = true;
} else {
replyLeaseSet = null;
}
long token;
if (wantACK) {
_cache.lastReplyRequestCache.put(_hashPair, Long.valueOf(now));
token = getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE);
_inTunnel = selectInboundTunnel();
} else {
token = -1;
}
PayloadGarlicConfig clove = buildClove();
if (clove == null) {
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION);
return;
}
// if (_log.shouldLog(Log.DEBUG))
// _log.debug(getJobId() + ": Clove built to " + _toString);
PublicKey key = _leaseSet.getEncryptionKey();
SessionKey sessKey = new SessionKey();
Set<SessionTag> tags = new HashSet<SessionTag>();
// Per-message flag > 0 overrides per-session option
int tagsToSend = SendMessageOptions.getTagsToSend(sendFlags);
GarlicMessage msg = OutboundClientMessageJobHelper.createGarlicMessage(getContext(), token, _overallExpiration, key, clove, _from.calculateHash(), _to, _inTunnel, tagsToSend, tagsRequired, sessKey, tags, wantACK, replyLeaseSet);
if (msg == null) {
// we dont receive the reply? hmm...)
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Unable to create the garlic message (no tunnels left or too lagged) to " + _toString);
getContext().statManager().addRateData("client.dispatchNoTunnels", now - _start);
dieFatal(MessageStatusMessage.STATUS_SEND_FAILURE_NO_TUNNELS);
return;
}
// if (_log.shouldLog(Log.DEBUG))
// _log.debug(getJobId() + ": send() - token expected " + token + " to " + _toString);
SendSuccessJob onReply = null;
SendTimeoutJob onFail = null;
ReplySelector selector = null;
if (wantACK) {
TagSetHandle tsh = null;
if (!tags.isEmpty()) {
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
if (skm != null)
tsh = skm.tagsDelivered(_leaseSet.getEncryptionKey(), sessKey, tags);
}
onReply = new SendSuccessJob(getContext(), sessKey, tsh);
onFail = new SendTimeoutJob(getContext(), sessKey, tsh);
long expiration = Math.max(_overallExpiration, _start + REPLY_TIMEOUT_MS_MIN);
selector = new ReplySelector(token, expiration);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug(getJobId() + ": Sending msg out " + _outTunnel.getSendTunnelId(0) + " to " + _toString + " at " + _lease.getTunnelId() + " on " + _lease.getGateway());
DispatchJob dispatchJob = new DispatchJob(getContext(), msg, selector, onReply, onFail);
// if (false) // dispatch may take 100+ms, so toss it in its own job
// getContext().jobQueue().addJob(dispatchJob);
// else
dispatchJob.runJob();
getContext().statManager().addRateData("client.dispatchPrepareTime", now - _start);
if (!wantACK)
getContext().statManager().addRateData("client.dispatchNoACK", 1);
}
use of net.i2p.crypto.TagSetHandle in project i2p.i2p by i2p.
the class MessageWrapper method wrap.
/**
* Garlic wrap a message from a client or this router, destined for a router,
* to hide the contents from the OBEP.
* Caller must call acked() or fail() on the returned object.
*
* @param from must be a local client with a session key manager,
* or null to use the router's session key manager
* @return null on encrypt failure
*/
static WrappedMessage wrap(RouterContext ctx, I2NPMessage m, Hash from, RouterInfo to) {
PayloadGarlicConfig payload = new PayloadGarlicConfig();
payload.setCertificate(Certificate.NULL_CERT);
payload.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE));
payload.setPayload(m);
payload.setRecipient(to);
payload.setDeliveryInstructions(DeliveryInstructions.LOCAL);
payload.setExpiration(m.getMessageExpiration());
SessionKeyManager skm;
if (from != null)
skm = ctx.clientManager().getClientSessionKeyManager(from);
else
skm = ctx.sessionKeyManager();
if (skm == null)
return null;
SessionKey sentKey = new SessionKey();
Set<SessionTag> sentTags = new HashSet<SessionTag>();
GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, sentKey, sentTags, NETDB_TAGS_TO_DELIVER, NETDB_LOW_THRESHOLD, skm);
if (msg == null)
return null;
TagSetHandle tsh = null;
PublicKey sentTo = to.getIdentity().getPublicKey();
if (!sentTags.isEmpty())
tsh = skm.tagsDelivered(sentTo, sentKey, sentTags);
// _log.debug("Sent to: " + to.getIdentity().getHash() + " with key: " + sentKey + " and tags: " + sentTags.size());
return new WrappedMessage(msg, skm, sentTo, sentKey, tsh);
}
Aggregations