Search in sources :

Example 11 with Signature

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

the class KeyGenerator method testSig.

private static void testSig(SigType type, int runs) throws GeneralSecurityException {
    byte[] src = new byte[512];
    double gtime = 0;
    long stime = 0;
    long vtime = 0;
    SimpleDataStructure[] keys = null;
    long st = System.nanoTime();
    // RSA super slow, limit to 5
    int genruns = (type.getBaseAlgorithm() == SigAlgo.RSA) ? Math.min(runs, 5) : runs;
    for (int i = 0; i < genruns; i++) {
        keys = KeyGenerator.getInstance().generateSigningKeys(type);
    }
    long en = System.nanoTime();
    gtime = ((en - st) / (1000 * 1000d)) / genruns;
    System.out.println(type + " key gen " + genruns + " times: " + gtime + " ms each");
    SigningPublicKey pubkey = (SigningPublicKey) keys[0];
    SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
    SigningPublicKey pubkey2 = getSigningPublicKey(privkey);
    if (pubkey.equals(pubkey2))
        System.out.println(type + " private-to-public test PASSED");
    else
        System.out.println(type + " private-to-public test FAILED");
    // System.out.println("privkey " + keys[1]);
    MessageDigest md = type.getDigestInstance();
    for (int i = 0; i < runs; i++) {
        RandomSource.getInstance().nextBytes(src);
        md.update(src);
        byte[] sha = md.digest();
        SimpleDataStructure hash = type.getHashInstance();
        hash.setData(sha);
        long start = System.nanoTime();
        Signature sig = DSAEngine.getInstance().sign(src, privkey);
        Signature sig2 = DSAEngine.getInstance().sign(hash, privkey);
        if (sig == null)
            throw new GeneralSecurityException("signature generation failed");
        if (sig2 == null)
            throw new GeneralSecurityException("signature generation (H) failed");
        long mid = System.nanoTime();
        boolean ok = DSAEngine.getInstance().verifySignature(sig, src, pubkey);
        boolean ok2 = DSAEngine.getInstance().verifySignature(sig2, hash, pubkey);
        long end = System.nanoTime();
        stime += mid - start;
        vtime += end - mid;
        if (!ok)
            throw new GeneralSecurityException(type + " V(S(data)) fail");
        if (!ok2)
            throw new GeneralSecurityException(type + " V(S(H(data))) fail");
    }
    stime /= 1000 * 1000;
    vtime /= 1000 * 1000;
    System.out.println(type + " sign/verify " + runs + " times: " + (vtime + stime) + " ms = " + (((double) stime) / runs) + " each sign, " + (((double) vtime) / runs) + " each verify, " + (((double) (stime + vtime)) / runs) + " s+v");
}
Also used : SigningPrivateKey(net.i2p.data.SigningPrivateKey) SigningPublicKey(net.i2p.data.SigningPublicKey) Signature(net.i2p.data.Signature) GeneralSecurityException(java.security.GeneralSecurityException) MessageDigest(java.security.MessageDigest) SimpleDataStructure(net.i2p.data.SimpleDataStructure) ECPoint(java.security.spec.ECPoint)

Example 12 with Signature

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

the class DSATest method testMultiple.

public void testMultiple() {
    for (int i = 0; i < 25; i++) {
        byte[] message = new byte[256];
        _context.random().nextBytes(message);
        Object[] keys = KeyGenerator.getInstance().generateSigningKeypair();
        SigningPublicKey pubkey = (SigningPublicKey) keys[0];
        SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
        Signature s = DSAEngine.getInstance().sign(message, privkey);
        Signature s1 = DSAEngine.getInstance().sign(new ByteArrayInputStream(message), privkey);
        assertTrue(DSAEngine.getInstance().verifySignature(s, message, pubkey));
        assertTrue(DSAEngine.getInstance().verifySignature(s1, new ByteArrayInputStream(message), pubkey));
        assertTrue(DSAEngine.getInstance().verifySignature(s1, message, pubkey));
        assertTrue(DSAEngine.getInstance().verifySignature(s, new ByteArrayInputStream(message), pubkey));
    }
}
Also used : SigningPrivateKey(net.i2p.data.SigningPrivateKey) SigningPublicKey(net.i2p.data.SigningPublicKey) ByteArrayInputStream(java.io.ByteArrayInputStream) Signature(net.i2p.data.Signature)

