Search in sources :

Example 16 with SessionKey

use of net.i2p.data.SessionKey in project i2p.i2p by i2p.

the class PeerTestManager method receiveFromBobAsCharlie.

// Below here are methods for when we are Bob or Charlie
/**
 * The packet's IP/port does not match the IP/port included in the message,
 * so we must be Charlie receiving a PeerTest from Bob.
 *
 * @param state null if new
 */
private void receiveFromBobAsCharlie(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) {
    long now = _context.clock().now();
    int sz = testInfo.readIPSize();
    boolean isNew = false;
    if (state == null) {
        isNew = true;
        state = new PeerTestState(CHARLIE, sz == 16, nonce, now);
    } else {
        if (state.getReceiveBobTime() > now - (RESEND_TIMEOUT / 2)) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Too soon, not retransmitting: " + state);
            return;
        }
    }
    // TODO should only do most of this if isNew
    byte[] aliceIPData = new byte[sz];
    try {
        testInfo.readIP(aliceIPData, 0);
        boolean expectV6 = state.isIPv6();
        if ((!expectV6 && sz != 4) || (expectV6 && sz != 16))
            throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + sz);
        int alicePort = testInfo.readPort();
        if (alicePort == 0)
            throw new UnknownHostException("port 0");
        InetAddress aliceIP = InetAddress.getByAddress(aliceIPData);
        InetAddress bobIP = InetAddress.getByAddress(from.getIP());
        SessionKey aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
        testInfo.readIntroKey(aliceIntroKey.getData(), 0);
        state.setAliceIP(aliceIP);
        state.setAlicePort(alicePort);
        state.setAliceIntroKey(aliceIntroKey);
        state.setBobIP(bobIP);
        state.setBobPort(from.getPort());
        state.setLastSendTime(now);
        state.setReceiveBobTime(now);
        PeerState bob = _transport.getPeerState(from);
        if (bob == null) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Received from bob (" + from + ") who hasn't established a session with us, refusing to help him test " + aliceIP + ":" + alicePort);
            return;
        } else {
            state.setBobCipherKey(bob.getCurrentCipherKey());
            state.setBobMACKey(bob.getCurrentMACKey());
        }
        // we send two packets below, but increment just once
        if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_CHARLIE) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Too many, not retransmitting: " + state);
            return;
        }
        if (_log.shouldLog(Log.DEBUG))
            _log.debug("Receive from Bob: " + state);
        if (isNew) {
            _activeTests.put(Long.valueOf(nonce), state);
            _context.simpleTimer2().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
        }
        UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort, aliceIntroKey, nonce, state.getBobCipherKey(), state.getBobMACKey());
        _transport.send(packet);
        packet = _packetBuilder.buildPeerTestToAlice(aliceIP, alicePort, aliceIntroKey, _transport.getIntroKey(), nonce);
        _transport.send(packet);
    } catch (UnknownHostException uhe) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Unable to build the aliceIP from " + from + ", ip size: " + sz + " ip val: " + Base64.encode(aliceIPData), uhe);
        _context.statManager().addRateData("udp.testBadIP", 1);
    }
}
Also used : UnknownHostException(java.net.UnknownHostException) SessionKey(net.i2p.data.SessionKey) InetAddress(java.net.InetAddress)

Example 17 with SessionKey

use of net.i2p.data.SessionKey in project i2p.i2p by i2p.

the class PeerTestManager method receiveFromAliceAsBob.

/**
 * The PeerTest message came from the peer referenced in the message (or there wasn't
 * any info in the message), plus we are not acting as Charlie (so we've got to be Bob).
 *
 * testInfo IP/port ignored
 * @param state null if new
 */
