Changeset 00d4525


Ignore:
Timestamp:
Mar 23, 2019 1:39:47 PM (14 months ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
fea5bd4
Parents:
f17776e
Message:

Data: Initial work on b32 format for blinded leasesets (proposal 149, WIP)

Files:
1 added
7 edited

Legend:

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

    rf17776e r00d4525  
    12051205            } else if("i2p".equals(host)) {
    12061206                clientDest = null;
    1207             } else if(destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
     1207            } else if (destination.length() >= 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
    12081208                // use existing session to look up for efficiency
    12091209                verifySocketManager();
    12101210                I2PSession sess = sockMgr.getSession();
    1211                 if(!sess.isClosed()) {
    1212                     byte[] hData = Base32.decode(destination.substring(0, 52));
    1213                     if(hData != null) {
    1214                         if(_log.shouldLog(Log.INFO)) {
    1215                             _log.info("lookup in-session " + destination);
    1216                         }
    1217                         Hash hash = Hash.create(hData);
    1218                         clientDest = sess.lookupDest(hash, 20 * 1000);
     1211                if (!sess.isClosed()) {
     1212                    int len = destination.length();
     1213                    if (len == 60) {
     1214                        byte[] hData = Base32.decode(destination.substring(0, 52));
     1215                        if (hData != null) {
     1216                            if (_log.shouldInfo())
     1217                                _log.info("lookup b32 in-session " + destination);
     1218                            Hash hash = Hash.create(hData);
     1219                            clientDest = sess.lookupDest(hash, 20*1000);
     1220                        } else {
     1221                            clientDest = null;
     1222                        }
     1223                    } else if (len >= 64) {
     1224                        if (_log.shouldInfo())
     1225                            _log.info("lookup b33 in-session " + destination);
     1226                        clientDest = sess.lookupDest(destination, 20*1000);
     1227                    } else {
     1228                        // 61-63 chars, this won't work
     1229                        clientDest = _context.namingService().lookup(destination);
    12191230                    }
    12201231                } else {
  • core/java/src/net/i2p/client/naming/DummyNamingService.java

    rf17776e r00d4525  
    7070
    7171        // Try Base32 decoding
    72         if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p") &&
     72        if (hostname.length() >= BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p") &&
    7373                _context.getBooleanPropertyDefaultTrue(PROP_B32)) {
    7474            try {
    75                 d = LookupDest.lookupBase32Hash(_context, hostname.substring(0, BASE32_HASH_LENGTH));
     75                if (hostname.length() == BASE32_HASH_LENGTH + 8) {
     76                    // b32
     77                    d = LookupDest.lookupBase32Hash(_context, hostname.substring(0, BASE32_HASH_LENGTH));
     78                } else {
     79                    // b33
     80                    d = LookupDest.lookupHostname(_context, hostname);
     81                }
    7682                if (d != null) {
    7783                    putCache(hostname, d);
  • core/java/src/net/i2p/client/naming/LookupDest.java

    rf17776e r00d4525  
    6060
    6161    /** @param h 32 byte hash */
    62     static Destination lookupHash(I2PAppContext ctx, byte[] h) throws I2PSessionException {
     62    private static Destination lookupHash(I2PAppContext ctx, byte[] h) throws I2PSessionException {
    6363        Hash key = Hash.create(h);
    6464        Destination rv = null;
    6565        I2PClient client = new I2PSimpleClient();
     66        Properties opts = getOpts(ctx);
     67        I2PSession session = null;
     68        try {
     69            session = client.createSession(null, opts);
     70            session.connect();
     71            rv = session.lookupDest(key, DEFAULT_TIMEOUT);
     72        } finally {
     73            if (session != null)
     74                session.destroySession();
     75        }
     76        return rv;
     77    }
     78
     79    /**
     80     * Any hostname, but this is for long-format b32
     81     *
     82     * @param hostname a "b33" hostname, 64+ chars ending with ".b32.i2p"
     83     * @since 0.9.40
     84     */
     85    static Destination lookupHostname(I2PAppContext ctx, String hostname) throws I2PSessionException {
     86        Destination rv = null;
     87        I2PClient client = new I2PSimpleClient();
     88        Properties opts = getOpts(ctx);
     89        I2PSession session = null;
     90        try {
     91            session = client.createSession(null, opts);
     92            session.connect();
     93            rv = session.lookupDest(hostname, DEFAULT_TIMEOUT);
     94        } finally {
     95            if (session != null)
     96                session.destroySession();
     97        }
     98        return rv;
     99    }
     100
     101    /**
     102     * @since 0.9.40 split out from above
     103     */
     104    private static Properties getOpts(I2PAppContext ctx) {
    66105        Properties opts = new Properties();
    67106        if (!ctx.isRouterContext()) {
     
    82121                opts.put(PROP_PW, s);
    83122        }
    84         I2PSession session = null;
    85         try {
    86             session = client.createSession(null, opts);
    87             session.connect();
    88             rv = session.lookupDest(key, DEFAULT_TIMEOUT);
    89         } finally {
    90             if (session != null)
    91                 session.destroySession();
    92         }
    93         return rv;
     123        return opts;
    94124    }
    95125
  • core/java/src/net/i2p/client/naming/MetaNamingService.java

    rf17776e r00d4525  
    104104            return d;
    105105        // Base32 failed?
    106         if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p"))
     106        if (hostname.length() >= BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p"))
    107107            return null;
    108108
  • core/java/src/net/i2p/crypto/Blinding.java

    rf17776e r00d4525  
    55import java.util.Locale;
    66import java.util.TimeZone;
     7import java.util.zip.Checksum;
     8import java.util.zip.CRC32;
    79
    810import net.i2p.I2PAppContext;
     
    1012import net.i2p.crypto.eddsa.EdDSAPrivateKey;
    1113import net.i2p.crypto.eddsa.EdDSAPublicKey;
     14import net.i2p.data.Base32;
     15import net.i2p.data.BlindData;
    1216import net.i2p.data.DataHelper;
    1317import net.i2p.data.Destination;
     
    177181    }
    178182
     183    /**
     184     *  What's the default blinded type for a given unblinded type?
     185     *
     186     *  @return non-null
     187     *  @since 0.9.40
     188     */
     189    public static SigType getDefaultBlindedType(SigType unblindedType) {
     190        if (unblindedType == TYPE)
     191            return TYPER;
     192        return unblindedType;
     193    }
     194
     195    /**
     196     *  Decode a new-format b32 address.
     197     *  PRELIMINARY - Subject to change - see proposal 149
     198     *
     199     *  @param address ending with ".b32.i2p"
     200     *  @throws IllegalArgumentException on bad inputs
     201     *  @throws UnsupportedOperationException unless supported SigTypes
     202     *  @since 0.9.40
     203     */
     204    public static BlindData decode(I2PAppContext ctx, String address) throws RuntimeException {
     205        address = address.toLowerCase(Locale.US);
     206        if (!address.endsWith(".b32.i2p"))
     207            throw new IllegalArgumentException("Not a .b32.i2p address");
     208        byte[] b = Base32.decode(address.substring(0, address.length() - 8));
     209        if (b == null)
     210            throw new IllegalArgumentException("Bad base32 encoding");
     211        if (b.length < 35)
     212            throw new IllegalArgumentException("Not a new-format address");
     213        return decode(ctx, b);
     214    }
     215
     216    /**
     217     *  Decode a new-format b32 address.
     218     *  PRELIMINARY - Subject to change - see proposal 149
     219     *
     220     *  @param b 35+ bytes
     221     *  @throws IllegalArgumentException on bad inputs
     222     *  @throws UnsupportedOperationException unless supported SigTypes
     223     *  @since 0.9.40
     224     */
     225    public static BlindData decode(I2PAppContext ctx, byte[] b) throws RuntimeException {
     226        Checksum crc = new CRC32();
     227        crc.update(b, 3, b.length - 3);
     228        long check = crc.getValue();
     229        b[0] ^= (byte) check;
     230        b[1] ^= (byte) (check >> 8);
     231        b[2] ^= (byte) (check >> 16);
     232        int flag = b[0] & 0xff;
     233        if ((flag & 0xf8) != 0)
     234            throw new IllegalArgumentException("Corrupt b32 or unsupported options");
     235        if ((flag & 0x01) != 0)
     236            throw new IllegalArgumentException("Two byte sig types unsupported");
     237        if ((flag & 0x04) != 0)
     238            throw new IllegalArgumentException("Per-client auth unsupported");
     239        // TODO two-byte sigtypes
     240        int st1 = b[1] & 0xff;
     241        int st2 = b[2] & 0xff;
     242        SigType sigt1 = SigType.getByCode(st1);
     243        SigType sigt2 = SigType.getByCode(st2);
     244        if (sigt1 == null)
     245            throw new IllegalArgumentException("Unknown sig type " + st1);
     246        if (!sigt1.isAvailable())
     247            throw new IllegalArgumentException("Unavailable sig type " + sigt1);
     248        if (sigt2 == null)
     249            throw new IllegalArgumentException("Unknown blinded sig type " + st2);
     250        if (!sigt2.isAvailable())
     251            throw new IllegalArgumentException("Unavailable blinded sig type " + sigt2);
     252        // todo secret/privkey
     253        int spkLen = sigt1.getPubkeyLen();
     254        if (3 + spkLen > b.length)
     255            throw new IllegalArgumentException("b32 too short");
     256        byte[] spkData = new byte[spkLen];
     257        System.arraycopy(b, 3, spkData, 0, spkLen);
     258        SigningPublicKey spk = new SigningPublicKey(sigt1, spkData);
     259        String secret;
     260        if ((flag & 0x02) != 0) {
     261            if (4 + spkLen > b.length)
     262                throw new IllegalArgumentException("No secret data");
     263            int secLen = b[3 + spkLen] & 0xff;
     264            if (4 + spkLen + secLen != b.length)
     265                throw new IllegalArgumentException("Bad b32 length");
     266            secret = DataHelper.getUTF8(b, 4 + spkLen, secLen);
     267        } else if (3 + spkLen != b.length) {
     268            throw new IllegalArgumentException("b32 too long");
     269        } else {
     270            secret = null;
     271        }
     272        BlindData rv = new BlindData(ctx, spk, sigt2, secret);
     273        return rv;
     274    }
     275
     276    /**
     277     *  Encode a public key as a new-format b32 address.
     278     *  PRELIMINARY - Subject to change - see proposal 149
     279     *
     280     *  @param secret may be empty or null
     281     *  @return (56+ chars).b32.i2p
     282     *  @throws IllegalArgumentException on bad inputs
     283     *  @throws UnsupportedOperationException unless supported SigTypes
     284     *  @since 0.9.40
     285     */
     286    public static String encode(I2PAppContext ctx, SigningPublicKey key, String secret) throws RuntimeException {
     287        SigType type = key.getType();
     288        if (type != TYPE && type != TYPER)
     289            throw new UnsupportedOperationException();
     290        byte sdata[] = (secret != null) ? DataHelper.getUTF8(secret) : null;
     291        int slen = (secret != null) ? 1 + sdata.length : 0;
     292        if (slen > 256)
     293            throw new IllegalArgumentException("secret too long");
     294        byte[] d = key.getData();
     295        byte[] b = new byte[d.length + slen + 3];
     296        System.arraycopy(d, 0, b, 3, d.length);
     297        if (slen > 0) {
     298            b[3 + d.length] = (byte) sdata.length;
     299            System.arraycopy(sdata, 0, b, 4 + d.length, sdata.length);
     300        }
     301        Checksum crc = new CRC32();
     302        crc.update(b, 3, b.length - 3);
     303        long check = crc.getValue();
     304        // TODO two-byte sigtypes
     305        if (slen > 0)
     306            b[0] = 0x02;
     307        b[1] = (byte) (type.getCode() & 0xff);
     308        b[2] = (byte) (TYPER.getCode() & 0xff);
     309        b[0] ^= (byte) check;
     310        b[1] ^= (byte) (check >> 8);
     311        b[2] ^= (byte) (check >> 16);
     312        // todo privkey
     313        return Base32.encode(b) + ".b32.i2p";
     314    }
     315
    179316/******
    180317    public static void main(String args[]) throws Exception {
     
    182319        SigningPublicKey pub = (SigningPublicKey) keys[0];
    183320        SigningPrivateKey priv = (SigningPrivateKey) keys[1];
     321        I2PAppContext ctx = I2PAppContext.getGlobalContext();
     322        //String b32 = encode(ctx, pub, null);
     323        String b32 = encode(ctx, pub, "foobarbaz");
     324        System.out.println("pub b32 is " + b32);
     325        BlindData bd = decode(ctx, b32);
     326        if (bd.getBlindedPubKey().equals(pub))
     327            System.out.println("B32 test failed");
     328        else
     329            System.out.println("B32 test passed");
    184330        byte[] b = new byte[64];
    185         net.i2p.I2PAppContext.getGlobalContext().random().nextBytes(b);
     331        ctx.random().nextBytes(b);
    186332        b = EdDSABlinding.reduce(b);
    187333        SigningPrivateKey alpha = new SigningPrivateKey(TYPER, b);
  • core/java/src/net/i2p/data/PrivateKeyFile.java

    rf17776e r00d4525  
    2121import gnu.getopt.Getopt;
    2222
     23import net.i2p.I2PAppContext;
    2324import net.i2p.I2PException;
    2425import net.i2p.client.I2PClient;
     
    2728import net.i2p.client.I2PSessionException;
    2829import net.i2p.client.naming.HostTxtEntry;
     30import net.i2p.crypto.Blinding;
    2931import net.i2p.crypto.DSAEngine;
    3032import net.i2p.crypto.KeyGenerator;
     
    756758        s.append("\nB32: ");
    757759        s.append(this.dest != null ? this.dest.toBase32() : "null");
     760        if (dest != null) {
     761            SigningPublicKey spk = dest.getSigningPublicKey();
     762            SigType type = spk.getType();
     763            if (type == SigType.EdDSA_SHA512_Ed25519 ||
     764                type == SigType.RedDSA_SHA512_Ed25519) {
     765                I2PAppContext ctx = I2PAppContext.getGlobalContext();
     766                s.append("\nBlinded B32: ").append(Blinding.encode(ctx, spk, null));
     767            }
     768        }
    758769        s.append("\nContains: ");
    759770        s.append(this.dest);
  • router/java/src/net/i2p/router/client/LookupDestJob.java

    rf17776e r00d4525  
    77import java.util.Locale;
    88
     9import net.i2p.crypto.Blinding;
    910import net.i2p.data.Base32;
     11import net.i2p.data.BlindData;
    1012import net.i2p.data.Destination;
    1113import net.i2p.data.Hash;
     
    1820import net.i2p.router.JobImpl;
    1921import net.i2p.router.RouterContext;
     22import net.i2p.util.Log;
    2023
    2124/**
     
    2427 */
    2528class LookupDestJob extends JobImpl {
     29    private final Log _log;
    2630    private final ClientConnectionRunner _runner;
    2731    private final long _reqID;
     
    5357                         Hash fromLocalDest) {
    5458        super(context);
     59        _log = context.logManager().getLog(LookupDestJob.class);
    5560        if ((h == null && name == null) ||
    5661            (h != null && name != null) ||
    5762            (reqID >= 0 && sessID == null) ||
    58             (reqID < 0 && name != null))
     63            (reqID < 0 && name != null)) {
     64            _log.warn("bad args");
    5965            throw new IllegalArgumentException();
     66        }
    6067        _runner = runner;
    6168        _reqID = reqID;
     
    6370        _sessID = sessID;
    6471        _fromLocalDest = fromLocalDest;
    65         if (name != null && name.length() == 60) {
     72        if (name != null && name.length() >= 60) {
    6673            // convert a b32 lookup to a hash lookup
    6774            String nlc = name.toLowerCase(Locale.US);
    6875            if (nlc.endsWith(".b32.i2p")) {
    69                 byte[] b = Base32.decode(nlc.substring(0, 52));
    70                 if (b != null && b.length == Hash.HASH_LENGTH) {
    71                     h = Hash.create(b);
    72                     name = null;
     76                byte[] b = Base32.decode(nlc.substring(0, nlc.length() - 8));
     77                if (b != null) {
     78                    if (b.length == Hash.HASH_LENGTH) {
     79                        h = Hash.create(b);
     80                        if (_log.shouldDebug())
     81                            _log.debug("Converting name lookup " + name + " to " + h);
     82                        name = null;
     83                    } else if (b.length >= 35) {
     84                        // encrypted LS2
     85                        try {
     86                            BlindData bd = Blinding.decode(context, b);
     87                            h = bd.getBlindedHash();
     88                            if (_log.shouldDebug())
     89                                _log.debug("Converting name lookup " + name + " to blinded " + h);
     90                            name = null;
     91                        } catch (RuntimeException re) {
     92                            if (_log.shouldWarn())
     93                                _log.debug("Failed blinding conversion of " + name, re);
     94                            // lookup as a name, which will probably fail
     95                        }
     96                    }
    7397                }
    7498            }
     
    87111            // inline, ignore timeout
    88112            Destination d = getContext().namingService().lookup(_name);
    89             if (d != null)
     113            if (d != null) {
     114                if (_log.shouldDebug())
     115                    _log.debug("Found name lookup " + _name + " to " + d);
    90116                returnDest(d);
    91             else
     117            } else {
     118                if (_log.shouldDebug())
     119                    _log.debug("Failed name lookup " + _name);
    92120                returnFail();
     121            }
    93122        } else {
    94123            DoneJob done = new DoneJob(getContext());
     
    104133        public void runJob() {
    105134            Destination dest = getContext().netDb().lookupDestinationLocally(_hash);
    106             if (dest != null)
     135            if (dest != null) {
     136                if (_log.shouldDebug())
     137                    _log.debug("Found hash lookup " + _hash + " to " + dest);
    107138                returnDest(dest);
    108             else
     139            } else {
     140                if (_log.shouldDebug())
     141                    _log.debug("Failed hash lookup " + _hash);
    109142                returnFail();
     143            }
    110144        }
    111145    }
Note: See TracChangeset for help on using the changeset viewer.