Example 13 with Signature

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

the class EstablishState method sendInboundConfirm.

/**
 *  We are Bob. Send message #4 to Alice.
 *
 *  State must be VERIFIED.
 *  Caller must synch.
 */
private void sendInboundConfirm(RouterIdentity alice, long tsA) {
    // send Alice E(S(X+Y+Alice.identHash+tsA+tsB), sk, prev)
    byte[] toSign = new byte[XY_SIZE + XY_SIZE + 32 + 4 + 4];
    int off = 0;
    System.arraycopy(_X, 0, toSign, off, XY_SIZE);
    off += XY_SIZE;
    System.arraycopy(_Y, 0, toSign, off, XY_SIZE);
    off += XY_SIZE;
    Hash h = alice.calculateHash();
    System.arraycopy(h.getData(), 0, toSign, off, 32);
    off += 32;
    DataHelper.toLong(toSign, off, 4, tsA);
    off += 4;
    DataHelper.toLong(toSign, off, 4, _tsB);
    off += 4;
    // handle variable signature size
    Signature sig = _context.dsa().sign(toSign, _context.keyManager().getSigningPrivateKey());
    int siglen = sig.length();
    int rem = siglen % AES_SIZE;
    int padding;
    if (rem > 0)
        padding = AES_SIZE - rem;
    else
        padding = 0;
    byte[] preSig = new byte[siglen + padding];
    System.arraycopy(sig.getData(), 0, preSig, 0, siglen);
    if (padding > 0)
        _context.random().nextBytes(preSig, siglen, padding);
    _e_bobSig = new byte[preSig.length];
    _context.aes().encrypt(preSig, 0, _e_bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, HXY_TSB_PAD_SIZE - AES_SIZE, _e_bobSig.length);
    if (_log.shouldLog(Log.DEBUG))
        _log.debug(prefix() + "Sending encrypted inbound confirmation");
    _transport.getPumper().wantsWrite(_con, _e_bobSig);
}
Also used : Signature(net.i2p.data.Signature) Hash(net.i2p.data.Hash)

Example 14 with Signature

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

the class EstablishState method receiveOutbound.

/**
 *  We are Alice, so receive these bytes as part of an outbound connection.
 *  This method receives messages 2 and 4, and sends message 3.
 *
 *  All data must be copied out of the buffer as Reader.processRead()
 *  will return it to the pool.
 *
 *  Caller must synch.
 *
 *  FIXME none of the _state comparisons use _stateLock, but whole thing
 *  is synchronized, should be OK. See isComplete()
 */