private void receiveFromAliceAsBob(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) {
    // we are Bob, so pick a (potentially) Charlie and send Charlie Alice's info
    PeerState charlie;
    RouterInfo charlieInfo = null;
    int sz = from.getIP().length;
    boolean isIPv6 = sz == 16;
    if (state == null) {
        // pick a new charlie
        // if (from.getIP().length != 4) {
        // if (_log.shouldLog(Log.WARN))
        // _log.warn("PeerTest over IPv6 from Alice as Bob? " + from);
        // return;
        // }
        charlie = _transport.pickTestPeer(CHARLIE, isIPv6, from);
    } else {
        charlie = _transport.getPeerState(new RemoteHostId(state.getCharlieIP().getAddress(), state.getCharliePort()));
    }
    if (charlie == null) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Unable to pick a charlie (no peer), IPv6? " + isIPv6);
        return;
    }
    charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer());
    if (charlieInfo == null) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Unable to pick a charlie (no RI), IPv6? " + isIPv6);
        return;
    }
    // TODO should only do most of this if isNew
    InetAddress aliceIP = null;
    SessionKey aliceIntroKey = null;
    try {
        aliceIP = InetAddress.getByAddress(from.getIP());
        aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
        testInfo.readIntroKey(aliceIntroKey.getData(), 0);
        RouterAddress raddr = _transport.getTargetAddress(charlieInfo);
        if (raddr == null) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Unable to pick a charlie (no addr), IPv6? " + isIPv6);
            return;
        }
        UDPAddress addr = new UDPAddress(raddr);
        byte[] ikey = addr.getIntroKey();
        if (ikey == null) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Unable to pick a charlie (no ikey), IPv6? " + isIPv6);
            return;
        }
        SessionKey charlieIntroKey = new SessionKey(ikey);
        // UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, from.getPort(), aliceIntroKey, charlieIntroKey, nonce);
        // _transport.send(packet);
        long now = _context.clock().now();
        boolean isNew = false;
        if (state == null) {
            isNew = true;
            state = new PeerTestState(BOB, isIPv6, nonce, now);
        } else {
            if (state.getReceiveAliceTime() > now - (RESEND_TIMEOUT / 2)) {
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Too soon, not retransmitting: " + state);
                return;
            }
        }
        state.setAliceIP(aliceIP);
        state.setAlicePort(from.getPort());
        state.setAliceIntroKey(aliceIntroKey);
        state.setCharlieIP(charlie.getRemoteIPAddress());
        state.setCharliePort(charlie.getRemotePort());
        state.setCharlieIntroKey(charlieIntroKey);
        state.setLastSendTime(now);
        state.setReceiveAliceTime(now);
        if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_BOB) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Too many, not retransmitting: " + state);
            return;
        }
        if (isNew) {
            _activeTests.put(Long.valueOf(nonce), state);
            _context.simpleTimer2().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
        }
        UDPPacket packet = _packetBuilder.buildPeerTestToCharlie(aliceIP, from.getPort(), aliceIntroKey, nonce, charlie.getRemoteIPAddress(), charlie.getRemotePort(), charlie.getCurrentCipherKey(), charlie.getCurrentMACKey());
        if (_log.shouldLog(Log.DEBUG))
            _log.debug("Receive from Alice: " + state);
        _transport.send(packet);
    } catch (UnknownHostException uhe) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Unable to build the aliceIP from " + from, uhe);
        _context.statManager().addRateData("udp.testBadIP", 1);
    }
}
Also used : UnknownHostException(java.net.UnknownHostException) RouterInfo(net.i2p.data.router.RouterInfo) RouterAddress(net.i2p.data.router.RouterAddress) SessionKey(net.i2p.data.SessionKey) InetAddress(java.net.InetAddress)

Example 18 with SessionKey

use of net.i2p.data.SessionKey in project i2p.i2p by i2p.

the class BuildMessageGenerator method layeredEncrypt.

/**
 * Encrypt the records so their hop ident is visible at the appropriate times.
 *
 * Note that this layer-encrypts the build records for the message in-place.
 * Only call this once for a given message.
 *
 * @param order list of hop #s as Integers.  For instance, if (order.get(1) is 4), it is peer cfg.getPeer(4)
 */
