use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class BuildTestMessageJob method runJob.
public void runJob() {
if (alreadyKnownReachable()) {
getContext().jobQueue().addJob(_onSend);
return;
}
// first goes to the peer then back to us.
if (_log.shouldLog(Log.DEBUG))
_log.debug("Building garlic message to test " + _target.getIdentity().getHash().toBase64());
GarlicConfig config = buildGarlicCloveConfig();
// TODO: make the last params on this specify the correct sessionKey and tags used
ReplyJob replyJob = new JobReplyJob(getContext(), _onSend, config.getRecipient().getIdentity().getPublicKey(), config.getId(), null, new HashSet<SessionTag>());
MessageSelector sel = buildMessageSelector();
SendGarlicJob job = new SendGarlicJob(getContext(), config, null, _onSendFailed, replyJob, _onSendFailed, _timeoutMs, _priority, sel);
getContext().jobQueue().addJob(job);
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class ElGamalAESEngine method decrypt.
/**
* Decrypt the message using the given private key
* and using tags from the specified key manager.
* This works according to the
* ElGamal+AES algorithm in the data structure spec.
*
* Warning - use the correct SessionKeyManager. Clients should instantiate their own.
* Clients using I2PAppContext.sessionKeyManager() may be correlated with the router,
* unless you are careful to use different keys.
*
* @return decrypted data or null on failure
*/
public byte[] decrypt(byte[] data, PrivateKey targetPrivateKey, SessionKeyManager keyManager) throws DataFormatException {
if (data == null) {
if (_log.shouldLog(Log.ERROR))
_log.error("Null data being decrypted?");
return null;
} else if (data.length < MIN_ENCRYPTED_SIZE) {
if (_log.shouldLog(Log.ERROR))
_log.error("Data is less than the minimum size (" + data.length + " < " + MIN_ENCRYPTED_SIZE + ")");
return null;
}
byte[] tag = new byte[32];
System.arraycopy(data, 0, tag, 0, 32);
SessionTag st = new SessionTag(tag);
SessionKey key = keyManager.consumeTag(st);
SessionKey foundKey = new SessionKey();
SessionKey usedKey = new SessionKey();
Set<SessionTag> foundTags = new HashSet<SessionTag>();
byte[] decrypted = null;
boolean wasExisting = false;
if (key != null) {
// if (_log.shouldLog(Log.DEBUG)) _log.debug("Key is known for tag " + st);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Decrypting existing session encrypted with tag: " + st.toString() + ": key: " + key.toBase64() + ": " + data.length + " bytes ");
decrypted = decryptExistingSession(data, key, targetPrivateKey, foundTags, usedKey, foundKey);
if (decrypted != null) {
_context.statManager().updateFrequency("crypto.elGamalAES.decryptExistingSession");
if ((!foundTags.isEmpty()) && (_log.shouldLog(Log.DEBUG)))
_log.debug("ElG/AES decrypt success with " + st + ": found tags: " + foundTags);
wasExisting = true;
} else {
_context.statManager().updateFrequency("crypto.elGamalAES.decryptFailed");
if (_log.shouldLog(Log.WARN)) {
_log.warn("ElG decrypt fail: known tag [" + st + "], failed decrypt");
}
}
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Key is NOT known for tag " + st);
decrypted = decryptNewSession(data, targetPrivateKey, foundTags, usedKey, foundKey);
if (decrypted != null) {
_context.statManager().updateFrequency("crypto.elGamalAES.decryptNewSession");
if ((!foundTags.isEmpty()) && (_log.shouldLog(Log.DEBUG)))
_log.debug("ElG decrypt success: found tags: " + foundTags);
} else {
_context.statManager().updateFrequency("crypto.elGamalAES.decryptFailed");
if (_log.shouldLog(Log.WARN))
_log.warn("ElG decrypt fail: unknown tag: " + st);
}
}
if ((key == null) && (decrypted == null)) {
// _log.debug("Unable to decrypt the data starting with tag [" + st + "] - did the tag expire recently?", new Exception("Decrypt failure"));
}
if (!foundTags.isEmpty()) {
if (foundKey.getData() != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Found key: " + foundKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
keyManager.tagsReceived(foundKey, foundTags);
} else if (usedKey.getData() != null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Used key: " + usedKey.toBase64() + " tags: " + foundTags + " wasExisting? " + wasExisting);
keyManager.tagsReceived(usedKey, foundTags);
}
}
return decrypted;
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class ElGamalAESEngine method encryptAESBlock.
/**
* @param tagsForDelivery session tags to be associated with the key or null;
* 200 max enforced at receiver
*/
private final byte[] encryptAESBlock(byte[] data, SessionKey key, byte[] iv, Set<SessionTag> tagsForDelivery, SessionKey newKey, long paddedSize, int prefixBytes) {
// _log.debug("Encrypting AES");
if (tagsForDelivery == null)
tagsForDelivery = Collections.emptySet();
int size = // sizeof(tags)
2 + SessionTag.BYTE_LENGTH * tagsForDelivery.size() + // payload length
4 + Hash.HASH_LENGTH + (newKey == null ? 1 : 1 + SessionKey.KEYSIZE_BYTES) + data.length;
int totalSize = size + getPaddingSize(size, paddedSize);
byte[] aesData = new byte[totalSize + prefixBytes];
int cur = prefixBytes;
DataHelper.toLong(aesData, cur, 2, tagsForDelivery.size());
cur += 2;
for (SessionTag tag : tagsForDelivery) {
System.arraycopy(tag.getData(), 0, aesData, cur, SessionTag.BYTE_LENGTH);
cur += SessionTag.BYTE_LENGTH;
}
// _log.debug("# tags created, registered, and written: " + tagsForDelivery.size());
DataHelper.toLong(aesData, cur, 4, data.length);
cur += 4;
// _log.debug("data length: " + data.length);
// use alternate calculateHash() method to avoid object churn and caching
// Hash hash = _context.sha().calculateHash(data);
// System.arraycopy(hash.getData(), 0, aesData, cur, Hash.HASH_LENGTH);
_context.sha().calculateHash(data, 0, data.length, aesData, cur);
cur += Hash.HASH_LENGTH;
// _log.debug("hash of data: " + DataHelper.toString(hash.getData(), 32));
if (newKey == null) {
// don't rekey
aesData[cur++] = 0x00;
// _log.debug("flag written");
} else {
// rekey
aesData[cur++] = 0x01;
System.arraycopy(newKey.getData(), 0, aesData, cur, SessionKey.KEYSIZE_BYTES);
cur += SessionKey.KEYSIZE_BYTES;
}
System.arraycopy(data, 0, aesData, cur, data.length);
cur += data.length;
// _log.debug("raw data written: " + len);
byte[] padding = getPadding(_context, size, paddedSize);
// _log.debug("padding length: " + padding.length);
System.arraycopy(padding, 0, aesData, cur, padding.length);
cur += padding.length;
// Hash h = _context.sha().calculateHash(data);
// _log.debug("Hash of entire aes block before encryption: (len=" + data.length + ")\n" + DataHelper.toString(h.getData(), 32));
_context.aes().encrypt(aesData, prefixBytes, aesData, prefixBytes, key, iv, aesData.length - prefixBytes);
// return aesEncr;
return aesData;
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class TransientSessionKeyManager method tagsReceived.
/**
* Accept the given tags and associate them with the given key for decryption
*
* @param sessionTags modifiable; NOT copied. Non-null, non-empty.
* @param expire time from now
* @since 0.9.7
*/
@Override
public void tagsReceived(SessionKey key, Set<SessionTag> sessionTags, long expire) {
TagSet tagSet = new TagSet(sessionTags, key, _context.clock().now() + expire, _rcvTagSetID.incrementAndGet());
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Received " + tagSet);
// _log.debug("Tags: " + DataHelper.toString(sessionTags));
}
TagSet old = null;
SessionTag dupTag = null;
synchronized (_inboundTagSets) {
for (SessionTag tag : sessionTags) {
old = _inboundTagSets.put(tag, tagSet);
if (old != null) {
if (!old.getAssociatedKey().equals(tagSet.getAssociatedKey())) {
_inboundTagSets.remove(tag);
dupTag = tag;
break;
} else {
// ignore the dup
old = null;
}
}
}
}
if (old != null) {
// drop both old and tagSet tags
synchronized (_inboundTagSets) {
for (SessionTag tag : old.getTags()) {
_inboundTagSets.remove(tag);
}
for (SessionTag tag : sessionTags) {
_inboundTagSets.remove(tag);
}
}
if (_log.shouldLog(Log.WARN)) {
_log.warn("Multiple tags matching! tagSet: " + tagSet + " and old tagSet: " + old + " tag: " + dupTag + "/" + dupTag);
_log.warn("Earlier tag set creation: " + old + ": key=" + old.getAssociatedKey());
_log.warn("Current tag set creation: " + tagSet + ": key=" + tagSet.getAssociatedKey());
}
}
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class TransientSessionKeyManager method clearExcess.
/**
* remove a bunch of arbitrarily selected tags, then drop all of
* the associated tag sets. this is very time consuming - iterating
* across the entire _inboundTagSets map, but it should be very rare,
* and the stats we can gather can hopefully reduce the frequency of
* using too many session tags in the future
*/
private void clearExcess(int overage) {
long now = _context.clock().now();
int old = 0;
int large = 0;
int absurd = 0;
int recent = 0;
int tags = 0;
int toRemove = overage * 2;
_log.logAlways(Log.WARN, "TOO MANY SESSION TAGS! Starting cleanup, overage = " + overage);
List<TagSet> removed = new ArrayList<TagSet>(toRemove);
synchronized (_inboundTagSets) {
for (TagSet set : _inboundTagSets.values()) {
int size = set.getTags().size();
if (size > 1000)
absurd++;
if (size > 100)
large++;
if (set.getDate() - now < 3 * 60 * 1000) {
// expiration is 12 minutes, so these are older than 9 minutes
old++;
removed.add(set);
continue;
} else if (set.getDate() - now > 8 * 60 * 1000) {
// expiration is 12 minutes, so these were created in last 4 minutes
recent++;
continue;
}
if (removed.size() < toRemove)
removed.add(set);
}
for (int i = 0; i < removed.size(); i++) {
TagSet cur = removed.get(i);
for (SessionTag tag : cur.getTags()) {
_inboundTagSets.remove(tag);
tags++;
}
}
}
_log.logAlways(Log.WARN, "TOO MANY SESSION TAGS! removed " + removed.size() + " tag sets arbitrarily, with " + tags + " tags," + "where there are " + old + " long lasting sessions, " + recent + " ones created in the last few minutes, and " + large + " sessions with more than 100 tags (and " + absurd + " with more than 1000!), leaving a total of " + _inboundTagSets.size() + " tags behind");
}
Aggregations