private void receiveOutbound(ByteBuffer src) {
    // Read in Y, which is the first part of message #2
    while (_state == State.OB_SENT_X && src.hasRemaining()) {
        byte c = src.get();
        _Y[_received++] = c;
        // if (_log.shouldLog(Log.DEBUG)) _log.debug("recv x" + (int)c + " received=" + _received);
        if (_received >= XY_SIZE) {
            try {
                _dh.setPeerPublicValue(_Y);
                // force the calc
                _dh.getSessionKey();
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug(prefix() + "DH session key calculated (" + _dh.getSessionKey().toBase64() + ")");
                changeState(State.OB_GOT_Y);
            } catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
                _context.statManager().addRateData("ntcp.invalidDH", 1);
                fail("Invalid X", e);
                return;
            }
        }
    }
    // Read in the rest of message #2
    while (_state == State.OB_GOT_Y && src.hasRemaining()) {
        int i = _received - XY_SIZE;
        _received++;
        byte c = src.get();
        _e_hXY_tsB[i] = c;
        // _log.debug(prefix() + "recv _e_hXY_tsB " + (int)c + " received=" + _received);
        if (i + 1 >= HXY_TSB_PAD_SIZE) {
            if (_log.shouldLog(Log.DEBUG))
                _log.debug(prefix() + "received _e_hXY_tsB fully");
            byte[] hXY_tsB = new byte[HXY_TSB_PAD_SIZE];
            _context.aes().decrypt(_e_hXY_tsB, 0, hXY_tsB, 0, _dh.getSessionKey(), _Y, XY_SIZE - AES_SIZE, HXY_TSB_PAD_SIZE);
            byte[] XY = new byte[XY_SIZE + XY_SIZE];
            System.arraycopy(_X, 0, XY, 0, XY_SIZE);
            System.arraycopy(_Y, 0, XY, XY_SIZE, XY_SIZE);
            byte[] h = SimpleByteCache.acquire(HXY_SIZE);
            _context.sha().calculateHash(XY, 0, XY_SIZE + XY_SIZE, h, 0);
            // _log.debug(prefix() + "h(XY)=" + h.toBase64());
            if (!DataHelper.eq(h, 0, hXY_tsB, 0, HXY_SIZE)) {
                SimpleByteCache.release(h);
                _context.statManager().addRateData("ntcp.invalidHXY", 1);
                fail("Invalid H(X+Y) - mitm attack attempted?");
                return;
            }
            SimpleByteCache.release(h);
            changeState(State.OB_GOT_HXY);
            // their (Bob's) timestamp in seconds
            _tsB = DataHelper.fromLong(hXY_tsB, HXY_SIZE, 4);
            long now = _context.clock().now();
            // rtt from sending #1 to receiving #2
            long rtt = now - _con.getCreated();
            // our (Alice's) timestamp in seconds
            _tsA = (now + 500) / 1000;
            _peerSkew = (now - (_tsB * 1000) - (rtt / 2) + 500) / 1000;
            if (_log.shouldLog(Log.DEBUG))
                _log.debug(prefix() + "h(X+Y) is correct, skew = " + _peerSkew);
            // the skew is not authenticated yet, but it is certainly fatal to
            // the establishment, so fail hard if appropriate
            long diff = 1000 * Math.abs(_peerSkew);
            if (!_context.clock().getUpdatedSuccessfully()) {
                // Adjust the clock one time in desperation
                // We are Alice, he is Bob, adjust to match Bob
                _context.clock().setOffset(1000 * (0 - _peerSkew), true);
                _peerSkew = 0;
                if (diff != 0)
                    _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff));
            } else if (diff >= Router.CLOCK_FUDGE_FACTOR) {
                _context.statManager().addRateData("ntcp.invalidOutboundSkew", diff);
                _transport.markReachable(_con.getRemotePeer().calculateHash(), false);
                // Only banlist if we know what time it is
                _context.banlist().banlistRouter(DataHelper.formatDuration(diff), _con.getRemotePeer().calculateHash(), _x("Excessive clock skew: {0}"));
                _transport.setLastBadSkew(_peerSkew);
                fail("Clocks too skewed (" + diff + " ms)", null, true);
                return;
            } else if (_log.shouldLog(Log.DEBUG)) {
                _log.debug(prefix() + "Clock skew: " + diff + " ms");
            }
            // now prepare and send our response
            // send E(#+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB), sk, hX_xor_Bob.identHash[16:31])
            // +12;
            int sigSize = XY_SIZE + XY_SIZE + HXY_SIZE + 4 + 4;
            byte[] preSign = new byte[sigSize];
            System.arraycopy(_X, 0, preSign, 0, XY_SIZE);
            System.arraycopy(_Y, 0, preSign, XY_SIZE, XY_SIZE);
            System.arraycopy(_con.getRemotePeer().calculateHash().getData(), 0, preSign, XY_SIZE + XY_SIZE, HXY_SIZE);
            DataHelper.toLong(preSign, XY_SIZE + XY_SIZE + HXY_SIZE, 4, _tsA);
            DataHelper.toLong(preSign, XY_SIZE + XY_SIZE + HXY_SIZE + 4, 4, _tsB);
            // hXY_tsB has 12 bytes of padding (size=48, tsB=4 + hXY=32)
            // System.arraycopy(hXY_tsB, hXY_tsB.length-12, preSign, _X.length+_Y.length+Hash.HASH_LENGTH+4+4, 12);
            // byte sigPad[] = new byte[padSig];
            // _context.random().nextBytes(sigPad);
            // System.arraycopy(sigPad, 0, preSign, _X.length+_Y.length+Hash.HASH_LENGTH+4+4, padSig);
            Signature sig = _context.dsa().sign(preSign, _context.keyManager().getSigningPrivateKey());
            // if (_log.shouldLog(Log.DEBUG)) {
            // _log.debug(prefix()+"signing " + Base64.encode(preSign));
            // }
            byte[] ident = _context.router().getRouterInfo().getIdentity().toByteArray();
            // handle variable signature size
            int min = 2 + ident.length + 4 + sig.length();
            int rem = min % AES_SIZE;
            int padding = 0;
            if (rem > 0)
                padding = AES_SIZE - rem;
            byte[] preEncrypt = new byte[min + padding];
            DataHelper.toLong(preEncrypt, 0, 2, ident.length);
            System.arraycopy(ident, 0, preEncrypt, 2, ident.length);
            DataHelper.toLong(preEncrypt, 2 + ident.length, 4, _tsA);
            if (padding > 0)
                _context.random().nextBytes(preEncrypt, 2 + ident.length + 4, padding);
            System.arraycopy(sig.getData(), 0, preEncrypt, 2 + ident.length + 4 + padding, sig.length());
            _prevEncrypted = new byte[preEncrypt.length];
            _context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(), _hX_xor_bobIdentHash, _hX_xor_bobIdentHash.length - AES_SIZE, preEncrypt.length);
            // if (_log.shouldLog(Log.DEBUG)) {
            // _log.debug(prefix() + "unencrypted response to Bob: " + Base64.encode(preEncrypt));
            // _log.debug(prefix() + "encrypted response to Bob: " + Base64.encode(_prevEncrypted));
            // }
            // send 'er off (when the bw limiter says, etc)
            changeState(State.OB_SENT_RI);
            _transport.getPumper().wantsWrite(_con, _prevEncrypted);
        }
    }
    // Read in message #4
    if (_state == State.OB_SENT_RI && src.hasRemaining()) {
        // we are receiving their confirmation
        // recv E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev)
        int off = 0;
        if (_e_bobSig == null) {
            // handle variable signature size
            int siglen = _con.getRemotePeer().getSigningPublicKey().getType().getSigLen();
            int rem = siglen % AES_SIZE;
            int padding;
            if (rem > 0)
                padding = AES_SIZE - rem;
            else
                padding = 0;
            _e_bobSig = new byte[siglen + padding];
            if (_log.shouldLog(Log.DEBUG))
                _log.debug(prefix() + "receiving E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " + src.hasRemaining() + ")");
        } else {
            off = _received - XY_SIZE - HXY_TSB_PAD_SIZE;
            if (_log.shouldLog(Log.DEBUG))
                _log.debug(prefix() + "continuing to receive E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " + src.hasRemaining() + " off=" + off + " recv=" + _received + ")");
        }
        while (_state == State.OB_SENT_RI && src.hasRemaining()) {
            // if (_log.shouldLog(Log.DEBUG)) _log.debug(prefix()+"recv bobSig received=" + _received);
            _e_bobSig[off++] = src.get();
            _received++;
            if (off >= _e_bobSig.length) {
                changeState(State.OB_GOT_SIG);
                // if (_log.shouldLog(Log.DEBUG))
                // _log.debug(prefix() + "received E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev): " + Base64.encode(_e_bobSig));
                byte[] bobSig = new byte[_e_bobSig.length];
                _context.aes().decrypt(_e_bobSig, 0, bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, HXY_TSB_PAD_SIZE - AES_SIZE, _e_bobSig.length);
                // ignore the padding
                // handle variable signature size
                SigType type = _con.getRemotePeer().getSigningPublicKey().getType();
                int siglen = type.getSigLen();
                byte[] bobSigData = new byte[siglen];
                System.arraycopy(bobSig, 0, bobSigData, 0, siglen);
                Signature sig = new Signature(type, bobSigData);
                byte[] toVerify = new byte[XY_SIZE + XY_SIZE + HXY_SIZE + 4 + 4];
                int voff = 0;
                System.arraycopy(_X, 0, toVerify, voff, XY_SIZE);
                voff += XY_SIZE;
                System.arraycopy(_Y, 0, toVerify, voff, XY_SIZE);
                voff += XY_SIZE;
                System.arraycopy(_context.routerHash().getData(), 0, toVerify, voff, HXY_SIZE);
                voff += HXY_SIZE;
                DataHelper.toLong(toVerify, voff, 4, _tsA);
                voff += 4;
                DataHelper.toLong(toVerify, voff, 4, _tsB);
                voff += 4;
                boolean ok = _context.dsa().verifySignature(sig, toVerify, _con.getRemotePeer().getSigningPublicKey());
                if (!ok) {
                    _context.statManager().addRateData("ntcp.invalidSignature", 1);
                    fail("Signature was invalid - attempt to spoof " + _con.getRemotePeer().calculateHash().toBase64() + "?");
                } else {
                    if (_log.shouldLog(Log.DEBUG))
                        _log.debug(prefix() + "signature verified from Bob.  done!");
                    prepareExtra(src);
                    // reuse buf
                    byte[] nextWriteIV = _curEncrypted;
                    System.arraycopy(_prevEncrypted, _prevEncrypted.length - AES_SIZE, nextWriteIV, 0, AES_SIZE);
                    // this does not copy the nextWriteIV, do not release to cache
                    // We are Alice, he is Bob, clock skew is Bob - Alice
                    // skew in seconds
                    _con.finishOutboundEstablishment(_dh.getSessionKey(), _peerSkew, nextWriteIV, _e_bobSig);
                    releaseBufs(true);
                    // if socket gets closed this will be null - prevent NPE
                    InetAddress ia = _con.getChannel().socket().getInetAddress();
                    if (ia != null)
                        _transport.setIP(_con.getRemotePeer().calculateHash(), ia.getAddress());
                    changeState(State.VERIFIED);
                }
                return;
            }
        }
    }
}
Also used : Signature(net.i2p.data.Signature) DHSessionKeyBuilder(net.i2p.router.transport.crypto.DHSessionKeyBuilder) InetAddress(java.net.InetAddress) SigType(net.i2p.crypto.SigType)