public static void layeredEncrypt(I2PAppContext ctx, TunnelBuildMessage msg, TunnelCreatorConfig cfg, List<Integer> order) {
    // encrypt the records so that the right elements will be visible at the right time
    for (int i = 0; i < msg.getRecordCount(); i++) {
        EncryptedBuildRecord rec = msg.getRecord(i);
        Integer hopNum = order.get(i);
        int hop = hopNum.intValue();
        if ((isBlank(cfg, hop)) || (!cfg.isInbound() && hop == 1)) {
            // log.debug(msg.getUniqueId() + ": not pre-decrypting record " + i + "/" + hop + " for " + cfg);
            continue;
        }
        // if (log.shouldLog(Log.DEBUG))
        // log.debug(msg.getUniqueId() + ": pre-decrypting record " + i + "/" + hop + " for " + cfg);
        // ok, now decrypt the record with all of the reply keys from cfg.getConfig(0) through hop-1
        int stop = (cfg.isInbound() ? 0 : 1);
        for (int j = hop - 1; j >= stop; j--) {
            HopConfig hopConfig = cfg.getConfig(j);
            SessionKey key = hopConfig.getReplyKey();
            byte[] iv = hopConfig.getReplyIV();
            // if (log.shouldLog(Log.DEBUG))
            // log.debug(msg.getUniqueId() + ": pre-decrypting record " + i + "/" + hop + " for " + cfg
            // + " with " + key.toBase64() + "/" + Base64.encode(iv));
            // corrupts the SDS
            ctx.aes().decrypt(rec.getData(), 0, rec.getData(), 0, key, iv, TunnelBuildMessage.RECORD_SIZE);
        }
    }
// if (log.shouldLog(Log.DEBUG))
// log.debug(msg.getUniqueId() + ": done pre-decrypting all records for " + cfg);
}
Also used : EncryptedBuildRecord(net.i2p.data.i2np.EncryptedBuildRecord) SessionKey(net.i2p.data.SessionKey)

Example 19 with SessionKey

use of net.i2p.data.SessionKey in project i2p.i2p by i2p.

the class BuildMessageProcessor method decrypt.

/**
 * Decrypt the record targetting us, encrypting all of the other records with the included
 * reply key and IV.  The original, encrypted record targetting us is removed from the request
 * message (so that the reply can be placed in that position after going through the decrypted
 * request record).
 *
 * Note that this layer-decrypts the build records in-place.
 * Do not call this more than once for a given message.
 *
 * @return the current hop's decrypted record or null on failure
 */
