Search in sources :

Example 1 with SessionTag

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;
    }
}
Also used : SessionKey(net.i2p.data.SessionKey) ArrayList(java.util.ArrayList) SessionTag(net.i2p.data.SessionTag)

Example 2 with SessionTag

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);
    }
}
Also used : PrivateKey(net.i2p.data.PrivateKey) I2PAppContext(net.i2p.I2PAppContext) PublicKey(net.i2p.data.PublicKey) SessionKey(net.i2p.data.SessionKey) SessionTag(net.i2p.data.SessionTag) HashSet(java.util.HashSet)

Example 3 with SessionTag

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));
}
Also used : PayloadGarlicConfig(net.i2p.router.message.PayloadGarlicConfig) SessionKey(net.i2p.data.SessionKey) RemovableSingletonSet(net.i2p.router.util.RemovableSingletonSet) GarlicMessage(net.i2p.data.i2np.GarlicMessage) SessionKeyManager(net.i2p.crypto.SessionKeyManager) SessionTag(net.i2p.data.SessionTag)

Example 4 with SessionTag

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);
}
Also used : Log(net.i2p.util.Log) PublicKey(net.i2p.data.PublicKey) SessionKey(net.i2p.data.SessionKey) SessionTag(net.i2p.data.SessionTag) Date(java.util.Date)

Example 5 with SessionTag

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));
}
Also used : PrivateKey(net.i2p.data.PrivateKey) PublicKey(net.i2p.data.PublicKey) SessionKey(net.i2p.data.SessionKey) SessionKeyManager(net.i2p.crypto.SessionKeyManager) SessionTag(net.i2p.data.SessionTag) HashSet(java.util.HashSet) TagSetHandle(net.i2p.crypto.TagSetHandle)

Aggregations

SessionTag (net.i2p.data.SessionTag)19 SessionKey (net.i2p.data.SessionKey)15 HashSet (java.util.HashSet)8 PublicKey (net.i2p.data.PublicKey)7 SessionKeyManager (net.i2p.crypto.SessionKeyManager)6 TagSetHandle (net.i2p.crypto.TagSetHandle)5 PrivateKey (net.i2p.data.PrivateKey)4 GarlicMessage (net.i2p.data.i2np.GarlicMessage)3 ArrayList (java.util.ArrayList)2 DataFormatException (net.i2p.data.DataFormatException)2 Hash (net.i2p.data.Hash)2 PayloadGarlicConfig (net.i2p.router.message.PayloadGarlicConfig)2 RemovableSingletonSet (net.i2p.router.util.RemovableSingletonSet)2 Log (net.i2p.util.Log)2 IOException (java.io.IOException)1 Date (java.util.Date)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Set (java.util.Set)1 TreeSet (java.util.TreeSet)1