Example 15 with Signature

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

the class OutboundEstablishState method decryptSignature.

/**
 * decrypt the signature (and subsequent pad bytes) with the
 * additional layer of encryption using the negotiated key along side
 * the packet's IV
 *
 *  Caller must synch on this.
 *  Only call this once! Decrypts in-place.
 */
private void decryptSignature() {
    if (_receivedEncryptedSignature == null)
        throw new NullPointerException("encrypted signature is null! this=" + this.toString());
    if (_sessionKey == null)
        throw new NullPointerException("SessionKey is null!");
    if (_receivedIV == null)
        throw new NullPointerException("IV is null!");
    _context.aes().decrypt(_receivedEncryptedSignature, 0, _receivedEncryptedSignature, 0, _sessionKey, _receivedIV, _receivedEncryptedSignature.length);
    // handle variable signature size
    SigType type = _remotePeer.getSigningPublicKey().getType();
    // if type == null throws NPE
    int sigLen = type.getSigLen();
    int mod = sigLen % 16;
    if (mod != 0) {
        byte[] signatureBytes = new byte[sigLen];
        System.arraycopy(_receivedEncryptedSignature, 0, signatureBytes, 0, sigLen);
        _receivedSignature = new Signature(type, signatureBytes);
    } else {
        _receivedSignature = new Signature(type, _receivedEncryptedSignature);
    }
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Decrypted received signature: " + Base64.encode(_receivedSignature.getData()));
}
Also used : Signature(net.i2p.data.Signature) SigType(net.i2p.crypto.SigType)

Aggregations

Signature (net.i2p.data.Signature)36 IOException (java.io.IOException)16 SigType (net.i2p.crypto.SigType)14 DataFormatException (net.i2p.data.DataFormatException)11 SigningPublicKey (net.i2p.data.SigningPublicKey)11 ByteArrayInputStream (java.io.ByteArrayInputStream)7 GeneralSecurityException (java.security.GeneralSecurityException)6 FileInputStream (java.io.FileInputStream)5 StringWriter (java.io.StringWriter)5 SigningPrivateKey (net.i2p.data.SigningPrivateKey)5 InetAddress (java.net.InetAddress)4 MessageDigest (java.security.MessageDigest)4 Destination (net.i2p.data.Destination)4 SimpleDataStructure (net.i2p.data.SimpleDataStructure)4 FileOutputStream (java.io.FileOutputStream)3 InputStream (java.io.InputStream)3 DigestInputStream (java.security.DigestInputStream)3 Hash (net.i2p.data.Hash)3 Log (net.i2p.util.Log)3 SecureFileOutputStream (net.i2p.util.SecureFileOutputStream)3