public BuildRequestRecord decrypt(TunnelBuildMessage msg, Hash ourHash, PrivateKey privKey) {
    BuildRequestRecord rv = null;
    int ourHop = -1;
    long beforeActualDecrypt = 0;
    long afterActualDecrypt = 0;
    byte[] ourHashData = ourHash.getData();
    long beforeLoop = System.currentTimeMillis();
    for (int i = 0; i < msg.getRecordCount(); i++) {
        EncryptedBuildRecord rec = msg.getRecord(i);
        int len = BuildRequestRecord.PEER_SIZE;
        boolean eq = DataHelper.eq(ourHashData, 0, rec.getData(), 0, len);
        if (eq) {
            beforeActualDecrypt = System.currentTimeMillis();
            try {
                rv = new BuildRequestRecord(ctx, privKey, rec);
                afterActualDecrypt = System.currentTimeMillis();
                // i2pd bug
                boolean isBad = SessionKey.INVALID_KEY.equals(rv.readReplyKey());
                if (isBad) {
                    if (log.shouldLog(Log.WARN))
                        log.warn(msg.getUniqueId() + ": Bad reply key: " + rv);
                    ctx.statManager().addRateData("tunnel.buildRequestBadReplyKey", 1);
                    return null;
                }
                // The spec says to feed the 32-byte AES-256 reply key into the Bloom filter.
                // But we were using the first 32 bytes of the encrypted reply.
                // Fixed in 0.9.24
                boolean isDup = _filter.add(rv.getData(), BuildRequestRecord.OFF_REPLY_KEY, 32);
                if (isDup) {
                    if (log.shouldLog(Log.WARN))
                        log.warn(msg.getUniqueId() + ": Dup record: " + rv);
                    ctx.statManager().addRateData("tunnel.buildRequestDup", 1);
                    return null;
                }
                if (log.shouldLog(Log.DEBUG))
                    log.debug(msg.getUniqueId() + ": Matching record: " + rv);
                ourHop = i;
                // TODO should we keep looking for a second match and fail if found?
                break;
            } catch (DataFormatException dfe) {
                if (log.shouldLog(Log.WARN))
                    log.warn(msg.getUniqueId() + ": Matching record decrypt failure", dfe);
                // out there with the same first 16 bytes, go around again
                continue;
            }
        }
    }
    if (rv == null) {
        // none of the records matched, b0rk
        if (log.shouldLog(Log.WARN))
            log.warn(msg.getUniqueId() + ": No matching record");
        return null;
    }
    long beforeEncrypt = System.currentTimeMillis();
    SessionKey replyKey = rv.readReplyKey();
    byte[] iv = rv.readReplyIV();
    for (int i = 0; i < msg.getRecordCount(); i++) {
        if (i != ourHop) {
            EncryptedBuildRecord data = msg.getRecord(i);
            // if (log.shouldLog(Log.DEBUG))
            // log.debug("Encrypting record " + i + "/? with replyKey " + replyKey.toBase64() + "/" + Base64.encode(iv));
            // encrypt in-place, corrupts SDS
            byte[] bytes = data.getData();
            ctx.aes().encrypt(bytes, 0, bytes, 0, replyKey, iv, 0, EncryptedBuildRecord.LENGTH);
        }
    }
    long afterEncrypt = System.currentTimeMillis();
    msg.setRecord(ourHop, null);
    if (afterEncrypt - beforeLoop > 1000) {
        if (log.shouldLog(Log.WARN))
            log.warn("Slow decryption, total=" + (afterEncrypt - beforeLoop) + " looping=" + (beforeEncrypt - beforeLoop) + " decrypt=" + (afterActualDecrypt - beforeActualDecrypt) + " encrypt=" + (afterEncrypt - beforeEncrypt));
    }
    return rv;
}
Also used : EncryptedBuildRecord(net.i2p.data.i2np.EncryptedBuildRecord) DataFormatException(net.i2p.data.DataFormatException) SessionKey(net.i2p.data.SessionKey) BuildRequestRecord(net.i2p.data.i2np.BuildRequestRecord)

Example 20 with SessionKey

use of net.i2p.data.SessionKey in project i2p.i2p by i2p.

the class SessionEncryptionTest method testNoSessions1.

public void testNoSessions1() 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);
    byte[] msg = DataHelper.getASCII("msg 1");
    byte[] emsg = _context.elGamalAESEngine().encrypt(msg, pubKey, curKey, null, null, 64);
    byte[] dmsg = _context.elGamalAESEngine().decrypt(emsg, privKey, skm);
    assertTrue(DataHelper.eq(dmsg, msg));
}
Also used : PrivateKey(net.i2p.data.PrivateKey) PublicKey(net.i2p.data.PublicKey) SessionKey(net.i2p.data.SessionKey) SessionKeyManager(net.i2p.crypto.SessionKeyManager)

Aggregations

SessionKey (net.i2p.data.SessionKey)69 SessionTag (net.i2p.data.SessionTag)15 PublicKey (net.i2p.data.PublicKey)14 I2PAppContext (net.i2p.I2PAppContext)13 HashSet (java.util.HashSet)11 Hash (net.i2p.data.Hash)11 SessionKeyManager (net.i2p.crypto.SessionKeyManager)10 PrivateKey (net.i2p.data.PrivateKey)10 InetAddress (java.net.InetAddress)9 DataFormatException (net.i2p.data.DataFormatException)9 UnknownHostException (java.net.UnknownHostException)7 TagSetHandle (net.i2p.crypto.TagSetHandle)5 Map (java.util.Map)4 GarlicMessage (net.i2p.data.i2np.GarlicMessage)4 IOException (java.io.IOException)3 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 Set (java.util.Set)3 EncryptedBuildRecord (net.i2p.data.i2np.EncryptedBuildRecord)3 BigInteger (java.math.BigInteger)2