use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class ElGamalAESEngine method decryptAESBlock.
/**
* Decrypt the AES data with the session key and IV. The result should be:
* <pre>
* - 2 byte integer specifying the # of session tags
* - that many 32 byte session tags
* - 4 byte integer specifying data.length
* - SHA256 of data
* - 1 byte flag that, if == 1, is followed by a new SessionKey
* - data
* - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0
* </pre>
*
* If anything doesn't match up in decryption, return null. Otherwise, return
* the decrypted data and update the session as necessary. If the sentTag is not null,
* consume it, but if it is null, record the keys, etc as part of a new session.
*
* @param foundTags set which is filled with any sessionTags found during decryption
* @param foundKey out parameter. Data must be unset when called; may be filled with a new sessionKey found during decryption
* @return decrypted data or null on failure
*/
/**
**
* private byte[] decryptAESBlock(byte encrypted[], SessionKey key, byte iv[],
* byte sentTag[], Set foundTags, SessionKey foundKey) throws DataFormatException {
* return decryptAESBlock(encrypted, 0, encrypted.length, key, iv, sentTag, foundTags, foundKey);
* }
***
*/
/*
* Note: package private for ElGamalTest.testAES()
*/
byte[] decryptAESBlock(byte[] encrypted, int offset, int encryptedLen, SessionKey key, byte[] iv, byte[] sentTag, Set<SessionTag> foundTags, SessionKey foundKey) throws DataFormatException {
// _log.debug("iv for decryption: " + DataHelper.toString(iv, 16));
// _log.debug("decrypting AES block. encr.length = " + (encrypted == null? -1 : encrypted.length) + " sentTag: " + DataHelper.toString(sentTag, 32));
byte[] decrypted = new byte[encryptedLen];
_context.aes().decrypt(encrypted, offset, decrypted, 0, key, iv, encryptedLen);
// _log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32));
try {
SessionKey newKey = null;
List<SessionTag> tags = null;
// ByteArrayInputStream bais = new ByteArrayInputStream(decrypted);
int cur = 0;
long numTags = DataHelper.fromLong(decrypted, cur, 2);
if ((numTags < 0) || (numTags > MAX_TAGS_RECEIVED))
throw new IllegalArgumentException("Invalid number of session tags");
if (numTags > 0)
tags = new ArrayList<SessionTag>((int) numTags);
cur += 2;
// _log.debug("# tags: " + numTags);
if (numTags * SessionTag.BYTE_LENGTH > decrypted.length - 2) {
throw new IllegalArgumentException("# tags: " + numTags + " is too many for " + (decrypted.length - 2));
}
for (int i = 0; i < numTags; i++) {
byte[] tag = new byte[SessionTag.BYTE_LENGTH];
System.arraycopy(decrypted, cur, tag, 0, SessionTag.BYTE_LENGTH);
cur += SessionTag.BYTE_LENGTH;
tags.add(new SessionTag(tag));
}
long len = DataHelper.fromLong(decrypted, cur, 4);
cur += 4;
// _log.debug("len: " + len);
if ((len < 0) || (len > decrypted.length - cur - Hash.HASH_LENGTH - 1))
throw new IllegalArgumentException("Invalid size of payload (" + len + ", remaining " + (decrypted.length - cur) + ")");
// byte hashval[] = new byte[Hash.HASH_LENGTH];
// System.arraycopy(decrypted, cur, hashval, 0, Hash.HASH_LENGTH);
// readHash = new Hash();
// readHash.setData(hashval);
// readHash = Hash.create(decrypted, cur);
int hashIndex = cur;
cur += Hash.HASH_LENGTH;
byte flag = decrypted[cur++];
if (flag == 0x01) {
byte[] rekeyVal = new byte[SessionKey.KEYSIZE_BYTES];
System.arraycopy(decrypted, cur, rekeyVal, 0, SessionKey.KEYSIZE_BYTES);
cur += SessionKey.KEYSIZE_BYTES;
newKey = new SessionKey();
newKey.setData(rekeyVal);
}
byte[] unencrData = new byte[(int) len];
System.arraycopy(decrypted, cur, unencrData, 0, (int) len);
cur += (int) len;
// use alternate calculateHash() method to avoid object churn and caching
// Hash calcHash = _context.sha().calculateHash(unencrData);
// boolean eq = calcHash.equals(readHash);
byte[] calcHash = SimpleByteCache.acquire(32);
_context.sha().calculateHash(unencrData, 0, (int) len, calcHash, 0);
boolean eq = DataHelper.eq(decrypted, hashIndex, calcHash, 0, 32);
SimpleByteCache.release(calcHash);
if (eq) {
// everything matches. w00t.
if (tags != null)
foundTags.addAll(tags);
if (newKey != null)
foundKey.setData(newKey.getData());
return unencrData;
}
throw new RuntimeException("Hash does not match");
} catch (RuntimeException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to decrypt AES block", e);
return null;
}
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class ElGamalTest method testElGamalAESEngine.
public void testElGamalAESEngine() throws Exception {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
ElGamalAESEngine e = new ElGamalAESEngine(ctx);
Object[] kp = ctx.keyGenerator().generatePKIKeypair();
PublicKey pubKey = (PublicKey) kp[0];
PrivateKey privKey = (PrivateKey) kp[1];
SessionKey sessionKey = ctx.keyGenerator().generateSessionKey();
for (int i = 0; i < 10; i++) {
Set<SessionTag> tags = new HashSet<SessionTag>(5);
if (i == 0) {
for (int j = 0; j < 5; j++) tags.add(new SessionTag(true));
}
byte[] encrypted = e.encrypt(DataHelper.getASCII("blah"), pubKey, sessionKey, tags, null, 1024);
byte[] decrypted = e.decrypt(encrypted, privKey, _context.sessionKeyManager());
assertEquals("blah", new String(decrypted));
ctx.sessionKeyManager().tagsDelivered(pubKey, sessionKey, tags);
}
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class TestJob method sendTest.
private void sendTest(I2NPMessage m) {
// garlic route that DeliveryStatusMessage to ourselves so the endpoints and gateways
// can't tell its a test. to simplify this, we encrypt it with a random key and tag,
// remembering that key+tag so that we can decrypt it later. this means we can do the
// garlic encryption without any ElGamal (yay)
PayloadGarlicConfig payload = new PayloadGarlicConfig();
payload.setCertificate(Certificate.NULL_CERT);
payload.setId(getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE));
payload.setPayload(m);
payload.setRecipient(getContext().router().getRouterInfo());
payload.setDeliveryInstructions(DeliveryInstructions.LOCAL);
payload.setExpiration(m.getMessageExpiration());
SessionKey encryptKey = getContext().keyGenerator().generateSessionKey();
SessionTag encryptTag = new SessionTag(true);
_encryptTag = encryptTag;
SessionKey sentKey = new SessionKey();
Set<SessionTag> sentTags = null;
GarlicMessage msg = GarlicMessageBuilder.buildMessage(getContext(), payload, sentKey, sentTags, getContext().keyManager().getPublicKey(), encryptKey, encryptTag);
if (msg == null) {
// overloaded / unknown peers / etc
scheduleRetest();
return;
}
Set<SessionTag> encryptTags = new RemovableSingletonSet<SessionTag>(encryptTag);
// Register the single tag with the appropriate SKM
if (_cfg.isInbound() && !_pool.getSettings().isExploratory()) {
SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_pool.getSettings().getDestination());
if (skm != null)
skm.tagsReceived(encryptKey, encryptTags);
} else {
getContext().sessionKeyManager().tagsReceived(encryptKey, encryptTags);
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending garlic test of " + _outTunnel + " / " + _replyTunnel);
getContext().tunnelDispatcher().dispatchOutbound(msg, _outTunnel.getSendTunnelId(0), _replyTunnel.getReceiveTunnelId(0), _replyTunnel.getPeer(0));
}
use of net.i2p.data.SessionTag in project i2p.i2p by i2p.
the class GarlicMessageBuilder method buildMessage.
/**
* called by netdb and above
*
* @param ctx scope
* @param config how/what to wrap
* @param wrappedKey output parameter that will be filled with the sessionKey used
* @param wrappedTags Output parameter that will be filled with the sessionTags used.
* If non-empty on return you must call skm.tagsDelivered() when sent
* and then call skm.tagsAcked() or skm.failTags() later.
* @param numTagsToDeliver only if the estimated available tags are below the threshold.
* Set to zero to disable tag delivery. You must set to zero if you are not
* equipped to confirm delivery and call skm.tagsAcked() or failTags() later.
* If this is always 0, it forces ElGamal every time.
* @param lowTagsThreshold the threshold
* @param skm non-null
* @throws IllegalArgumentException on error
*/
public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags, int numTagsToDeliver, int lowTagsThreshold, SessionKeyManager skm) {
Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
PublicKey key = config.getRecipientPublicKey();
if (key == null) {
if (config.getRecipient() == null) {
throw new IllegalArgumentException("Null recipient specified");
} else if (config.getRecipient().getIdentity() == null) {
throw new IllegalArgumentException("Null recipient.identity specified");
} else if (config.getRecipient().getIdentity().getPublicKey() == null) {
throw new IllegalArgumentException("Null recipient.identity.publicKey specified");
} else
key = config.getRecipient().getIdentity().getPublicKey();
}
if (log.shouldLog(Log.INFO))
log.info("Encrypted with public key to expire on " + new Date(config.getExpiration()));
SessionKey curKey = skm.getCurrentOrNewKey(key);
SessionTag curTag = null;
curTag = skm.consumeNextAvailableTag(key, curKey);
if (log.shouldLog(Log.DEBUG)) {
int availTags = skm.getAvailableTags(key, curKey);
log.debug("Available tags for encryption: " + availTags + " low threshold: " + lowTagsThreshold);
}
if (numTagsToDeliver > 0 && skm.shouldSendTags(key, curKey, lowTagsThreshold)) {
for (int i = 0; i < numTagsToDeliver; i++) wrappedTags.add(new SessionTag(true));
if (log.shouldLog(Log.INFO))
log.info("Too few tags available so we're including " + numTagsToDeliver);
}
wrappedKey.setData(curKey.getData());
return buildMessage(ctx, config, wrappedKey, wrappedTags, key, curKey, curTag);
}
use of net.i2p.data.SessionTag 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));
}
Aggregations