Changeset 82eea0a


Ignore:
Timestamp:
Mar 27, 2019 12:51:10 PM (17 months ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
ea127d3
Parents:
14492d72
Message:

NetDB: Cache blinding data for lookups and decryption (proposal #123)

Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java

    r14492d72 r82eea0a  
    12481248                } else if(ahelperPresent) {
    12491249                    header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
    1250                 } else if(destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
     1250                } else if(destination.length() >= 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
    12511251                    header = getErrorPage("nols", ERR_DESTINATION_UNKNOWN);
    12521252                    extraMessage = _t("Destination lease set not found");
  • core/java/src/net/i2p/data/BlindData.java

    r14492d72 r82eea0a  
    2626
    2727    /**
     28     *  @param secret may be null or zero-length
    2829     *  @throws IllegalArgumentException on various errors
    2930     */
     
    3435
    3536    /**
     37     *  @param secret may be null or zero-length
    3638     *  @throws IllegalArgumentException on various errors
    3739     */
     
    4850
    4951    /**
    50      *  @return The blinded key for the current day
     52     *  @return The unblinded SPK, non-null
     53     */
     54    public SigningPublicKey getUnblindedPubKey() {
     55        return _clearSPK;
     56    }
     57
     58    /**
     59     *  @return The blinded key for the current day, non-null
    5160     */
    5261    public synchronized SigningPublicKey getBlindedPubKey() {
    5362        calculate();
    5463        return _blindSPK;
     64    }
     65
     66    /**
     67     *  @return The hash of the destination if known, or null
     68     */
     69    public synchronized Hash getDestHash() {
     70        return _dest != null ? _dest.getHash() : null;
    5571    }
    5672
     
    128144        _blindHash = _context.sha().calculateHash(hashData);
    129145    }
     146   
     147    @Override
     148    public synchronized String toString() {
     149        calculate();
     150        StringBuilder buf = new StringBuilder(256);
     151        buf.append("[BlindData: ");
     152        buf.append("\n\tSigningPublicKey: ").append(_clearSPK);
     153        buf.append("\n\tAlpha           : ").append(_alpha);
     154        buf.append("\n\tBlindedPublicKey: ").append(_blindSPK);
     155        buf.append("\n\tBlinded Hash    : ").append(_blindHash);
     156        buf.append("\n\tSecret: ").append(_secret);
     157        if (_dest != null)
     158            buf.append("\n\tDestination: ").append(_dest);
     159        if (_dest != null)
     160            buf.append("\n\tDestination: unknown");
     161        buf.append(']');
     162        return buf.toString();
     163    }
    130164}
  • core/java/src/net/i2p/data/EncryptedLeaseSet.java

    r14492d72 r82eea0a  
    3434    private Hash __calculatedHash;
    3535    private SigningPrivateKey _alpha;
     36    // to decrypt with if we don't have full dest
     37    private SigningPublicKey _unblindedSPK;
    3638    private String _secret;
    3739    private final Log _log;
     
    121123        }
    122124        SigningPublicKey spk = dest.getSigningPublicKey();
     125        setSigningKey(spk);
     126    }
     127
     128    /**
     129     * Overridden to set the blinded key
     130     *
     131     * @param spk unblinded key non-null, must be EdDSA_SHA512_Ed25519 or RedDSA_SHA512_Ed25519
     132     * @throws IllegalStateException if already signed
     133     * @throws IllegalArgumentException if not EdDSA
     134     * @since 0.9.40
     135     */
     136    @Override
     137    public void setSigningKey(SigningPublicKey spk) {
     138        // TODO already-set checks
    123139        SigType type = spk.getType();
    124140        if (type != SigType.EdDSA_SHA512_Ed25519 &&
    125141            type != SigType.RedDSA_SHA512_Ed25519)
    126142            throw new IllegalArgumentException();
    127         SigningPublicKey bpk = blind();
     143        if (_unblindedSPK != null) {
     144            if (!_unblindedSPK.equals(spk))
     145                throw new IllegalArgumentException("unblinded pubkey mismatch");
     146        } else {
     147            _unblindedSPK = spk;
     148        }
     149        SigningPublicKey bpk = blind(spk);
    128150        if (_signingKey == null)
    129151            _signingKey = bpk;
     
    140162     * @since 0.9.39
    141163     */
    142     private SigningPublicKey blind() {
    143         SigningPublicKey spk = _destination.getSigningPublicKey();
     164    private SigningPublicKey blind(SigningPublicKey spk) {
    144165        I2PAppContext ctx = I2PAppContext.getGlobalContext();
    145166        if (_published <= 0)
    146             _alpha = Blinding.generateAlpha(ctx, _destination.getSigningPublicKey(), _secret);
     167            _alpha = Blinding.generateAlpha(ctx, spk, _secret);
    147168        else
    148             _alpha = Blinding.generateAlpha(ctx, _destination.getSigningPublicKey(), _secret, _published);
     169            _alpha = Blinding.generateAlpha(ctx, spk, _secret, _published);
    149170        SigningPublicKey rv = Blinding.blind(spk, _alpha);
    150171        if (_log.shouldDebug())
     
    477498     */
    478499    private byte[] getSubcredential(I2PAppContext ctx) {
    479         if (_destination == null)
    480             throw new IllegalStateException("no known destination to decrypt with");
    481         SigningPublicKey destspk = _destination.getSigningPublicKey();
    482         int spklen = destspk.length();
     500        if (_unblindedSPK == null)
     501            throw new IllegalStateException("no known SPK to decrypt with");
     502        int spklen = _unblindedSPK.length();
    483503        byte[] in = new byte[spklen + 4];
    484504        // SHA256("credential" || spk || sigtypein || sigtypeout)
    485         System.arraycopy(destspk.getData(), 0, in, 0, spklen);
    486         DataHelper.toLong(in, spklen, 2, destspk.getType().getCode());
     505        System.arraycopy(_unblindedSPK.getData(), 0, in, 0, spklen);
     506        DataHelper.toLong(in, spklen, 2, _unblindedSPK.getType().getCode());
    487507        DataHelper.toLong(in, spklen + 2, 2, SigType.RedDSA_SHA512_Ed25519.getCode());
    488508        byte[] credential = hash(ctx, CREDENTIAL, in);
     
    573593        }
    574594        _log.info("ELS2 outer sig verify success");
    575         if (_destination == null) {
    576             _log.warn("ELS2 no dest to decrypt with");
     595        if (_unblindedSPK == null) {
     596            if (_log.shouldWarn())
     597                _log.warn("ELS2 no dest/SPK to decrypt with", new Exception("I did it"));
    577598            return true;
    578599        }
  • history.txt

    r14492d72 r82eea0a  
     12019-03-27 zzz
     2 * NetDB: Cache blinding data for lookups and decryption (proposal #123)
     3
     42019-03-23 zzz
     5 * Data: Preliminary work on new b32 format (proposal #149)
     6 * SelfSignedGenerator:
     7   - Fix generation with Ed25519ph keys (ticket #2465)
     8   - Increase serial number from 63 to 71 bits
     9 * SusiDNS: Add import feature (ticket #2447)
     10
    1112019-03-22 zzz
    212 * i2ptunnel: Escape {} in URLs (ticket #2130)
  • router/java/src/net/i2p/router/NetworkDatabaseFacade.java

    r14492d72 r82eea0a  
    1414import java.util.Set;
    1515
     16import net.i2p.data.BlindData;
    1617import net.i2p.data.DatabaseEntry;
    1718import net.i2p.data.Destination;
    1819import net.i2p.data.Hash;
    1920import net.i2p.data.LeaseSet;
     21import net.i2p.data.SigningPublicKey;
    2022import net.i2p.data.router.RouterInfo;
    2123import net.i2p.router.networkdb.reseed.ReseedChecker;
     
    162164     */
    163165    public boolean isNegativeCachedForever(Hash key) { return false; }
     166   
     167    /**
     168     *  @param spk unblinded key
     169     *  @return BlindData or null
     170     *  @since 0.9.40
     171     */
     172    public BlindData getBlindData(SigningPublicKey spk) {
     173        return null;
     174    }
     175   
     176    /**
     177     *  @param bd new BlindData to put in the cache
     178     *  @since 0.9.40
     179     */
     180    public void setBlindData(BlindData bd) {}
    164181}
  • router/java/src/net/i2p/router/RouterVersion.java

    r14492d72 r82eea0a  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 1;
     21    public final static long BUILD = 2;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/client/LookupDestJob.java

    r14492d72 r82eea0a  
    1010import net.i2p.data.Base32;
    1111import net.i2p.data.BlindData;
     12import net.i2p.data.DatabaseEntry;
    1213import net.i2p.data.Destination;
     14import net.i2p.data.EncryptedLeaseSet;
    1315import net.i2p.data.Hash;
    1416import net.i2p.data.LeaseSet;
     17import net.i2p.data.SigningPublicKey;
    1518import net.i2p.data.i2cp.DestReplyMessage;
    1619import net.i2p.data.i2cp.HostReplyMessage;
     
    3538    private final SessionId _sessID;
    3639    private final Hash _fromLocalDest;
     40    private final BlindData _blindData;
    3741
    3842    private static final long DEFAULT_TIMEOUT = 15*1000;
     
    7074        _sessID = sessID;
    7175        _fromLocalDest = fromLocalDest;
     76        BlindData bd = null;
    7277        if (name != null && name.length() >= 60) {
    7378            // convert a b32 lookup to a hash lookup
     
    8388                    } else if (b.length >= 35) {
    8489                        // encrypted LS2
     90                        // lookup the blinded hash
    8591                        try {
    86                             BlindData bd = Blinding.decode(context, b);
     92                            bd = Blinding.decode(context, b);
     93                            SigningPublicKey spk = bd.getUnblindedPubKey();
     94                            BlindData bd2 = getContext().netDb().getBlindData(spk);
     95                            if (bd2 != null) {
     96                                bd = bd2;
     97                            } else {
     98                                getContext().netDb().setBlindData(bd);
     99                            }
    87100                            h = bd.getBlindedHash();
    88101                            if (_log.shouldDebug())
     
    100113        _hash = h;
    101114        _name = name;
     115        _blindData = bd;
    102116    }
    103117   
     
    108122
    109123    public void runJob() {
     124        if (_blindData != null) {
     125            Destination d = _blindData.getDestination();
     126            if (d != null) {
     127                if (_log.shouldDebug())
     128                    _log.debug("Found cached b33 lookup " + _name + " to " + d);
     129                returnDest(d);
     130                return;
     131            }
     132        }
    110133        if (_name != null) {
    111134            // inline, ignore timeout
     
    122145        } else {
    123146            DoneJob done = new DoneJob(getContext());
     147            // TODO tell router this is an encrypted lookup, skip 38 or earlier ffs?
    124148            getContext().netDb().lookupDestination(_hash, done, _timeout, _fromLocalDest);
    125149        }
     
    133157        public void runJob() {
    134158            Destination dest = getContext().netDb().lookupDestinationLocally(_hash);
     159            if (dest == null && _blindData != null) {
     160                // TODO store and lookup original hash instead
     161                LeaseSet ls = getContext().netDb().lookupLeaseSetLocally(_hash);
     162                if (ls != null && ls.getType() == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
     163                    // already decrypted
     164                    EncryptedLeaseSet encls = (EncryptedLeaseSet) ls;
     165                    LeaseSet decls = encls.getDecryptedLeaseSet();
     166                    if (decls != null) {
     167                        dest = decls.getDestination();
     168                    }
     169                }
     170            }
    135171            if (dest != null) {
    136172                if (_log.shouldDebug())
  • router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java

    r14492d72 r82eea0a  
    2222import net.i2p.crypto.SigAlgo;
    2323import net.i2p.crypto.SigType;
     24import net.i2p.data.BlindData;
    2425import net.i2p.data.Certificate;
    2526import net.i2p.data.DatabaseEntry;
     
    2728import net.i2p.data.DataHelper;
    2829import net.i2p.data.Destination;
     30import net.i2p.data.EncryptedLeaseSet;
    2931import net.i2p.data.Hash;
    3032import net.i2p.data.KeyCertificate;
    3133import net.i2p.data.LeaseSet;
    3234import net.i2p.data.LeaseSet2;
     35import net.i2p.data.SigningPublicKey;
    3336import net.i2p.data.i2np.DatabaseLookupMessage;
    3437import net.i2p.data.i2np.DatabaseStoreMessage;
     
    7477    private NegativeLookupCache _negativeCache;
    7578    protected final int _networkID;
     79    private final BlindCache _blindCache;
    7680
    7781    /**
     
    172176        _activeRequests = new HashMap<Hash, SearchJob>(8);
    173177        _reseedChecker = new ReseedChecker(context);
     178        _blindCache = new BlindCache(context);
    174179        context.statManager().createRateStat("netDb.lookupDeferred", "how many lookups are deferred?", "NetworkDatabase", new long[] { 60*60*1000 });
    175180        context.statManager().createRateStat("netDb.exploreKeySet", "how many keys are queued for exploration?", "NetworkDatabase", new long[] { 60*60*1000 });
     
    247252        _exploreKeys.clear(); // hope this doesn't cause an explosion, it shouldn't.
    248253        // _exploreKeys = null;
    249         _negativeCache.clear();
     254        if (_negativeCache != null)
     255            _negativeCache.clear();
     256        _blindCache.shutdown();
    250257    }
    251258   
     
    258265        _ds.restart();
    259266        _exploreKeys.clear();
     267        _blindCache.startup();
    260268
    261269        _initialized = true;
     
    288296        _dbDir = dbDir;
    289297        _negativeCache = new NegativeLookupCache(_context);
     298        _blindCache.startup();
    290299       
    291300        createHandlers();
     
    465474   
    466475    /**
     476     *  @param spk unblinded key
     477     *  @return BlindData or null
     478     *  @since 0.9.40
     479     */
     480    @Override
     481    public BlindData getBlindData(SigningPublicKey spk) {
     482        return _blindCache.getData(spk);
     483    }
     484   
     485    /**
     486     *  @param bd new BlindData to put in the cache
     487     *  @since 0.9.40
     488     */
     489    @Override
     490    public void setBlindData(BlindData bd) {
     491        if (_log.shouldWarn())
     492            _log.warn("Adding to blind cache: " + bd);
     493        _blindCache.addToCache(bd);
     494    }
     495   
     496    /**
    467497     *  @return RouterInfo, LeaseSet, or null, validated
    468498     *  @since 0.8.3
     
    477507        if (DatabaseEntry.isLeaseSet(type)) {
    478508            LeaseSet ls = (LeaseSet)rv;
    479             if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR))
     509            if (ls.isCurrent(Router.CLOCK_FUDGE_FACTOR)) {
    480510                return rv;
    481             else
     511            } else {
     512                key = _blindCache.getHash(key);
    482513                fail(key);
     514            }
    483515        } else if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
    484516            try {
     
    534566            //if (_log.shouldLog(Log.DEBUG))
    535567            //    _log.debug("leaseSet not found locally, running search");
     568            key = _blindCache.getHash(key);
    536569            search(key, onFindJob, onFailedLookupJob, timeoutMs, true, fromLocalDest);
    537570        }
     
    550583    public void lookupLeaseSetRemotely(Hash key, Hash fromLocalDest) {
    551584        if (!_initialized) return;
     585        key = _blindCache.getHash(key);
    552586        search(key, null, null, 20*1000, true, fromLocalDest);
    553587    }
     
    565599                    return ls;
    566600                } else {
     601                    key = _blindCache.getHash(key);
    567602                    fail(key);
    568603                    // this was an interesting key, so either refetch it or simply explore with it
     
    600635            _context.jobQueue().addJob(onFinishedJob);
    601636        } else {
     637            key = _blindCache.getHash(key);
    602638            search(key, onFinishedJob, onFinishedJob, timeoutMs, true, fromLocalDest);
    603639        }
     
    893929            throw new IllegalArgumentException("LS Hash collision");
    894930
     931        EncryptedLeaseSet encls = null;
     932        if (leaseSet.getType() == DatabaseEntry.KEY_TYPE_ENCRYPTED_LS2) {
     933            // set dest or key before validate() calls verifySignature() which
     934            // will do the decryption
     935            BlindData bd = _blindCache.getReverseData(leaseSet.getSigningKey());
     936            if (bd != null) {
     937                if (_log.shouldWarn())
     938                    _log.warn("Found blind data for encls: " + bd);
     939                encls = (EncryptedLeaseSet) leaseSet;
     940                Destination dest = bd.getDestination();
     941                if (dest != null) {
     942                    encls.setDestination(dest);
     943                } else {
     944                    encls.setSigningKey(bd.getUnblindedPubKey());
     945                }
     946            } else {
     947                if (_log.shouldWarn())
     948                    _log.warn("No blind data found for encls: " + encls);
     949            }
     950        }
     951
     952
    895953        String err = validate(key, leaseSet);
    896954        if (err != null)
     
    899957        _ds.put(key, leaseSet);
    900958       
     959        if (encls != null) {
     960            // we now have decrypted it, store it as well
     961            LeaseSet decls = encls.getDecryptedLeaseSet();
     962            if (decls != null) {
     963                if (_log.shouldWarn())
     964                    _log.warn("Successfully decrypted encls: " + decls);
     965                // recursion
     966                Destination dest = decls.getDestination();
     967                store(dest.getHash(), decls);
     968                _blindCache.setBlinded(dest);
     969            }
     970        }
     971
    901972        // Iterate through the old failure / success count, copying over the old
    902973        // values (if any tunnels overlap between leaseSets).  no need to be
Note: See TracChangeset for help on using the changeset viewer.