Changes in / [49ff3cfb:83588d9]


Ignore:
Files:
1 added
15 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/I2PAppContext.java

    r49ff3cfb r83588d9  
    389389     * data.  This component allows transparent operation of the
    390390     * ElGamal/AES+SessionTag algorithm, and contains all of the session tags
    391      * for one particular application.  If you want to seperate multiple apps
    392      * to have their own sessionTags and sessionKeys, they should use different
    393      * I2PAppContexts, and hence, different sessionKeyManagers.
     391     * for one particular application.
     392     *
     393     * This is deprecated for client use, it should be used only by the router
     394     * as its own key manager. Not that clients are doing end-to-end crypto anyway.
     395     *
     396     * For client crypto within the router,
     397     * use RouterContext.clientManager.getClientSessionKeyManager(dest)
    394398     *
    395399     */
  • core/java/src/net/i2p/crypto/ElGamalAESEngine.java

    r49ff3cfb r83588d9  
    6060
    6161    /**
    62      * Decrypt the message using the given private key using tags from the given key manager.
     62     * Decrypt the message using the given private key using tags from the default key manager.
     63     *
     64     * @deprecated specify the key manager!
    6365     */
    6466    public byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException {
     
    6769
    6870    /**
    69      * Decrypt the message using the given private key.  This works according to the
     71     * Decrypt the message using the given private key
     72     * and using tags from the specified key manager.
     73     * This works according to the
    7074     * ElGamal+AES algorithm in the data structure spec.
    7175     *
  • core/java/src/net/i2p/crypto/SessionKeyManager.java

    r49ff3cfb r83588d9  
    9696     *
    9797     */
    98     public void tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) { // nop
     98    public TagSetHandle tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) { // nop
     99         return null;
    99100    }
    100101
     
    135136
    136137    public void renderStatusHTML(Writer out) throws IOException {}
     138    public void failTags(PublicKey target, SessionKey key, TagSetHandle ts) {}
     139    public void tagsAcked(PublicKey target, SessionKey key, TagSetHandle ts) {}
    137140}
  • core/java/src/net/i2p/crypto/TransientSessionKeyManager.java

    r49ff3cfb r83588d9  
    2020import java.util.List;
    2121import java.util.Map;
     22import java.util.NoSuchElementException;
    2223import java.util.Set;
    2324import java.util.TreeSet;
     
    3637 * to disk).  However, this being java, we cannot guarantee that the keys aren't swapped
    3738 * out to disk so this should not be considered secure in that sense.
     39 *
     40 * The outbound and inbound sides are completely independent, each with
     41 * their own keys and tags.
     42 *
     43 * For a new session, outbound tags are not considered delivered until an ack is received.
     44 * Otherwise, the loss of the first message would render all subsequent messages
     45 * undecryptable. True?
     46 *
     47 * For an existing session, outbound tags are immediately considered delivered, and are
     48 * later revoked if the ack times out. This prevents massive stream slowdown caused by
     49 * repeated tag delivery after the minimum tag threshold is reached. Included tags
     50 * pushes messages above the ideal 1956 size by ~2KB and causes excessive fragmentation
     51 * and padding. As the tags are not seen by the streaming lib, they aren't accounted
     52 * for in the window size, and one or more of a series of large messages is likely to be dropped,
     53 * either due to high fragmentation or drop priorites at the tunnel OBEP.
     54 *
     55 * For this to work, the minimum tag threshold and tag delivery quanitity defined in
     56 * GarlicMessageBuilder must be chosen with streaming lib windows sizes in mind.
     57 * If a single TagSet is not delivered, there will be no stall as long as the
     58 * current window size is smaller than the minimum tag threshold.
     59 * Additional TagSets will be sent before the acked tags completely run out. See below.
     60 * all subsequent messages will fail to decrypt.
     61 * See ConnectionOptions in streaming for more information.
     62 *
     63 * There are large inefficiencies caused by the repeated delivery of tags in a new session.
     64 * With an initial streaming window size of 6 and 40 tags per delivery, a web server
     65 * would deliver up to 240 tags (7680 bytes, not including bundled leaseset, etc.)
     66 * in the first volley of the response.
     67 *
     68 * Could the two directions be linked somehow, such that the initial request could
     69 * contain a key or tags for the response?
     70 *
     71 * Should the tag threshold and quantity be adaptive?
     72 *
     73 * Todo: Switch to ConcurrentHashMaps and ReadWriteLocks, only get write lock during cleanup
    3874 *
    3975 */
     
    127163
    128164    /* FIXME Exporting non-public type through public API */
     165/****** leftover from when we had the persistent SKM
    129166    protected void setData(Set<TagSet> inboundTagSets, Set<OutboundSession> outboundSessions) {
    130167        if (_log.shouldLog(Log.INFO))
     
    153190        }
    154191    }
     192******/
    155193
    156194    /**
     
    180218     * when to expire that key begin with this call.
    181219     *
    182      * Unused except in tests?
    183220     */
    184221    @Override
    185222    public void createSession(PublicKey target, SessionKey key) {
    186         OutboundSession sess = new OutboundSession(target);
    187         sess.setCurrentKey(key);
    188         addSession(sess);
     223        createAndReturnSession(target, key);
    189224    }
    190225
     
    219254            SessionTag nxt = sess.consumeNext();
    220255            if (_log.shouldLog(Log.DEBUG))
    221                 _log.debug("Tag consumed: " + nxt + " with key: " + key.toBase64());
     256                _log.debug("OB Tag consumed: " + nxt + " with: " + key);
    222257            return nxt;
    223258        }
     
    262297    /**
    263298     * Take note of the fact that the given sessionTags associated with the key for
    264      * encryption to the target have definitely been received at the target (aka call this
    265      * method after receiving an ack to a message delivering them)
    266      *
    267      */
    268     @Override
    269     public void tagsDelivered(PublicKey target, SessionKey key, Set sessionTags) {
     299     * encryption to the target have been sent. Whether to use the tags immediately
     300     * (i.e. assume they will be received) or to wait until an ack, is implementation dependent.
     301     *
     302     * Here, we wait for the ack if the session is new, otherwise we use right away.
     303     * Will this work???
     304     * If the tags are pipelined sufficiently, it will.
     305     *
     306     * @return the TagSetHandle. Caller MUST subsequently call failTags() or tagsAcked()
     307     * with this handle.
     308     */
     309    @Override
     310    public TagSetHandle tagsDelivered(PublicKey target, SessionKey key, Set<SessionTag> sessionTags) {
    270311        if (_log.shouldLog(Log.DEBUG)) {
    271312            //_log.debug("Tags delivered to set " + set + " on session " + sess);
    272313            if (sessionTags.size() > 0)
    273                 _log.debug("Tags delivered: " + sessionTags.size() + " for key: " + key.toBase64() + ": " + sessionTags);
     314                _log.debug("Tags delivered: " + sessionTags.size() + " for key: " + key + ": " + sessionTags);
    274315        }
    275316        OutboundSession sess = getSession(target);
    276317        if (sess == null)
    277318            sess = createAndReturnSession(target, key);
    278         sess.setCurrentKey(key);
     319        else
     320            sess.setCurrentKey(key);
    279321        TagSet set = new TagSet(sessionTags, key, _context.clock().now());
    280322        sess.addTags(set);
     323        return set;
    281324    }
    282325
     
    286329     * from corrupted tag sets and crashes
    287330     *
     331     * @deprecated unused and rather drastic
    288332     */
    289333    @Override
    290334    public void failTags(PublicKey target) {
    291335        removeSession(target);
     336    }
     337
     338    /**
     339     * Mark these tags as invalid, since the peer
     340     * has failed to ack them in time.
     341     */
     342    @Override
     343    public void failTags(PublicKey target, SessionKey key, TagSetHandle ts) {
     344        OutboundSession sess = getSession(target);
     345        if (sess == null)
     346            return;
     347        if(!key.equals(sess.getCurrentKey()))
     348            return;
     349        sess.failTags((TagSet)ts);
     350        if (_log.shouldLog(Log.DEBUG))
     351            _log.debug("TagSet failed: " + ts);
     352    }
     353
     354    /**
     355     * Mark these tags as acked, start to use them (if we haven't already)
     356     */
     357    @Override
     358    public void tagsAcked(PublicKey target, SessionKey key, TagSetHandle ts) {
     359        OutboundSession sess = getSession(target);
     360        if (sess == null)
     361            return;
     362        if(!key.equals(sess.getCurrentKey()))
     363            return;
     364        sess.ackTags((TagSet)ts);
     365        if (_log.shouldLog(Log.DEBUG))
     366            _log.debug("TagSet acked: " + ts);
    292367    }
    293368
     
    305380            SessionTag tag = iter.next();
    306381            if (_log.shouldLog(Log.DEBUG))
    307                 _log.debug("Receiving tag " + tag + " for key " + key.toBase64() + " / " + key.toString() + ": tagSet: " + tagSet);
     382                _log.debug("Receiving tag " + tag + " for key " + key + ": tagSet: " + tagSet);
    308383            synchronized (_inboundTagSets) {
    309                 old = (TagSet)_inboundTagSets.put(tag, tagSet);
     384                old = _inboundTagSets.put(tag, tagSet);
    310385                overage = _inboundTagSets.size() - MAX_INBOUND_SESSION_TAGS;
    311386                if (old != null) {
     
    335410
    336411            if (_log.shouldLog(Log.WARN)) {
    337                 _log.warn("Multiple tags matching!  tagSet: " + tagSet + " and old tagSet: " + old + " tag: " + dupTag + "/" + dupTag.toBase64());
    338                 _log.warn("Earlier tag set creation: " + old + ": key=" + old.getAssociatedKey().toBase64(), old.getCreatedBy());
    339                 _log.warn("Current tag set creation: " + tagSet + ": key=" + tagSet.getAssociatedKey().toBase64(), tagSet.getCreatedBy());
     412                _log.warn("Multiple tags matching!  tagSet: " + tagSet + " and old tagSet: " + old + " tag: " + dupTag + "/" + dupTag);
     413                _log.warn("Earlier tag set creation: " + old + ": key=" + old.getAssociatedKey());
     414                _log.warn("Current tag set creation: " + tagSet + ": key=" + tagSet.getAssociatedKey());
    340415            }
    341416        }
     
    346421        if ( (sessionTags.size() <= 0) && (_log.shouldLog(Log.DEBUG)) )
    347422            _log.debug("Received 0 tags for key " + key);
    348         if (false) aggressiveExpire();
     423        //if (false) aggressiveExpire();
    349424    }
    350425   
     
    411486    @Override
    412487    public SessionKey consumeTag(SessionTag tag) {
    413         if (false) aggressiveExpire();
     488        //if (false) aggressiveExpire();
    414489        synchronized (_inboundTagSets) {
    415490            TagSet tagSet = (TagSet) _inboundTagSets.remove(tag);
    416491            if (tagSet == null) {
    417492                if (_log.shouldLog(Log.DEBUG))
    418                     _log.debug("Cannot consume tag " + tag + " as it is not known");
     493                    _log.debug("Cannot consume IB " + tag + " as it is not known");
    419494                return null;
    420495            }
     
    423498            SessionKey key = tagSet.getAssociatedKey();
    424499            if (_log.shouldLog(Log.DEBUG))
    425                 _log.debug("Consuming tag " + tag.toString() + " for sessionKey " + key.toBase64() + " / " + key.toString() + " on tagSet: " + tagSet);
     500                _log.debug("Consuming IB " + tag + " for " + key + " on: " + tagSet);
    426501            return key;
    427502        }
     
    430505    private OutboundSession getSession(PublicKey target) {
    431506        synchronized (_outboundSessions) {
    432             return (OutboundSession) _outboundSessions.get(target);
     507            return _outboundSessions.get(target);
    433508        }
    434509    }
     
    444519        OutboundSession session = null;
    445520        synchronized (_outboundSessions) {
    446             session = (OutboundSession)_outboundSessions.remove(target);
     521            session = _outboundSessions.remove(target);
    447522        }
    448523        if ( (session != null) && (_log.shouldLog(Log.WARN)) )
     
    462537        long now = _context.clock().now();
    463538        StringBuilder buf = null;
    464         StringBuilder bufSummary = null;
     539        //StringBuilder bufSummary = null;
    465540        if (_log.shouldLog(Log.DEBUG)) {
    466541            buf = new StringBuilder(128);
    467542            buf.append("Expiring inbound: ");
    468             bufSummary = new StringBuilder(1024);
     543            //bufSummary = new StringBuilder(1024);
    469544        }
    470545        synchronized (_inboundTagSets) {
     
    478553                    removed++;
    479554                    if (buf != null)
    480                         buf.append(tag.toString()).append(" @ age ").append(DataHelper.formatDuration(age));
    481                 } else if (false && (bufSummary != null) ) {
    482                     bufSummary.append("\nTagSet: " + ts.toString() + ", key: " + ts.getAssociatedKey().toBase64()+"/" + ts.getAssociatedKey().toString()
    483                                       + ": tag: " + tag.toString());
     555                        buf.append(tag).append(" @ age ").append(DataHelper.formatDuration(age));
     556                //} else if (false && (bufSummary != null) ) {
     557                //    bufSummary.append("\nTagSet: " + ts + ", key: " + ts.getAssociatedKey()
     558                //                      + ": tag: " + tag);
    484559                }
    485560            }
     
    489564        if ( (buf != null) && (removed > 0) )
    490565            _log.debug(buf.toString());
    491         if (bufSummary != null)
    492             _log.debug("Cleaning up with remaining: " + bufSummary.toString());
     566        //if (bufSummary != null)
     567        //    _log.debug("Cleaning up with remaining: " + bufSummary.toString());
    493568
    494569        //_log.warn("Expiring tags: [" + tagsToDrop + "]");
     
    499574                OutboundSession sess = _outboundSessions.get(key);
    500575                removed += sess.expireTags();
    501                 if (sess.availableTags() <= 0) {
     576                // don't kill a new session or one that's temporarily out of tags
     577                if (sess.getLastUsedDate() < now - (SESSION_LIFETIME_MAX_MS / 2) &&
     578                    sess.availableTags() <= 0) {
    502579                    iter.remove();
    503                     removed++;
     580                    removed++;   // just to have a non-zero return value?
    504581                }
    505582            }
     
    564641                total += size;
    565642                buf.append("<li><b>Sent:</b> ").append(DataHelper.formatDuration(now - ts.getDate())).append(" ago with ");
    566                 buf.append(size).append(" tags remaining</li>");
     643                buf.append(size).append(" tags remaining; acked? ").append(ts.getAcked()).append("</li>");
    567644            }
    568645            buf.append("</ul></td></tr>\n");
     
    581658     *  Earliest first
    582659     */
    583     private class TagSetComparator implements Comparator {
     660    private static class TagSetComparator implements Comparator {
    584661         public int compare(Object l, Object r) {
    585662             return (int) (((TagSet)l).getDate() - ((TagSet)r).getDate());
     
    587664    }
    588665
    589     class OutboundSession {
     666    private class OutboundSession {
    590667        private PublicKey _target;
    591668        private SessionKey _currentKey;
    592669        private long _established;
    593670        private long _lastUsed;
     671        /** before the first ack, all tagsets go here. These are never expired, we rely
     672            on the callers to call failTags() or ackTags() to remove them from this list. */
     673        private /* FIXME final FIXME */ List<TagSet> _unackedTagSets;
     674        /**
     675         *  As tagsets are acked, they go here.
     676         *  After the first ack, new tagsets go here (i.e. presumed acked)
     677         */
    594678        private /* FIXME final FIXME */ List<TagSet> _tagSets;
     679        /** set to true after first tagset is acked */
     680        private boolean _acked;
    595681
    596682        public OutboundSession(PublicKey target) {
     
    603689            _established = established;
    604690            _lastUsed = lastUsed;
    605             _tagSets = tagSets;
    606         }
    607 
    608         /** list of TagSet objects */
     691            _unackedTagSets = tagSets;
     692            _tagSets = new ArrayList();
     693        }
     694
     695        /**
     696         *  @return list of TagSet objects
     697         *  This is used only by renderStatusHTML().
     698         *  It includes both acked and unacked TagSets.
     699         */
    609700        List<TagSet> getTagSets() {
     701            List<TagSet> rv;
    610702            synchronized (_tagSets) {
    611                 return new ArrayList(_tagSets);
     703                rv = new ArrayList(_unackedTagSets);
     704                rv.addAll(_tagSets);
     705            }
     706            return rv;
     707        }
     708
     709        /**
     710         *  got an ack for these tags
     711         *  For tagsets delivered after the session was acked, this is a nop
     712         *  because the tagset was originally placed directly on the acked list.
     713         */
     714        void ackTags(TagSet set) {
     715            synchronized (_tagSets) {
     716                if (_unackedTagSets.remove(set)) {
     717                    _tagSets.add(set);
     718                    _acked = true;
     719                }
     720            }
     721            set.setAcked();
     722        }
     723
     724        /** didn't get an ack for these tags */
     725        void failTags(TagSet set) {
     726            synchronized (_tagSets) {
     727                _unackedTagSets.remove(set);
     728                _tagSets.remove(set);
    612729            }
    613730        }
     
    657774            synchronized (_tagSets) {
    658775                for (int i = 0; i < _tagSets.size(); i++) {
    659                     TagSet set = (TagSet) _tagSets.get(i);
     776                    TagSet set = _tagSets.get(i);
    660777                    if (set.getDate() + SESSION_TAG_DURATION_MS <= now) {
    661778                        _tagSets.remove(i);
     
    673790            synchronized (_tagSets) {
    674791                while (_tagSets.size() > 0) {
    675                     TagSet set = (TagSet) _tagSets.get(0);
     792                    TagSet set = _tagSets.get(0);
    676793                    if (set.getDate() + SESSION_TAG_DURATION_MS > now) {
    677794                        SessionTag tag = set.consumeNext();
     
    687804        }
    688805
     806        /** @return the total number of tags in acked TagSets */
    689807        public int availableTags() {
    690808            int tags = 0;
     
    692810            synchronized (_tagSets) {
    693811                for (int i = 0; i < _tagSets.size(); i++) {
    694                     TagSet set = (TagSet) _tagSets.get(i);
    695                     if (set.getDate() + SESSION_TAG_DURATION_MS > now)
    696                         tags += set.getTags().size();
     812                    TagSet set = _tagSets.get(i);
     813                    if (set.getDate() + SESSION_TAG_DURATION_MS > now) {
     814                        int sz = set.getTags().size();
     815                        // so tags are sent when the acked tags are below
     816                        // 30, 17, and 4.
     817                        if (!set.getAcked())
     818                            sz /= 3;
     819                        tags += sz;
     820                    }
    697821                }
    698822            }
     
    720844        }
    721845
     846        /**
     847         *  If the session has never been acked, put the TagSet on the unacked list.
     848         *  Otherwise, consider it good right away.
     849         */
    722850        public void addTags(TagSet set) {
    723851            _lastUsed = _context.clock().now();
    724             synchronized (_tagSets) {
    725                 _tagSets.add(set);
    726             }
    727         }
    728     }
    729 
    730     static class TagSet {
     852            if (_acked) {
     853                synchronized (_tagSets) {
     854                    _tagSets.add(set);
     855                }
     856            } else {
     857                synchronized (_unackedTagSets) {
     858                    _unackedTagSets.add(set);
     859                }
     860            }
     861        }
     862    }
     863
     864    private static class TagSet implements TagSetHandle {
    731865        private Set<SessionTag> _sessionTags;
    732866        private SessionKey _key;
    733867        private long _date;
    734         private Exception _createdBy;
     868        //private Exception _createdBy;
     869        /** did we get an ack for this tagset? */
     870        private boolean _acked;
    735871
    736872        public TagSet(Set<SessionTag> tags, SessionKey key, long date) {
     
    740876            _key = key;
    741877            _date = date;
    742             if (true) {
    743                 long now = I2PAppContext.getGlobalContext().clock().now();
    744                 _createdBy = new Exception("Created by: key=" + _key.toBase64() + " on "
    745                                            + new Date(now) + "/" + now
    746                                            + " via " + Thread.currentThread().getName());
    747             }
     878            //if (true) {
     879            //    long now = I2PAppContext.getGlobalContext().clock().now();
     880            //    _createdBy = new Exception("Created by: key=" + _key.toBase64() + " on "
     881            //                               + new Date(now) + "/" + now
     882            //                               + " via " + Thread.currentThread().getName());
     883            //}
    748884        }
    749885
     
    771907
    772908        public void consume(SessionTag tag) {
    773             if (contains(tag)) {
    774                 _sessionTags.remove(tag);
    775             }
    776         }
    777 
     909            _sessionTags.remove(tag);
     910        }
     911
     912        /** let's do this without counting the elements first */
    778913        public SessionTag consumeNext() {
    779             if (_sessionTags.size() <= 0) {
     914            SessionTag first;
     915            try {
     916                first = _sessionTags.iterator().next();
     917            } catch (NoSuchElementException nsee) {
    780918                return null;
    781919            }
    782 
    783             SessionTag first = (SessionTag) _sessionTags.iterator().next();
    784920            _sessionTags.remove(first);
    785921            return first;
    786922        }
    787923       
    788         public Exception getCreatedBy() { return _createdBy; }
     924        //public Exception getCreatedBy() { return _createdBy; }
     925
     926        public void setAcked() { _acked = true; }
     927        public boolean getAcked() { return _acked; }
    789928       
     929/******    this will return a dup if two in the same ms, so just use java
    790930        @Override
    791931        public int hashCode() {
     
    801941            if ((o == null) || !(o instanceof TagSet)) return false;
    802942            TagSet ts = (TagSet) o;
    803             return DataHelper.eq(ts.getAssociatedKey(), getAssociatedKey())
     943            return DataHelper.eq(ts.getAssociatedKey(), _key)
    804944                   //&& DataHelper.eq(ts.getTags(), getTags())
    805                    && ts.getDate() == getDate();
     945                   && ts.getDate() == _date;
     946        }
     947******/
     948
     949        @Override
     950        public String toString() {
     951            StringBuilder buf = new StringBuilder(256);
     952            buf.append("TagSet established: ").append(new Date(_date));
     953            buf.append(" Session key: ").append(_key.toBase64());
     954            buf.append(" Size: ").append(_sessionTags.size());
     955            buf.append(" Acked? ").append(_acked);
     956            return buf.toString();
    806957        }
    807958    }
  • core/java/src/net/i2p/data/SessionKey.java

    r49ff3cfb r83588d9  
    9090    @Override
    9191    public String toString() {
     92        return "SessionKey " + toBase64();
     93      /****
    9294        if (true) return super.toString();
    9395        StringBuilder buf = new StringBuilder(64);
     
    104106        buf.append("]");
    105107        return buf.toString();
     108      ****/
    106109    }
    107110}
  • core/java/src/net/i2p/data/SessionTag.java

    r49ff3cfb r83588d9  
    5959    }
    6060
     61    @Override
     62    public String toString() {
     63        return "SessionTag " + toBase64();
     64    }
    6165}
  • router/java/src/net/i2p/router/client/ClientConnectionRunner.java

    r49ff3cfb r83588d9  
    1919
    2020import net.i2p.crypto.SessionKeyManager;
     21import net.i2p.crypto.TransientSessionKeyManager;
    2122import net.i2p.data.Destination;
    2223import net.i2p.data.Hash;
     
    189190            _log.debug("SessionEstablished called for destination " + _destHashCache.toBase64());
    190191        _config = config;
    191         // per-dest unimplemented
    192         //if (_sessionKeyManager == null)
    193         //    _sessionKeyManager = new TransientSessionKeyManager(_context);
    194         //else
    195         //    _log.error("SessionEstablished called for twice for destination " + _destHashCache.toBase64().substring(0,4));
     192        // per-destination session key manager to prevent rather easy correlation
     193        if (_sessionKeyManager == null)
     194            _sessionKeyManager = new TransientSessionKeyManager(_context);
     195        else
     196            _log.error("SessionEstablished called for twice for destination " + _destHashCache.toBase64().substring(0,4));
    196197        _manager.destinationEstablished(this);
    197198    }
  • router/java/src/net/i2p/router/message/GarlicMessageBuilder.java

    r49ff3cfb r83588d9  
    1818import net.i2p.data.DataFormatException;
    1919import net.i2p.data.DataHelper;
    20 import net.i2p.data.Destination;
     20import net.i2p.data.Hash;
    2121import net.i2p.data.PublicKey;
    2222import net.i2p.data.SessionKey;
     
    6060     *  So a value somewhat higher than the low threshold
    6161     *  seems appropriate.
     62     *
     63     *  Use care when adjusting these values. See ConnectionOptions in streaming,
     64     *  and TransientSessionKeyManager in crypto, for more information.
    6265     */
    6366    private static final int DEFAULT_TAGS = 40;
    64     private static final int LOW_THRESHOLD = 20;
    65 
    66     public static int estimateAvailableTags(RouterContext ctx, PublicKey key, Destination local) {
    67         // per-dest Unimplemented
    68         //SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(local);
    69         SessionKeyManager skm = ctx.sessionKeyManager();
     67    private static final int LOW_THRESHOLD = 30;
     68
     69    /** @param local non-null; do not use this method for the router's SessionKeyManager */
     70    public static int estimateAvailableTags(RouterContext ctx, PublicKey key, Hash local) {
     71        SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(local);
    7072        if (skm == null)
    7173            return 0;
     
    7678    }
    7779   
    78     public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config) {
    79         return buildMessage(ctx, config, new SessionKey(), new HashSet());
    80     }
    81 
    82     public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags) {
    83         return buildMessage(ctx, config, wrappedKey, wrappedTags, DEFAULT_TAGS);
    84     }
    85 
    86     public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags, int numTagsToDeliver) {
     80    /**
     81     * Unused and probably a bad idea.
     82     *
     83     * Used below only on a recursive call if the garlic message contains a garlic message.
     84     * We don't need the SessionKey or SesssionTags returned
     85     * This uses the router's SKM, which is probably not what you want.
     86     * This isn't fully implemented, because the key and tags aren't saved - maybe
     87     * it should force elGamal?
     88     *
     89     * @param ctx scope
     90     * @param config how/what to wrap
     91     */
     92    private static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config) {
     93        Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
     94        log.error("buildMessage 2 args, using router SKM", new Exception("who did it"));
     95        return buildMessage(ctx, config, new SessionKey(), new HashSet(), ctx.sessionKeyManager());
     96    }
     97
     98    /**
     99     * called by OCMJH
     100     *
     101     * @param ctx scope
     102     * @param config how/what to wrap
     103     * @param wrappedKey output parameter that will be filled with the sessionKey used
     104     * @param wrappedTags output parameter that will be filled with the sessionTags used
     105     */
     106    public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
     107                                             SessionKeyManager skm) {
     108        return buildMessage(ctx, config, wrappedKey, wrappedTags, DEFAULT_TAGS, false, skm);
     109    }
     110
     111    /** unused */
     112    /***
     113    public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags,
     114                                             int numTagsToDeliver) {
    87115        return buildMessage(ctx, config, wrappedKey, wrappedTags, numTagsToDeliver, false);
    88116    }
    89 
    90     public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags, int numTagsToDeliver, boolean forceElGamal) {
     117    ***/
     118
     119    /**
     120     * @param ctx scope
     121     * @param config how/what to wrap
     122     * @param wrappedKey output parameter that will be filled with the sessionKey used
     123     * @param wrappedTags output parameter that will be filled with the sessionTags used
     124     * @param numTagsToDeliver only if the estimated available tags are below the threshold
     125     */
     126    private static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
     127                                             int numTagsToDeliver, boolean forceElGamal, SessionKeyManager skm) {
    91128        Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
    92129        PublicKey key = config.getRecipientPublicKey();
     
    105142            log.info("Encrypted with public key " + key + " to expire on " + new Date(config.getExpiration()));
    106143       
    107         SessionKey curKey = ctx.sessionKeyManager().getCurrentKey(key);
     144        SessionKey curKey = skm.getCurrentKey(key);
    108145        SessionTag curTag = null;
    109146        if (curKey == null)
    110             curKey = ctx.sessionKeyManager().createSession(key);
     147            curKey = skm.createSession(key);
    111148        if (!forceElGamal) {
    112             curTag = ctx.sessionKeyManager().consumeNextAvailableTag(key, curKey);
     149            curTag = skm.consumeNextAvailableTag(key, curKey);
    113150           
    114             int availTags = ctx.sessionKeyManager().getAvailableTags(key, curKey);
     151            int availTags = skm.getAvailableTags(key, curKey);
    115152            if (log.shouldLog(Log.DEBUG))
    116153                log.debug("Available tags for encryption to " + key + ": " + availTags);
     
    121158                if (log.shouldLog(Log.INFO))
    122159                    log.info("Too few are available (" + availTags + "), so we're including more");
    123             } else if (ctx.sessionKeyManager().getAvailableTimeLeft(key, curKey) < 60*1000) {
     160            } else if (skm.getAvailableTimeLeft(key, curKey) < 60*1000) {
    124161                // if we have enough tags, but they expire in under 30 seconds, we want more
    125162                for (int i = 0; i < numTagsToDeliver; i++)
     
    139176   
    140177    /**
     178     *  used by TestJob and directly above
     179     *
    141180     * @param ctx scope
    142181     * @param config how/what to wrap
    143      * @param wrappedKey output parameter that will be filled with the sessionKey used
     182     * @param wrappedKey unused - why??
    144183     * @param wrappedTags output parameter that will be filled with the sessionTags used
    145184     * @param target public key of the location being garlic routed to (may be null if we
     
    148187     * @param encryptTag sessionTag used to encrypt the current message
    149188     */
    150     public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set wrappedTags, PublicKey target, SessionKey encryptKey, SessionTag encryptTag) {
     189    public static GarlicMessage buildMessage(RouterContext ctx, GarlicConfig config, SessionKey wrappedKey, Set<SessionTag> wrappedTags,
     190                                             PublicKey target, SessionKey encryptKey, SessionTag encryptTag) {
    151191        Log log = ctx.logManager().getLog(GarlicMessageBuilder.class);
    152192        if (config == null)
     
    210250                    } else {
    211251                        log.debug("Subclove IS NOT a payload garlic clove");
     252                        // See notes below
    212253                        cloves[i] = buildClove(ctx, c);
    213254                    }
     
    243284    }
    244285   
     286    /**
     287     *  UNUSED
     288     *
     289     *  The Garlic Message we are building contains another garlic message,
     290     *  as specified by a GarlicConfig (NOT a PayloadGarlicConfig).
     291     *
     292     *  So this calls back to the top, to buildMessage(ctx, config),
     293     *  which uses the router's SKM, i.e. the wrong one.
     294     *  Unfortunately we've lost the reference to the SessionKeyManager way down here,
     295     *  so we can't call buildMessage(ctx, config, key, tags, skm).
     296     *
     297     *  If we do ever end up constructing a garlic message that contains a garlic message,
     298     *  we'll have to fix this by passing the skm through the last buildMessage,
     299     *  through buildCloveSet, to here.
     300     *
     301     */
    245302    private static byte[] buildClove(RouterContext ctx, GarlicConfig config) throws DataFormatException, IOException {
    246303        GarlicClove clove = new GarlicClove(ctx);
  • router/java/src/net/i2p/router/message/GarlicMessageParser.java

    r49ff3cfb r83588d9  
    1111import java.util.Date;
    1212
     13import net.i2p.crypto.SessionKeyManager;
    1314import net.i2p.data.Certificate;
    1415import net.i2p.data.DataFormatException;
     
    3334    }
    3435   
    35     public CloveSet getGarlicCloves(GarlicMessage message, PrivateKey encryptionKey) {
     36    /** @param skm use tags from this session key manager */
     37    public CloveSet getGarlicCloves(GarlicMessage message, PrivateKey encryptionKey, SessionKeyManager skm) {
    3638        byte encData[] = message.getData();
    3739        byte decrData[] = null;
     
    3941            if (_log.shouldLog(Log.DEBUG))
    4042                _log.debug("Decrypting with private key " + encryptionKey);
    41             decrData = _context.elGamalAESEngine().decrypt(encData, encryptionKey);
     43            decrData = _context.elGamalAESEngine().decrypt(encData, encryptionKey, skm);
    4244        } catch (DataFormatException dfe) {
    4345            if (_log.shouldLog(Log.WARN))
  • router/java/src/net/i2p/router/message/GarlicMessageReceiver.java

    r49ff3cfb r83588d9  
    99 */
    1010
     11import net.i2p.crypto.SessionKeyManager;
    1112import net.i2p.data.DataHelper;
    1213import net.i2p.data.Hash;
     
    4849        _parser = new GarlicMessageParser(context);
    4950        _receiver = receiver;
     51        //_log.error("New GMR dest = " + clientDestination);
    5052    }
    5153   
    5254    public void receive(GarlicMessage message) {
    5355        PrivateKey decryptionKey = null;
     56        SessionKeyManager skm = null;
    5457        if (_clientDestination != null) {
    5558            LeaseSetKeys keys = _context.keyManager().getKeys(_clientDestination);
    56             if (keys != null) {
     59            skm = _context.clientManager().getClientSessionKeyManager(_clientDestination);
     60            if (keys != null && skm != null) {
    5761                decryptionKey = keys.getDecryptionKey();
    5862            } else {
     
    6367        } else {
    6468            decryptionKey = _context.keyManager().getPrivateKey();
     69            skm = _context.sessionKeyManager();
    6570        }
    6671       
    67         CloveSet set = _parser.getGarlicCloves(message, decryptionKey);
     72        CloveSet set = _parser.getGarlicCloves(message, decryptionKey, skm);
    6873        if (set != null) {
    6974            for (int i = 0; i < set.getCloveCount(); i++) {
  • router/java/src/net/i2p/router/message/HandleGarlicMessageJob.java

    r49ff3cfb r83588d9  
    3232    private Log _log;
    3333    private GarlicMessage _message;
    34     private RouterIdentity _from;
    35     private Hash _fromHash;
    36     private Map _cloves; // map of clove Id --> Expiration of cloves we've already seen
     34    //private RouterIdentity _from;
     35    //private Hash _fromHash;
     36    //private Map _cloves; // map of clove Id --> Expiration of cloves we've already seen
    3737    //private MessageHandler _handler;
    38     private GarlicMessageParser _parser;
     38    //private GarlicMessageParser _parser;
    3939   
    4040    private final static int FORWARD_PRIORITY = 50;
    4141   
     42    /**
     43     *  @param from ignored
     44     *  @param fromHash ignored
     45     */
    4246    public HandleGarlicMessageJob(RouterContext context, GarlicMessage msg, RouterIdentity from, Hash fromHash) {
    4347        super(context);
     
    4751            _log.debug("New handle garlicMessageJob called w/ message from [" + from + "]", new Exception("Debug"));
    4852        _message = msg;
    49         _from = from;
    50         _fromHash = fromHash;
    51         _cloves = new HashMap();
     53        //_from = from;
     54        //_fromHash = fromHash;
     55        //_cloves = new HashMap();
    5256        //_handler = new MessageHandler(context);
    53         _parser = new GarlicMessageParser(context);
     57        //_parser = new GarlicMessageParser(context);
    5458    }
    5559   
  • router/java/src/net/i2p/router/message/OutboundClientMessageJobHelper.java

    r49ff3cfb r83588d9  
    1818import net.i2p.data.PublicKey;
    1919import net.i2p.data.SessionKey;
     20import net.i2p.data.SessionTag;
    2021import net.i2p.data.TunnelId;
    2122import net.i2p.data.i2np.DataMessage;
     
    4748     * For now, its just a tunneled DeliveryStatusMessage
    4849     *
     50     * Unused?
     51     *
    4952     * @param bundledReplyLeaseSet if specified, the given LeaseSet will be packaged with the message (allowing
    5053     *                             much faster replies, since their netDb search will return almost instantly)
     
    5356    static GarlicMessage createGarlicMessage(RouterContext ctx, long replyToken, long expiration, PublicKey recipientPK,
    5457                                             Payload data, Hash from, Destination dest, TunnelInfo replyTunnel,
    55                                              SessionKey wrappedKey, Set wrappedTags,
     58                                             SessionKey wrappedKey, Set<SessionTag> wrappedTags,
    5659                                             boolean requireAck, LeaseSet bundledReplyLeaseSet) {
    5760        PayloadGarlicConfig dataClove = buildDataClove(ctx, data, dest, expiration);
     
    6366     * same payload (including expiration and unique id) in different garlics (down different tunnels)
    6467     *
     68     * This is called from OCMOSJ
     69     *
    6570     * @return garlic, or null if no tunnels were found (or other errors)
    6671     */
    6772    static GarlicMessage createGarlicMessage(RouterContext ctx, long replyToken, long expiration, PublicKey recipientPK,
    6873                                             PayloadGarlicConfig dataClove, Hash from, Destination dest, TunnelInfo replyTunnel, SessionKey wrappedKey,
    69                                              Set wrappedTags, boolean requireAck, LeaseSet bundledReplyLeaseSet) {
     74                                             Set<SessionTag> wrappedTags, boolean requireAck, LeaseSet bundledReplyLeaseSet) {
    7075        GarlicConfig config = createGarlicConfig(ctx, replyToken, expiration, recipientPK, dataClove, from, dest, replyTunnel, requireAck, bundledReplyLeaseSet);
    7176        if (config == null)
    7277            return null;
    73         GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, config, wrappedKey, wrappedTags);
     78        GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, config, wrappedKey, wrappedTags,
     79                                                              ctx.clientManager().getClientSessionKeyManager(from));
    7480        return msg;
    7581    }
  • router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java

    r49ff3cfb r83588d9  
    1111import java.util.Set;
    1212
     13import net.i2p.crypto.SessionKeyManager;
     14import net.i2p.crypto.TagSetHandle;
    1315import net.i2p.data.Base64;
    1416import net.i2p.data.Certificate;
     
    2123import net.i2p.data.RouterInfo;
    2224import net.i2p.data.SessionKey;
     25import net.i2p.data.SessionTag;
    2326import net.i2p.data.i2cp.MessageId;
    2427import net.i2p.data.i2np.DataMessage;
     
    472475        }
    473476
    474         int existingTags = GarlicMessageBuilder.estimateAvailableTags(getContext(), _leaseSet.getEncryptionKey(), _from);
     477        int existingTags = GarlicMessageBuilder.estimateAvailableTags(getContext(), _leaseSet.getEncryptionKey(),
     478                                                                      _from.calculateHash());
    475479        _outTunnel = selectOutboundTunnel(_to);
    476480        // boolean wantACK = _wantACK || existingTags <= 30 || getContext().random().nextInt(100) < 5;
     
    490494        PublicKey key = _leaseSet.getEncryptionKey();
    491495        SessionKey sessKey = new SessionKey();
    492         Set tags = new HashSet();
     496        Set<SessionTag> tags = new HashSet();
    493497        // If we want an ack, bundle a leaseSet... (so he can get back to us)
    494498        LeaseSet replyLeaseSet = getReplyLeaseSet(wantACK);
     
    532536        ReplySelector selector = null;
    533537        if (wantACK) {
    534             onReply = new SendSuccessJob(getContext(), sessKey, tags);
    535             onFail = new SendTimeoutJob(getContext());
     538            TagSetHandle tsh = null;
     539            if ( (sessKey != null) && (tags != null) && (tags.size() > 0) ) {
     540                if (_leaseSet != null) {
     541                    SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
     542                    if (skm != null)
     543                        tsh = skm.tagsDelivered(_leaseSet.getEncryptionKey(), sessKey, tags);
     544                }
     545            }
     546            onReply = new SendSuccessJob(getContext(), sessKey, tsh);
     547            onFail = new SendTimeoutJob(getContext(), sessKey, tsh);
    536548            selector = new ReplySelector(token);
    537549        }
     
    551563
    552564            DispatchJob dispatchJob = new DispatchJob(getContext(), msg, selector, onReply, onFail, (int)(_overallExpiration-getContext().clock().now()));
    553             if (false) // dispatch may take 100+ms, so toss it in its own job
    554                 getContext().jobQueue().addJob(dispatchJob);
    555             else
     565            //if (false) // dispatch may take 100+ms, so toss it in its own job
     566            //    getContext().jobQueue().addJob(dispatchJob);
     567            //else
    556568                dispatchJob.runJob();
    557569        } else {
     
    849861    /** build the payload clove that will be used for all of the messages, placing the clove in the status structure */
    850862    private boolean buildClove() {
     863// FIXME set SKM
    851864        PayloadGarlicConfig clove = new PayloadGarlicConfig();
    852865       
     
    933946    private class SendSuccessJob extends JobImpl implements ReplyJob {
    934947        private SessionKey _key;
    935         private Set _tags;
     948        private TagSetHandle _tags;
    936949       
    937950        /**
     
    940953         *
    941954         */
    942         public SendSuccessJob(RouterContext enclosingContext, SessionKey key, Set tags) {
     955        public SendSuccessJob(RouterContext enclosingContext, SessionKey key, TagSetHandle tags) {
    943956            super(enclosingContext);
    944957            _key = key;
     
    956969                           + " sent after " + sendTime + "ms");
    957970           
    958             if ( (_key != null) && (_tags != null) && (_tags.size() > 0) ) {
    959                 if (_leaseSet != null)
    960                     getContext().sessionKeyManager().tagsDelivered(_leaseSet.getEncryptionKey(),
    961                                                                   _key, _tags);
     971            if (_key != null && _tags != null && _leaseSet != null) {
     972                SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
     973                if (skm != null)
     974                    skm.tagsAcked(_leaseSet.getEncryptionKey(), _key, _tags);
    962975            }
    963976           
     
    9951008     */
    9961009    private class SendTimeoutJob extends JobImpl {
    997         public SendTimeoutJob(RouterContext enclosingContext) {
     1010        private SessionKey _key;
     1011        private TagSetHandle _tags;
     1012
     1013        public SendTimeoutJob(RouterContext enclosingContext, SessionKey key, TagSetHandle tags) {
    9981014            super(enclosingContext);
     1015            _key = key;
     1016            _tags = tags;
    9991017        }
    10001018       
     
    10061024           
    10071025            _lease.setNumFailure(_lease.getNumFailure()+1);
     1026            if (_key != null && _tags != null && _leaseSet != null) {
     1027                SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_from.calculateHash());
     1028                if (skm != null)
     1029                    skm.failTags(_leaseSet.getEncryptionKey(), _key, _tags);
     1030            }
    10081031            dieFatal();
    10091032        }
  • router/java/src/net/i2p/router/tunnel/pool/TestJob.java

    r49ff3cfb r83588d9  
    44import java.util.Set;
    55
     6import net.i2p.crypto.SessionKeyManager;
    67import net.i2p.data.Certificate;
    78import net.i2p.data.SessionKey;
     
    2930    private TunnelInfo _replyTunnel;
    3031    private PooledTunnelCreatorConfig _otherTunnel;
     32    /** save this so we can tell the SKM to kill it if the test fails */
     33    private SessionTag _encryptTag;
    3134   
    3235    /** base to randomize the test delay on */
     
    130133        SessionKey encryptKey = getContext().keyGenerator().generateSessionKey();
    131134        SessionTag encryptTag = new SessionTag(true);
     135        _encryptTag = encryptTag;
    132136        SessionKey sentKey = new SessionKey();
    133137        Set sentTags = null;
     
    143147        Set encryptTags = new HashSet(1);
    144148        encryptTags.add(encryptTag);
    145         getContext().sessionKeyManager().tagsReceived(encryptKey, encryptTags);
     149        // Register the single tag with the appropriate SKM
     150        if (_cfg.isInbound() && !_pool.getSettings().isExploratory()) {
     151            SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_pool.getSettings().getDestination());
     152            if (skm != null)
     153                skm.tagsReceived(encryptKey, encryptTags);
     154        } else {
     155            getContext().sessionKeyManager().tagsReceived(encryptKey, encryptTags);
     156        }
    146157
    147158        if (_log.shouldLog(Log.DEBUG))
     
    308319            if (_log.shouldLog(Log.WARN))
    309320                _log.warn("Timeout: found? " + _found, getAddedBy());
    310             if (!_found)
     321            if (!_found) {
     322                // don't clog up the SKM with old one-tag tagsets
     323                if (_cfg.isInbound() && !_pool.getSettings().isExploratory()) {
     324                    SessionKeyManager skm = getContext().clientManager().getClientSessionKeyManager(_pool.getSettings().getDestination());
     325                    if (skm != null)
     326                        skm.consumeTag(_encryptTag);
     327                } else {
     328                    getContext().sessionKeyManager().consumeTag(_encryptTag);
     329                }
    311330                testFailed(getContext().clock().now() - _started);
     331            }
    312332        }
    313333       
  • router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java

    r49ff3cfb r83588d9  
    310310        //buildComplete();
    311311        if (cfg.getLength() > 1 &&
    312             !_context.router().gracefulShutdownInProgress()) {
     312            (!_context.router().gracefulShutdownInProgress()) &&
     313            !Boolean.valueOf(_context.getProperty("router.disableTunnelTesting")).booleanValue()) {
    313314            TunnelPool pool = cfg.getTunnelPool();
    314315            if (pool == null) {
Note: See TracChangeset for help on using the changeset viewer.