Changeset 06106c75


Ignore:
Timestamp:
Jun 2, 2018 12:35:11 PM (2 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
05ffa63
Parents:
363aaadb
Message:

NTCP: Refactor EstablishState? into interface/base/inbound/outbound,
in prep for NTCP2

Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • history.txt

    r363aaadb r06106c75  
     12018-06-02 zzz
     2 * Console: Sort tunnels within pools by expiration (ticket #2232)
     3 * NTCP: Refactor EstablishState in prep for NTCP2
     4
     52018-06-01 zzz
     6 * SusiDNS: Fix deleting notes (ticket #1433)
     7
    182018-05-31 zzz
    29 * Console:
  • router/java/src/net/i2p/router/RouterVersion.java

    r363aaadb r06106c75  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 16;
     21    public final static long BUILD = 17;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/transport/ntcp/EstablishState.java

    r363aaadb r06106c75  
    11package net.i2p.router.transport.ntcp;
    22
    3 import java.io.ByteArrayInputStream;
    4 import java.io.ByteArrayOutputStream;
    5 import java.io.IOException;
    6 import java.net.InetAddress;
    7 import java.net.UnknownHostException;
    83import java.nio.ByteBuffer;
    94
    10 import net.i2p.I2PAppContext;
    11 import net.i2p.crypto.SigType;
    12 import net.i2p.data.Base64;
    13 import net.i2p.data.DataFormatException;
    14 import net.i2p.data.DataHelper;
    15 import net.i2p.data.Hash;
    16 import net.i2p.data.router.RouterIdentity;
    17 import net.i2p.data.Signature;
    18 import net.i2p.router.Router;
    19 import net.i2p.router.RouterContext;
    20 import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
    21 import net.i2p.util.Log;
    22 import net.i2p.util.SimpleByteCache;
    23 
    245/**
    25  * Handle the 4-phase establishment, which is as follows:
    26  *
    27  * <pre>
    28  *
    29  * Alice                   contacts                      Bob
    30  * =========================================================
    31  *
    32  * Message 1 (Session Request):
    33  *  X+(H(X) xor Bob.identHash)-----------------------------&gt;
    34  *
    35  * Message 2 (Session Created):
    36  *  &lt;----------------------------------------Y+E(H(X+Y)+tsB, sk, Y[239:255])
    37  *
    38  * Message 3 (Session Confirm A):
    39  *  E(sz+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB), sk, hX_xor_Bob.identHash[16:31])---&gt;
    40  *
    41  * Message 4 (Session Confirm B):
    42  *  &lt;----------------------E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev)
    43  *
    44  *  Key:
    45  *
    46  *    X, Y: 256 byte DH keys
    47  *    H(): 32 byte SHA256 Hash
    48  *    E(data, session key, IV): AES256 Encrypt
    49  *    S(): 40 byte DSA Signature
    50  *    tsA, tsB: timestamps (4 bytes, seconds since epoch)
    51  *    sk: 32 byte Session key
    52  *    sz: 2 byte size of Alice identity to follow
    53  *
    54  * </pre>
    55  *
    56  *
    57  * Alternately, when Bob receives a connection, it could be a
    58  * check connection (perhaps prompted by Bob asking for someone
    59  * to verify his listener).  check connections are formatted per
    60  * isCheckInfo()
    61  * NOTE: Check info is unused.
     6 * Handle the establishment
    627 *
    638 */
    64 class EstablishState {
     9interface EstablishState {
    6510   
    66     public static final VerifiedEstablishState VERIFIED = new VerifiedEstablishState();
    67     public static final FailedEstablishState FAILED = new FailedEstablishState();
    68    
    69     private final RouterContext _context;
    70     private final Log _log;
    71 
    72     // bob receives (and alice sends)
    73     private final byte _X[];
    74     private final byte _hX_xor_bobIdentHash[];
    75     private int _aliceIdentSize;
    76     private RouterIdentity _aliceIdent;
    77     /** contains the decrypted aliceIndexSize + aliceIdent + tsA + padding + aliceSig */
    78     private ByteArrayOutputStream _sz_aliceIdent_tsA_padding_aliceSig;
    79     /** how long we expect _sz_aliceIdent_tsA_padding_aliceSig to be when its full */
    80     private int _sz_aliceIdent_tsA_padding_aliceSigSize;
    81     // alice receives (and bob sends)
    82     private final byte _Y[];
    83     private final byte _e_hXY_tsB[];
    84     /** Bob's timestamp in seconds, this is in message #2, *before* _tsA */
    85     private transient long _tsB;
    86     /** Alice's timestamp in seconds, this is in message #3, *after* _tsB
    87      *  Only saved for outbound. For inbound, see verifyInbound().
    88      */
    89     private transient long _tsA;
    90     /**
    91      *  OUR clock minus HIS clock, in seconds
    92      *
    93      *  Inbound: tsB - tsA - rtt/2
    94      *  Outbound: tsA - tsB - rtt/2
    95      */
    96     private transient long _peerSkew;
    97     private transient byte _e_bobSig[];
    98 
    99     /** previously received encrypted block (or the IV) */
    100     private byte _prevEncrypted[];
    101     /** current encrypted block we are reading (IB only) or an IV buf used at the end for OB */
    102     private byte _curEncrypted[];
    103     /**
    104      * next index in _curEncrypted to write to (equals _curEncrypted length if the block is
    105      * ready to decrypt)
    106      */
    107     private int _curEncryptedOffset;
    108     /** decryption buffer */
    109     private final byte _curDecrypted[];
    110 
    111     /** bytes received so far */
    112     private int _received;
    113     private byte _extra[];
    114 
    115     private final DHSessionKeyBuilder _dh;
    116 
    117     private final NTCPTransport _transport;
    118     private final NTCPConnection _con;
    119     /** error causing the corruption */
    120     private String _err;
    121     /** exception causing the error */
    122     private Exception _e;
    123     private boolean _failedBySkew;
    124    
    125     private static final int MIN_RI_SIZE = 387;
    126     private static final int MAX_RI_SIZE = 3072;
    127 
    128     private static final int AES_SIZE = 16;
    129     private static final int XY_SIZE = 256;
    130     private static final int HXY_SIZE = 32;  //Hash.HASH_LENGTH;
    131     private static final int HXY_TSB_PAD_SIZE = HXY_SIZE + 4 + 12;  // 48
    132 
    133     private static final Object _stateLock = new Object();
    134     protected State _state;
    135 
    136     private enum State {
    137         OB_INIT,
    138         /** sent 1 */
    139         OB_SENT_X,
    140         /** sent 1, got 2 partial */
    141         OB_GOT_Y,
    142         /** sent 1, got 2 */
    143         OB_GOT_HXY,
    144         /** sent 1, got 2, sent 3 */
    145         OB_SENT_RI,
    146         /** sent 1, got 2, sent 3, got 4 */
    147         OB_GOT_SIG,
    148 
    149         IB_INIT,
    150         /** got 1 partial */
    151         IB_GOT_X,
    152         /** got 1 */
    153         IB_GOT_HX,
    154         /** got 1, sent 2 */
    155         IB_SENT_Y,
    156         /** got 1, sent 2, got partial 3 */
    157         IB_GOT_RI_SIZE,
    158         /** got 1, sent 2, got 3 */
    159         IB_GOT_RI,
    160 
    161         /** OB: got and verified 4; IB: got and verified 3 and sent 4 */
    162         VERIFIED,
    163         CORRUPT
    164     }
    165 
    166     private EstablishState() {
    167         _context = null;
    168         _log = null;
    169         _X = null;
    170         _Y = null;
    171         _hX_xor_bobIdentHash = null;
    172         _curDecrypted = null;
    173         _dh = null;
    174         _transport = null;
    175         _con = null;
    176         _e_hXY_tsB = null;
    177     }
    178 
    179     public EstablishState(RouterContext ctx, NTCPTransport transport, NTCPConnection con) {
    180         _context = ctx;
    181         _log = ctx.logManager().getLog(getClass());
    182         _transport = transport;
    183         _con = con;
    184         _dh = _transport.getDHBuilder();
    185         _hX_xor_bobIdentHash = SimpleByteCache.acquire(HXY_SIZE);
    186         if (_con.isInbound()) {
    187             _X = SimpleByteCache.acquire(XY_SIZE);
    188             _Y = _dh.getMyPublicValueBytes();
    189             _sz_aliceIdent_tsA_padding_aliceSig = new ByteArrayOutputStream(512);
    190             _prevEncrypted = SimpleByteCache.acquire(AES_SIZE);
    191             _state = State.IB_INIT;
    192         } else {
    193             _X = _dh.getMyPublicValueBytes();
    194             _Y = SimpleByteCache.acquire(XY_SIZE);
    195             ctx.sha().calculateHash(_X, 0, XY_SIZE, _hX_xor_bobIdentHash, 0);
    196             xor32(con.getRemotePeer().calculateHash().getData(), _hX_xor_bobIdentHash);
    197             // _prevEncrypted will be created later
    198             _state = State.OB_INIT;
    199         }
    200 
    201         _e_hXY_tsB = new byte[HXY_TSB_PAD_SIZE];
    202         _curEncrypted = SimpleByteCache.acquire(AES_SIZE);
    203         _curDecrypted = SimpleByteCache.acquire(AES_SIZE);
    204     }
    205 
    206     /** @since 0.9.16 */
    207     private void changeState(State state) {
    208         synchronized (_stateLock) {
    209             _state = state;
    210         }
    211     }
    212 
    21311    /**
    21412     * parse the contents of the buffer as part of the handshake.  if the
     
    22018     * will return it to the pool.
    22119     */
    222     public synchronized void receive(ByteBuffer src) {
    223         synchronized(_stateLock) {   
    224             if (_state == State.VERIFIED || _state == State.CORRUPT)
    225                 throw new IllegalStateException(prefix() + "received unexpected data on " + _con);
    226         }
    227         if (!src.hasRemaining())
    228             return; // nothing to receive
     20    public void receive(ByteBuffer src);
    22921
    230         if (_log.shouldLog(Log.DEBUG))
    231             _log.debug(prefix() + "Receiving: " + src.remaining() + " Received: " + _received);
    232         if (_con.isInbound())
    233             receiveInbound(src);
    234         else
    235             receiveOutbound(src);
    236     }
     22    /**
     23     * Does nothing. Outbound (Alice) must override.
     24     * We are establishing an outbound connection, so prepare ourselves by
     25     * queueing up the write of the first part of the handshake
     26     */
     27    public void prepareOutbound();
    23728
    23829    /**
    23930     *  Was this connection failed because of clock skew?
    24031     */
    241     public synchronized boolean getFailedBySkew() { return _failedBySkew; }
    242 
    243     /**
    244      *  we are Bob, so receive these bytes as part of an inbound connection
    245      *  This method receives messages 1 and 3, and sends messages 2 and 4.
    246      *
    247      *  All data must be copied out of the buffer as Reader.processRead()
    248      *  will return it to the pool.
    249      *
    250      *  Caller must synch.
    251      *
    252      *  FIXME none of the _state comparisons use _stateLock, but whole thing
    253      *  is synchronized, should be OK. See isComplete()
    254      */
    255     private void receiveInbound(ByteBuffer src) {
    256         while (_state == State.IB_INIT && src.hasRemaining()) {
    257             byte c = src.get();
    258             _X[_received++] = c;
    259             if (_received >= XY_SIZE)
    260                 changeState(State.IB_GOT_X);
    261         }
    262         while (_state == State.IB_GOT_X && src.hasRemaining()) {
    263             int i = _received - XY_SIZE;
    264             _received++;
    265             byte c = src.get();
    266             _hX_xor_bobIdentHash[i] = c;
    267             if (i >= HXY_SIZE - 1)
    268                 changeState(State.IB_GOT_HX);
    269         }
    270 
    271         if (_state == State.IB_GOT_HX) {
    272 
    273                 if (_log.shouldLog(Log.DEBUG))
    274                     _log.debug(prefix()+"Enough data for a DH received");
    275 
    276                 // first verify that Alice knows who she is trying to talk with and that the X
    277                 // isn't corrupt
    278                 byte[] realXor = SimpleByteCache.acquire(HXY_SIZE);
    279                 _context.sha().calculateHash(_X, 0, XY_SIZE, realXor, 0);
    280                 xor32(_context.routerHash().getData(), realXor);
    281                 if (!DataHelper.eq(realXor, _hX_xor_bobIdentHash)) {
    282                     SimpleByteCache.release(realXor);
    283                     _context.statManager().addRateData("ntcp.invalidHXxorBIH", 1);
    284                     fail("Invalid hX_xor");
    285                     return;
    286                 }
    287                 SimpleByteCache.release(realXor);
    288                 if (!_transport.isHXHIValid(_hX_xor_bobIdentHash)) {
    289                     // blocklist source? but spoofed IPs could DoS us
    290                     _context.statManager().addRateData("ntcp.replayHXxorBIH", 1);
    291                     fail("Replay hX_xor");
    292                     return;
    293                 }
    294 
    295                 try {
    296                     // ok, they're actually trying to talk to us, and we got their (unauthenticated) X
    297                     _dh.setPeerPublicValue(_X);
    298                     _dh.getSessionKey(); // force the calc
    299                     System.arraycopy(_hX_xor_bobIdentHash, AES_SIZE, _prevEncrypted, 0, AES_SIZE);
    300                     if (_log.shouldLog(Log.DEBUG))
    301                         _log.debug(prefix()+"DH session key calculated (" + _dh.getSessionKey().toBase64() + ")");
    302 
    303                     // now prepare our response: Y+E(H(X+Y)+tsB+padding, sk, Y[239:255])
    304                     byte xy[] = new byte[XY_SIZE + XY_SIZE];
    305                     System.arraycopy(_X, 0, xy, 0, XY_SIZE);
    306                     System.arraycopy(_Y, 0, xy, XY_SIZE, XY_SIZE);
    307                     byte[] hxy = SimpleByteCache.acquire(HXY_SIZE);
    308                     _context.sha().calculateHash(xy, 0, XY_SIZE + XY_SIZE, hxy, 0);
    309                     // our (Bob's) timestamp in seconds
    310                     _tsB = (_context.clock().now() + 500) / 1000l;
    311                     byte toEncrypt[] = new byte[HXY_TSB_PAD_SIZE];  // 48
    312                     System.arraycopy(hxy, 0, toEncrypt, 0, HXY_SIZE);
    313                     byte tsB[] = DataHelper.toLong(4, _tsB);
    314                     System.arraycopy(tsB, 0, toEncrypt, HXY_SIZE, tsB.length);
    315                     _context.random().nextBytes(toEncrypt, HXY_SIZE + 4, 12);
    316                     if (_log.shouldLog(Log.DEBUG)) {
    317                         _log.debug(prefix()+"h(x+y)="+Base64.encode(hxy));
    318                         _log.debug(prefix() + "tsb = " + _tsB);
    319                         _log.debug(prefix()+"unencrypted H(X+Y)+tsB+padding: " + Base64.encode(toEncrypt));
    320                         _log.debug(prefix()+"encryption iv= " + Base64.encode(_Y, XY_SIZE-AES_SIZE, AES_SIZE));
    321                         _log.debug(prefix()+"encryption key= " + _dh.getSessionKey().toBase64());
    322                     }
    323                     SimpleByteCache.release(hxy);
    324                     _context.aes().encrypt(toEncrypt, 0, _e_hXY_tsB, 0, _dh.getSessionKey(),
    325                                            _Y, XY_SIZE-AES_SIZE, HXY_TSB_PAD_SIZE);
    326                     if (_log.shouldLog(Log.DEBUG))
    327                         _log.debug(prefix()+"encrypted H(X+Y)+tsB+padding: " + Base64.encode(_e_hXY_tsB));
    328                     byte write[] = new byte[XY_SIZE + HXY_TSB_PAD_SIZE];
    329                     System.arraycopy(_Y, 0, write, 0, XY_SIZE);
    330                     System.arraycopy(_e_hXY_tsB, 0, write, XY_SIZE, HXY_TSB_PAD_SIZE);
    331 
    332                     // ok, now that is prepared, we want to actually send it, so make sure we are up for writing
    333                     changeState(State.IB_SENT_Y);
    334                     _transport.getPumper().wantsWrite(_con, write);
    335                     if (!src.hasRemaining()) return;
    336                 } catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
    337                     _context.statManager().addRateData("ntcp.invalidDH", 1);
    338                     fail("Invalid X", e);
    339                     return;
    340                 }
    341 
    342         }
    343 
    344         // ok, we are onto the encrypted area, i.e. Message #3
    345         while ((_state == State.IB_SENT_Y ||
    346                 _state == State.IB_GOT_RI_SIZE ||
    347                 _state == State.IB_GOT_RI) && src.hasRemaining()) {
    348 
    349                 // Collect a 16-byte block
    350                 while (_curEncryptedOffset < AES_SIZE && src.hasRemaining()) {
    351                     _curEncrypted[_curEncryptedOffset++] = src.get();
    352                     _received++;
    353                 }
    354                 // Decrypt the 16-byte block
    355                 if (_curEncryptedOffset >= AES_SIZE) {
    356                     _context.aes().decrypt(_curEncrypted, 0, _curDecrypted, 0, _dh.getSessionKey(),
    357                                            _prevEncrypted, 0, AES_SIZE);
    358 
    359                     byte swap[] = _prevEncrypted;
    360                     _prevEncrypted = _curEncrypted;
    361                     _curEncrypted = swap;
    362                     _curEncryptedOffset = 0;
    363 
    364                     if (_state == State.IB_SENT_Y) { // we are on the first decrypted block
    365                         int sz = (int)DataHelper.fromLong(_curDecrypted, 0, 2);
    366                         if (sz < MIN_RI_SIZE || sz > MAX_RI_SIZE) {
    367                             _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
    368                             fail("size is invalid", new Exception("size is " + sz));
    369                             return;
    370                         }
    371                         if (_log.shouldLog(Log.DEBUG))
    372                             _log.debug(prefix() + "got the RI size: " + sz);
    373                         _aliceIdentSize  = sz;
    374                         changeState(State.IB_GOT_RI_SIZE);
    375 
    376                         // We must defer the calculations for total size of the message until
    377                         //  we get the full alice ident so
    378                         // we can determine how long the signature is.
    379                         // See below
    380 
    381                     }
    382                     try {
    383                         _sz_aliceIdent_tsA_padding_aliceSig.write(_curDecrypted);
    384                     } catch (IOException ioe) {
    385                         if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
    386                     }
    387 
    388                     if (_state == State.IB_GOT_RI_SIZE &&
    389                         _sz_aliceIdent_tsA_padding_aliceSig.size() >= 2 + _aliceIdentSize) {
    390                         // we have enough to get Alice's RI and determine the sig+padding length
    391                         readAliceRouterIdentity();
    392                         if (_log.shouldLog(Log.DEBUG))
    393                             _log.debug(prefix() + "got the RI");
    394                         if (_aliceIdent == null) {
    395                             // readAliceRouterIdentity already called fail
    396                             return;
    397                         }
    398                         SigType type = _aliceIdent.getSigningPublicKey().getType();
    399                         if (type == null) {
    400                             fail("Unsupported sig type");
    401                             return;
    402                         }
    403                         changeState(State.IB_GOT_RI);
    404                         // handle variable signature size
    405                         _sz_aliceIdent_tsA_padding_aliceSigSize = 2 + _aliceIdentSize + 4 + type.getSigLen();
    406                         int rem = (_sz_aliceIdent_tsA_padding_aliceSigSize % AES_SIZE);
    407                         int padding = 0;
    408                         if (rem > 0)
    409                             padding = AES_SIZE-rem;
    410                         _sz_aliceIdent_tsA_padding_aliceSigSize += padding;
    411                         if (_log.shouldLog(Log.DEBUG))
    412                             _log.debug(prefix() + "alice ident size decrypted as " + _aliceIdentSize +
    413                                        ", making the padding at " + padding + " and total size at " +
    414                                        _sz_aliceIdent_tsA_padding_aliceSigSize);
    415                     }
    416 
    417                     if (_state == State.IB_GOT_RI &&
    418                         _sz_aliceIdent_tsA_padding_aliceSig.size() >= _sz_aliceIdent_tsA_padding_aliceSigSize) {
    419                         // we have the remainder of Message #3, i.e. the padding+signature
    420                         // Time to verify.
    421 
    422                             if (_log.shouldLog(Log.DEBUG))
    423                                 _log.debug(prefix() + "got the sig");
    424                             verifyInbound();
    425                             if (_state == State.VERIFIED && src.hasRemaining())
    426                                 prepareExtra(src);
    427                             if (_log.shouldLog(Log.DEBUG))
    428                                 _log.debug(prefix()+"verifying size (sz=" + _sz_aliceIdent_tsA_padding_aliceSig.size()
    429                                            + " expected=" + _sz_aliceIdent_tsA_padding_aliceSigSize
    430                                            + ' ' + _state
    431                                            + " extra=" + (_extra != null ? _extra.length : 0) + ")");
    432                             return;
    433                     }
    434                 } else {
    435                     // no more bytes available in the buffer, and only a partial
    436                     // block was read, so we can't decrypt it.
    437                     if (_log.shouldLog(Log.DEBUG))
    438                         _log.debug(prefix() + "end of available data with only a partial block read (" +
    439                                    _curEncryptedOffset + ", " + _received + ")");
    440                 }
    441         }
    442 
    443         if (_log.shouldLog(Log.DEBUG))
    444             _log.debug(prefix()+"done with the data, not yet complete or corrupt");
    445     }
    446 
    447     /**
    448      *  We are Alice, so receive these bytes as part of an outbound connection.
    449      *  This method receives messages 2 and 4, and sends message 3.
    450      *
    451      *  All data must be copied out of the buffer as Reader.processRead()
    452      *  will return it to the pool.
    453      *
    454      *  Caller must synch.
    455      *
    456      *  FIXME none of the _state comparisons use _stateLock, but whole thing
    457      *  is synchronized, should be OK. See isComplete()
    458      */
    459     private void receiveOutbound(ByteBuffer src) {
    460 
    461         // recv Y+E(H(X+Y)+tsB, sk, Y[239:255])
    462         // Read in Y, which is the first part of message #2
    463         while (_state == State.OB_SENT_X && src.hasRemaining()) {
    464             byte c = src.get();
    465             _Y[_received++] = c;
    466             if (_received >= XY_SIZE) {
    467                 try {
    468                     _dh.setPeerPublicValue(_Y);
    469                     _dh.getSessionKey(); // force the calc
    470                     if (_log.shouldLog(Log.DEBUG))
    471                         _log.debug(prefix()+"DH session key calculated (" + _dh.getSessionKey().toBase64() + ")");
    472                     changeState(State.OB_GOT_Y);
    473                 } catch (DHSessionKeyBuilder.InvalidPublicParameterException e) {
    474                     _context.statManager().addRateData("ntcp.invalidDH", 1);
    475                     fail("Invalid X", e);
    476                     return;
    477                 }
    478             }
    479         }
    480 
    481         // Read in Y, which is the first part of message #2
    482         // Read in the rest of message #2
    483         while (_state == State.OB_GOT_Y && src.hasRemaining()) {
    484             int i = _received-XY_SIZE;
    485             _received++;
    486             byte c = src.get();
    487             _e_hXY_tsB[i] = c;
    488             if (i+1 >= HXY_TSB_PAD_SIZE) {
    489                 if (_log.shouldLog(Log.DEBUG)) _log.debug(prefix() + "received _e_hXY_tsB fully");
    490                 byte hXY_tsB[] = new byte[HXY_TSB_PAD_SIZE];
    491                 _context.aes().decrypt(_e_hXY_tsB, 0, hXY_tsB, 0, _dh.getSessionKey(), _Y, XY_SIZE-AES_SIZE, HXY_TSB_PAD_SIZE);
    492                 byte XY[] = new byte[XY_SIZE + XY_SIZE];
    493                 System.arraycopy(_X, 0, XY, 0, XY_SIZE);
    494                 System.arraycopy(_Y, 0, XY, XY_SIZE, XY_SIZE);
    495                 byte[] h = SimpleByteCache.acquire(HXY_SIZE);
    496                 _context.sha().calculateHash(XY, 0, XY_SIZE + XY_SIZE, h, 0);
    497                 if (!DataHelper.eq(h, 0, hXY_tsB, 0, HXY_SIZE)) {
    498                     SimpleByteCache.release(h);
    499                     _context.statManager().addRateData("ntcp.invalidHXY", 1);
    500                     fail("Invalid H(X+Y) - mitm attack attempted?");
    501                     return;
    502                 }
    503                 SimpleByteCache.release(h);
    504                 changeState(State.OB_GOT_HXY);
    505                 // their (Bob's) timestamp in seconds
    506                 _tsB = DataHelper.fromLong(hXY_tsB, HXY_SIZE, 4);
    507                 long now = _context.clock().now();
    508                 // rtt from sending #1 to receiving #2
    509                 long rtt = now - _con.getCreated();
    510                 // our (Alice's) timestamp in seconds
    511                 _tsA = (now + 500) / 1000;
    512                 _peerSkew = (now - (_tsB * 1000) - (rtt / 2) + 500) / 1000;
    513                 if (_log.shouldLog(Log.DEBUG))
    514                     _log.debug(prefix()+"h(X+Y) is correct, skew = " + _peerSkew);
    515 
    516                 // the skew is not authenticated yet, but it is certainly fatal to
    517                 // the establishment, so fail hard if appropriate
    518                 long diff = 1000*Math.abs(_peerSkew);
    519                 if (!_context.clock().getUpdatedSuccessfully()) {
    520                     // Adjust the clock one time in desperation
    521                     // We are Alice, he is Bob, adjust to match Bob
    522                     _context.clock().setOffset(1000 * (0 - _peerSkew), true);
    523                     _peerSkew = 0;
    524                     if (diff != 0)
    525                         _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff));
    526                 } else if (diff >= Router.CLOCK_FUDGE_FACTOR) {
    527                     _context.statManager().addRateData("ntcp.invalidOutboundSkew", diff);
    528                     _transport.markReachable(_con.getRemotePeer().calculateHash(), false);
    529                     // Only banlist if we know what time it is
    530                     _context.banlist().banlistRouter(DataHelper.formatDuration(diff),
    531                                                        _con.getRemotePeer().calculateHash(),
    532                                                        _x("Excessive clock skew: {0}"));
    533                     _transport.setLastBadSkew(_peerSkew);
    534                     fail("Clocks too skewed (" + diff + " ms)", null, true);
    535                     return;
    536                 } else if (_log.shouldLog(Log.DEBUG)) {
    537                     _log.debug(prefix()+"Clock skew: " + diff + " ms");
    538                 }
    539 
    540                 // now prepare and send our response
    541                 // send E(#+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB), sk, hX_xor_Bob.identHash[16:31])
    542                 int sigSize = XY_SIZE + XY_SIZE + HXY_SIZE + 4+4;//+12;
    543                 byte preSign[] = new byte[sigSize];
    544                 System.arraycopy(_X, 0, preSign, 0, XY_SIZE);
    545                 System.arraycopy(_Y, 0, preSign, XY_SIZE, XY_SIZE);
    546                 System.arraycopy(_con.getRemotePeer().calculateHash().getData(), 0, preSign, XY_SIZE + XY_SIZE, HXY_SIZE);
    547                 DataHelper.toLong(preSign, XY_SIZE + XY_SIZE + HXY_SIZE, 4, _tsA);
    548                 DataHelper.toLong(preSign, XY_SIZE + XY_SIZE + HXY_SIZE + 4, 4, _tsB);
    549                 // hXY_tsB has 12 bytes of padding (size=48, tsB=4 + hXY=32)
    550                 Signature sig = _context.dsa().sign(preSign, _context.keyManager().getSigningPrivateKey());
    551 
    552                 byte ident[] = _context.router().getRouterInfo().getIdentity().toByteArray();
    553                 // handle variable signature size
    554                 int min = 2 + ident.length + 4 + sig.length();
    555                 int rem = min % AES_SIZE;
    556                 int padding = 0;
    557                 if (rem > 0)
    558                     padding = AES_SIZE - rem;
    559                 byte preEncrypt[] = new byte[min+padding];
    560                 DataHelper.toLong(preEncrypt, 0, 2, ident.length);
    561                 System.arraycopy(ident, 0, preEncrypt, 2, ident.length);
    562                 DataHelper.toLong(preEncrypt, 2+ident.length, 4, _tsA);
    563                 if (padding > 0)
    564                     _context.random().nextBytes(preEncrypt, 2 + ident.length + 4, padding);
    565                 System.arraycopy(sig.getData(), 0, preEncrypt, 2+ident.length+4+padding, sig.length());
    566 
    567                 _prevEncrypted = new byte[preEncrypt.length];
    568                 _context.aes().encrypt(preEncrypt, 0, _prevEncrypted, 0, _dh.getSessionKey(),
    569                                        _hX_xor_bobIdentHash, _hX_xor_bobIdentHash.length-AES_SIZE, preEncrypt.length);
    570 
    571                 changeState(State.OB_SENT_RI);
    572                 _transport.getPumper().wantsWrite(_con, _prevEncrypted);
    573             }
    574         }
    575 
    576         // Read in message #4
    577         if (_state == State.OB_SENT_RI && src.hasRemaining()) {
    578             // we are receiving their confirmation
    579 
    580             // recv E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev)
    581             int off = 0;
    582             if (_e_bobSig == null) {
    583                 // handle variable signature size
    584                 int siglen = _con.getRemotePeer().getSigningPublicKey().getType().getSigLen();
    585                 int rem = siglen % AES_SIZE;
    586                 int padding;
    587                 if (rem > 0)
    588                     padding = AES_SIZE - rem;
    589                 else
    590                     padding = 0;
    591                 _e_bobSig = new byte[siglen + padding];
    592                 if (_log.shouldLog(Log.DEBUG))
    593                     _log.debug(prefix() + "receiving E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " +
    594                                src.hasRemaining() + ")");
    595             } else {
    596                 off = _received - XY_SIZE - HXY_TSB_PAD_SIZE;
    597                 if (_log.shouldLog(Log.DEBUG))
    598                     _log.debug(prefix() + "continuing to receive E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev) (remaining? " +
    599                                src.hasRemaining() + " off=" + off + " recv=" + _received + ")");
    600             }
    601             while (_state == State.OB_SENT_RI && src.hasRemaining()) {
    602                 _e_bobSig[off++] = src.get();
    603                 _received++;
    604 
    605                 if (off >= _e_bobSig.length) {
    606                     changeState(State.OB_GOT_SIG);
    607                     byte bobSig[] = new byte[_e_bobSig.length];
    608                     _context.aes().decrypt(_e_bobSig, 0, bobSig, 0, _dh.getSessionKey(),
    609                                            _e_hXY_tsB, HXY_TSB_PAD_SIZE - AES_SIZE, _e_bobSig.length);
    610                     // ignore the padding
    611                     // handle variable signature size
    612                     SigType type = _con.getRemotePeer().getSigningPublicKey().getType();
    613                     int siglen = type.getSigLen();
    614                     byte bobSigData[] = new byte[siglen];
    615                     System.arraycopy(bobSig, 0, bobSigData, 0, siglen);
    616                     Signature sig = new Signature(type, bobSigData);
    617 
    618                     byte toVerify[] = new byte[XY_SIZE + XY_SIZE + HXY_SIZE +4+4];
    619                     int voff = 0;
    620                     System.arraycopy(_X, 0, toVerify, voff, XY_SIZE); voff += XY_SIZE;
    621                     System.arraycopy(_Y, 0, toVerify, voff, XY_SIZE); voff += XY_SIZE;
    622                     System.arraycopy(_context.routerHash().getData(), 0, toVerify, voff, HXY_SIZE); voff += HXY_SIZE;
    623                     DataHelper.toLong(toVerify, voff, 4, _tsA); voff += 4;
    624                     DataHelper.toLong(toVerify, voff, 4, _tsB); voff += 4;
    625 
    626                     boolean ok = _context.dsa().verifySignature(sig, toVerify, _con.getRemotePeer().getSigningPublicKey());
    627                     if (!ok) {
    628                         _context.statManager().addRateData("ntcp.invalidSignature", 1);
    629                         fail("Signature was invalid - attempt to spoof " + _con.getRemotePeer().calculateHash().toBase64() + "?");
    630                     } else {
    631                         if (_log.shouldLog(Log.DEBUG))
    632                             _log.debug(prefix() + "signature verified from Bob.  done!");
    633                         prepareExtra(src);
    634                         byte nextWriteIV[] = _curEncrypted; // reuse buf
    635                         System.arraycopy(_prevEncrypted, _prevEncrypted.length-AES_SIZE, nextWriteIV, 0, AES_SIZE);
    636                         // this does not copy the nextWriteIV, do not release to cache
    637                         // We are Alice, he is Bob, clock skew is Bob - Alice
    638                         _con.finishOutboundEstablishment(_dh.getSessionKey(), _peerSkew, nextWriteIV, _e_bobSig); // skew in seconds
    639                         releaseBufs(true);
    640                         // if socket gets closed this will be null - prevent NPE
    641                         InetAddress ia = _con.getChannel().socket().getInetAddress();
    642                         if (ia != null)
    643                             _transport.setIP(_con.getRemotePeer().calculateHash(), ia.getAddress());
    644                         changeState(State.VERIFIED);
    645                     }
    646                     return;
    647                 }
    648             }
    649         }
    650     }
     32    public boolean getFailedBySkew();
    65133
    65234    /** did the handshake fail for some reason? */
    653     public boolean isCorrupt() {
    654         synchronized(_stateLock) {
    655             return _state == State.CORRUPT;
    656         }
    657     }
     35    public boolean isCorrupt();
    65836
    65937    /**
     
    66442     *  @return is the handshake complete and valid?
    66543     */
    666     public boolean isComplete() {
    667         synchronized(_stateLock) {
    668             return _state == State.VERIFIED;
    669         }
    670     }
    671 
    672     /**
    673      * We are Alice.
    674      * We are establishing an outbound connection, so prepare ourselves by
    675      * queueing up the write of the first part of the handshake
    676      * This method sends message #1 to Bob.
    677      */
    678     public synchronized void prepareOutbound() {
    679         boolean shouldSend;
    680         synchronized(_stateLock) {   
    681             shouldSend = _state == State.OB_INIT;
    682         }
    683         if (shouldSend) {
    684             if (_log.shouldLog(Log.DEBUG))
    685                 _log.debug(prefix() + "send X");
    686             byte toWrite[] = new byte[XY_SIZE + _hX_xor_bobIdentHash.length];
    687             System.arraycopy(_X, 0, toWrite, 0, XY_SIZE);
    688             System.arraycopy(_hX_xor_bobIdentHash, 0, toWrite, XY_SIZE, _hX_xor_bobIdentHash.length);
    689             changeState(State.OB_SENT_X);
    690             _transport.getPumper().wantsWrite(_con, toWrite);
    691         } else {
    692             if (_log.shouldLog(Log.WARN))
    693                 _log.warn(prefix() + "unexpected prepareOutbound()");
    694         }
    695     }
    696 
    697     /**
    698      * We are Bob. We have received enough of message #3 from Alice
    699      * to get Alice's RouterIdentity.
    700      *
    701      * _aliceIdentSize must be set.
    702      * _sz_aliceIdent_tsA_padding_aliceSig must contain at least 2 + _aliceIdentSize bytes.
    703      *
    704      * Sets _aliceIdent so that we
    705      * may determine the signature and padding sizes.
    706      *
    707      * After all of message #3 is received including the signature and
    708      * padding, verifyIdentity() must be called.
    709      *
    710      *  State must be IB_GOT_RI_SIZE.
    711      *  Caller must synch.
    712      *
    713      * @since 0.9.16 pulled out of verifyInbound()
    714      */
    715     private void readAliceRouterIdentity() {
    716         byte b[] = _sz_aliceIdent_tsA_padding_aliceSig.toByteArray();
    717 
    718         try {
    719             int sz = _aliceIdentSize;
    720             if (sz < MIN_RI_SIZE || sz > MAX_RI_SIZE ||
    721                 sz > b.length-2) {
    722                 _context.statManager().addRateData("ntcp.invalidInboundSize", sz);
    723                 fail("size is invalid", new Exception("size is " + sz));
    724                 return;
    725             }
    726             RouterIdentity alice = new RouterIdentity();
    727             ByteArrayInputStream bais = new ByteArrayInputStream(b, 2, sz);
    728             alice.readBytes(bais);
    729             _aliceIdent = alice;
    730         } catch (IOException ioe) {
    731             _context.statManager().addRateData("ntcp.invalidInboundIOE", 1);
    732             fail("Error verifying peer", ioe);
    733         } catch (DataFormatException dfe) {
    734             _context.statManager().addRateData("ntcp.invalidInboundDFE", 1);
    735             fail("Error verifying peer", dfe);
    736         }
    737     }
    738 
    739 
    740     /**
    741      * We are Bob. Verify message #3 from Alice, then send message #4 to Alice.
    742      *
    743      * _aliceIdentSize and _aliceIdent must be set.
    744      * _sz_aliceIdent_tsA_padding_aliceSig must contain at least
    745      *  (2 + _aliceIdentSize + 4 + padding + sig) bytes.
    746      *
    747      * Sets _aliceIdent so that we
    748      *
    749      * readAliceRouterIdentity() must have been called previously
    750      *
    751      * Make sure the signatures are correct, and if they are, update the
    752      * NIOConnection with the session key / peer ident / clock skew / iv.
    753      * The NIOConnection itself is responsible for registering with the
    754      * transport
    755      *
    756      *  State must be IB_GOT_RI.
    757      *  Caller must synch.
    758      */
    759     private void verifyInbound() {
    760         byte b[] = _sz_aliceIdent_tsA_padding_aliceSig.toByteArray();
    761         try {
    762             int sz = _aliceIdentSize;
    763             // her timestamp from message #3
    764             long tsA = DataHelper.fromLong(b, 2+sz, 4);
    765             // _tsB is when we sent message #2
    766             // Adjust backward by RTT/2
    767             long now = _context.clock().now();
    768             // rtt from sending #2 to receiving #3
    769             long rtt = now - _con.getCreated();
    770             _peerSkew = (now - (tsA * 1000) - (rtt / 2) + 500) / 1000;
    771 
    772             ByteArrayOutputStream baos = new ByteArrayOutputStream(768);
    773             baos.write(_X);
    774             baos.write(_Y);
    775             baos.write(_context.routerHash().getData());
    776             baos.write(DataHelper.toLong(4, tsA));
    777             baos.write(DataHelper.toLong(4, _tsB));
    778             //baos.write(b, 2+sz+4, b.length-2-sz-4-Signature.SIGNATURE_BYTES);
    779 
    780             byte toVerify[] = baos.toByteArray();
    781 
    782             // handle variable signature size
    783             SigType type = _aliceIdent.getSigningPublicKey().getType();
    784             if (type == null) {
    785                 fail("unsupported sig type");
    786                 return;
    787             }
    788             byte s[] = new byte[type.getSigLen()];
    789             System.arraycopy(b, b.length-s.length, s, 0, s.length);
    790             Signature sig = new Signature(type, s);
    791             boolean ok = _context.dsa().verifySignature(sig, toVerify, _aliceIdent.getSigningPublicKey());
    792             if (ok) {
    793                 // get inet-addr
    794                 InetAddress addr = this._con.getChannel().socket().getInetAddress();
    795                 byte[] ip = (addr == null) ? null : addr.getAddress();
    796                 if (_context.banlist().isBanlistedForever(_aliceIdent.calculateHash())) {
    797                     if (_log.shouldLog(Log.WARN))
    798                         _log.warn("Dropping inbound connection from permanently banlisted peer: " + _aliceIdent.calculateHash());
    799                     // So next time we will not accept the con from this IP,
    800                     // rather than doing the whole handshake
    801                     if(ip != null)
    802                        _context.blocklist().add(ip);
    803                     fail("Peer is banlisted forever: " + _aliceIdent.calculateHash());
    804                     return;
    805                 }
    806                 if(ip != null)
    807                    _transport.setIP(_aliceIdent.calculateHash(), ip);
    808                 if (_log.shouldLog(Log.DEBUG))
    809                     _log.debug(prefix() + "verification successful for " + _con);
    810 
    811                 long diff = 1000*Math.abs(_peerSkew);
    812                 if (!_context.clock().getUpdatedSuccessfully()) {
    813                     // Adjust the clock one time in desperation
    814                     // This isn't very likely, outbound will do it first
    815                     // We are Bob, she is Alice, adjust to match Alice
    816                     _context.clock().setOffset(1000 * (0 - _peerSkew), true);
    817                     _peerSkew = 0;
    818                     if (diff != 0)
    819                         _log.logAlways(Log.WARN, "NTP failure, NTCP adjusting clock by " + DataHelper.formatDuration(diff));
    820                 } else if (diff >= Router.CLOCK_FUDGE_FACTOR) {
    821                     _context.statManager().addRateData("ntcp.invalidInboundSkew", diff);
    822                     _transport.markReachable(_aliceIdent.calculateHash(), true);
    823                     // Only banlist if we know what time it is
    824                     _context.banlist().banlistRouter(DataHelper.formatDuration(diff),
    825                                                        _aliceIdent.calculateHash(),
    826                                                        _x("Excessive clock skew: {0}"));
    827                     _transport.setLastBadSkew(_peerSkew);
    828                     fail("Clocks too skewed (" + diff + " ms)", null, true);
    829                     return;
    830                 } else if (_log.shouldLog(Log.DEBUG)) {
    831                     _log.debug(prefix()+"Clock skew: " + diff + " ms");
    832                 }
    833 
    834                 _con.setRemotePeer(_aliceIdent);
    835                 sendInboundConfirm(_aliceIdent, tsA);
    836                 if (_log.shouldLog(Log.DEBUG))
    837                     _log.debug(prefix()+"e_bobSig is " + _e_bobSig.length + " bytes long");
    838                 byte iv[] = _curEncrypted;  // reuse buf
    839                 System.arraycopy(_e_bobSig, _e_bobSig.length-AES_SIZE, iv, 0, AES_SIZE);
    840                 // this does not copy the IV, do not release to cache
    841                 // We are Bob, she is Alice, clock skew is Alice-Bob
    842                 _con.finishInboundEstablishment(_dh.getSessionKey(), _peerSkew, iv, _prevEncrypted); // skew in seconds
    843                 releaseBufs(true);
    844                 if (_log.shouldLog(Log.INFO))
    845                     _log.info(prefix()+"Verified remote peer as " + _aliceIdent.calculateHash());
    846                 changeState(State.VERIFIED);
    847             } else {
    848                 _context.statManager().addRateData("ntcp.invalidInboundSignature", 1);
    849                 fail("Peer verification failed - spoof of " + _aliceIdent.calculateHash() + "?");
    850             }
    851         } catch (IOException ioe) {
    852             _context.statManager().addRateData("ntcp.invalidInboundIOE", 1);
    853             fail("Error verifying peer", ioe);
    854         }
    855     }
    856 
    857     /**
    858      *  We are Bob. Send message #4 to Alice.
    859      *
    860      *  State must be VERIFIED.
    861      *  Caller must synch.
    862      */
    863     private void sendInboundConfirm(RouterIdentity alice, long tsA) {
    864         // send Alice E(S(X+Y+Alice.identHash+tsA+tsB), sk, prev)
    865         byte toSign[] = new byte[XY_SIZE + XY_SIZE + 32+4+4];
    866         int off = 0;
    867         System.arraycopy(_X, 0, toSign, off, XY_SIZE); off += XY_SIZE;
    868         System.arraycopy(_Y, 0, toSign, off, XY_SIZE); off += XY_SIZE;
    869         Hash h = alice.calculateHash();
    870         System.arraycopy(h.getData(), 0, toSign, off, 32); off += 32;
    871         DataHelper.toLong(toSign, off, 4, tsA); off += 4;
    872         DataHelper.toLong(toSign, off, 4, _tsB); off += 4;
    873 
    874         // handle variable signature size
    875         Signature sig = _context.dsa().sign(toSign, _context.keyManager().getSigningPrivateKey());
    876         int siglen = sig.length();
    877         int rem = siglen % AES_SIZE;
    878         int padding;
    879         if (rem > 0)
    880             padding = AES_SIZE - rem;
    881         else
    882             padding = 0;
    883         byte preSig[] = new byte[siglen + padding];
    884         System.arraycopy(sig.getData(), 0, preSig, 0, siglen);
    885         if (padding > 0)
    886             _context.random().nextBytes(preSig, siglen, padding);
    887         _e_bobSig = new byte[preSig.length];
    888         _context.aes().encrypt(preSig, 0, _e_bobSig, 0, _dh.getSessionKey(), _e_hXY_tsB, HXY_TSB_PAD_SIZE - AES_SIZE, _e_bobSig.length);
    889 
    890         if (_log.shouldLog(Log.DEBUG))
    891             _log.debug(prefix() + "Sending encrypted inbound confirmation");
    892         _transport.getPumper().wantsWrite(_con, _e_bobSig);
    893     }
    894 
    895     /** Anything left over in the byte buffer after verification is extra
    896      *
    897      *  All data must be copied out of the buffer as Reader.processRead()
    898      *  will return it to the pool.
    899      *
    900      *  State must be VERIFIED.
    901      *  Caller must synch.
    902      */
    903     private void prepareExtra(ByteBuffer buf) {
    904         int remaining = buf.remaining();
    905         if (remaining > 0) {
    906             _extra = new byte[remaining];
    907             buf.get(_extra);
    908             _received += remaining;
    909         }
    910         if (_log.shouldLog(Log.DEBUG))
    911             _log.debug(prefix() + "prepare extra " + remaining + " (total received: " + _received + ")");
    912     }
     44    public boolean isComplete();
    91345
    91446    /**
     
    91648     * handshake that were after the actual handshake.  This may return null.
    91749     */
    918     public synchronized byte[] getExtraBytes() { return _extra; }
     50    public byte[] getExtraBytes();
    91951
    92052    /**
     
    92355     *  @since 0.9.16
    92456     */
    925     public synchronized void close(String reason, Exception e) {
    926         fail(reason, e);
    927     }
     57    public void close(String reason, Exception e);
    92858
    929     /** Caller must synch. */
    930     private void fail(String reason) { fail(reason, null); }
     59    public String getError();
    93160
    932     /** Caller must synch. */
    933     private void fail(String reason, Exception e) { fail(reason, e, false); }
    934 
    935     /** Caller must synch. */
    936     private void fail(String reason, Exception e, boolean bySkew) {
    937         synchronized(_stateLock) {   
    938             if (_state == State.CORRUPT || _state == State.VERIFIED)
    939                 return;
    940             changeState(State.CORRUPT);
    941         }
    942         _failedBySkew = bySkew;
    943         _err = reason;
    944         _e = e;
    945         if (_log.shouldLog(Log.WARN))
    946             _log.warn(prefix()+"Failed to establish: " + _err, e);
    947         releaseBufs(false);
    948     }
    949 
    950     /**
    951      *  Only call once. Caller must synch.
    952      *  @since 0.9.16
    953      */
    954     private void releaseBufs(boolean isVerified) {
    955         // null or longer for OB
    956         if (_prevEncrypted != null && _prevEncrypted.length == AES_SIZE)
    957             SimpleByteCache.release(_prevEncrypted);
    958         // Do not release _curEncrypted if verified, it is passed to
    959         // NTCPConnection to use as the IV
    960         if (!isVerified)
    961             SimpleByteCache.release(_curEncrypted);
    962         SimpleByteCache.release(_curDecrypted);
    963         SimpleByteCache.release(_hX_xor_bobIdentHash);
    964         if (_dh.getPeerPublicValue() == null)
    965             _transport.returnUnused(_dh);
    966         if (_con.isInbound())
    967             SimpleByteCache.release(_X);
    968         else
    969             SimpleByteCache.release(_Y);
    970     }
    971 
    972     public synchronized String getError() { return _err; }
    973 
    974     public synchronized Exception getException() { return _e; }
    975    
    976     /**
    977      *  XOR a into b. Modifies b. a is unmodified.
    978      *  @param a 32 bytes
    979      *  @param b 32 bytes
    980      *  @since 0.9.12
    981      */
    982     private static void xor32(byte[] a, byte[] b) {
    983         for (int i = 0; i < 32; i++) {
    984             b[i] ^= a[i];
    985         }
    986     }
    987 
    988     private String prefix() { return toString(); }
    989 
    990     @Override
    991     public String toString() {
    992         StringBuilder buf = new StringBuilder(64);
    993         if (_con.isInbound())
    994             buf.append("IBES ");
    995         else
    996             buf.append("OBES ");
    997         buf.append(System.identityHashCode(this));
    998         buf.append(' ').append(_state);
    999         if (_con.isEstablished()) buf.append(" established");
    1000         buf.append(": ");
    1001         return buf.toString();
    1002     }
    1003 
    1004     /**
    1005      *  @since 0.9.8
    1006      */
    1007     private static class VerifiedEstablishState extends EstablishState {
    1008 
    1009         public VerifiedEstablishState() {
    1010             super();
    1011             _state = State.VERIFIED;
    1012         }
    1013 
    1014         @Override public void prepareOutbound() {
    1015             Log log =RouterContext.getCurrentContext().logManager().getLog(VerifiedEstablishState.class);
    1016             log.warn("prepareOutbound() on verified state, doing nothing!");
    1017         }
    1018 
    1019         @Override public String toString() { return "VerifiedEstablishState: ";}
    1020     }
    1021 
    1022     /**
    1023      *  @since 0.9.16
    1024      */
    1025     private static class FailedEstablishState extends EstablishState {
    1026 
    1027         public FailedEstablishState() {
    1028             super();
    1029             _state = State.CORRUPT;
    1030         }
    1031 
    1032         @Override public void prepareOutbound() {
    1033             Log log =RouterContext.getCurrentContext().logManager().getLog(VerifiedEstablishState.class);
    1034             log.warn("prepareOutbound() on verified state, doing nothing!");
    1035         }
    1036 
    1037         @Override public String toString() { return "FailedEstablishState: ";}
    1038     }
    1039 
    1040 /*******
    1041     public static void main(String args[]) {
    1042         if (args.length == 3) {
    1043             checkHost(args);
    1044             return;
    1045         }
    1046         I2PAppContext ctx = I2PAppContext.getGlobalContext();
    1047         try {
    1048             java.net.Socket s = new java.net.Socket("localhost", 9094);
    1049             OutputStream out = s.getOutputStream();
    1050             DHSessionKeyBuilder dh = new DHSessionKeyBuilder();
    1051             byte X[] = dh.getMyPublicValueBytes();
    1052 
    1053             //  SEND X+(H(X) xor Bob.identHash)----------------------------->
    1054             out.write(X);
    1055             System.out.println("sent X =" + Base64.encode(X));
    1056             byte bih[] = Base64.decode("HuRdDx9t-RaZfYkYvacRwP~6s9mvbdkYzIMrpUCsZIo=");
    1057             System.out.println("bih = " + Base64.encode(bih));
    1058             Hash hx = ctx.sha().calculateHash(X);
    1059             System.out.println("hx  = " + Base64.encode(hx.getData()));
    1060             byte hx_xor_bih[] = DataHelper.xor(bih, hx.getData());
    1061             System.out.println("xor = " + Base64.encode(hx_xor_bih));
    1062             out.write(hx_xor_bih);
    1063             out.flush();
    1064             //  DONE SENDING X+(H(X) xor Bob.identHash)----------------------------->
    1065 
    1066             //  NOW READ Y+E(H(X+Y)+tsB+padding, sk, Y[239:255])
    1067             InputStream in = s.getInputStream();
    1068             byte toRead[] = new byte[256+(32+4+12)];
    1069             int read = 0;
    1070             while (read < toRead.length) {
    1071                 int r = in.read(toRead, read, toRead.length-read);
    1072                 if (r == -1)
    1073                     throw new EOFException("eof at read=" + read);
    1074                 read += r;
    1075             }
    1076             byte Y[] = new byte[256];
    1077             System.arraycopy(toRead, 0, Y, 0, Y.length);
    1078             dh.setPeerPublicValue(Y);
    1079             byte decrypted[] = new byte[(32+4+12)];
    1080             ctx.aes().decrypt(toRead, Y.length, decrypted, 0, dh.getSessionKey(), Y, Y.length-16, decrypted.length);
    1081             //display y, encrypted, decrypted, hx+y, tsb, padding
    1082             //unencrypted H(X+Y)+tsB+padding: bSJIv1ynFw9MhIqbObOpCqeZxtFvKEx-ilcsZQ31zYNEnVXyHCZagLbdQYRmd1oq
    1083             System.out.println("dh session key: " + dh.getSessionKey().toBase64());
    1084             System.out.println("decryption iv: " + Base64.encode(Y, Y.length-16, 16));
    1085             System.out.println("Y = " + Base64.encode(Y));
    1086             byte xy[] = new byte[512];
    1087             System.arraycopy(X, 0, xy, 0, X.length);
    1088             System.arraycopy(Y, 0, xy, X.length, Y.length);
    1089             System.out.println("h(x+y): " + ctx.sha().calculateHash(xy).toBase64());
    1090             System.out.println("encrypted H(X+Y)+tsB+padding: " + Base64.encode(toRead, Y.length, toRead.length-Y.length));
    1091             System.out.println("unencrypted H(X+Y)+tsB+padding: " + Base64.encode(decrypted));
    1092             long tsB = DataHelper.fromLong(decrypted, 32, 4);
    1093 
    1094             //try { Thread.sleep(40*1000); } catch (InterruptedException ie) {}
    1095 
    1096             RouterIdentity alice = new RouterIdentity();
    1097             Object k[] = ctx.keyGenerator().generatePKIKeypair();
    1098             PublicKey pub = (PublicKey)k[0];
    1099             PrivateKey priv = (PrivateKey)k[1];
    1100             k = ctx.keyGenerator().generateSigningKeypair();
    1101             SigningPublicKey spub = (SigningPublicKey)k[0];
    1102             SigningPrivateKey spriv = (SigningPrivateKey)k[1];
    1103             alice.setCertificate(new Certificate(Certificate.CERTIFICATE_TYPE_NULL, null));
    1104             alice.setPublicKey(pub);
    1105             alice.setSigningPublicKey(spub);
    1106 
    1107             //  SEND E(#+Alice.identity+tsA+padding+S(X+Y+Bob.identHash+tsA+tsB+padding), sk, hX_xor_Bob.identHash[16:31])--->
    1108 
    1109             ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
    1110             byte aliceb[] = alice.toByteArray();
    1111             long tsA = ctx.clock().now()/1000l;
    1112             baos.write(DataHelper.toLong(2, aliceb.length));
    1113             baos.write(aliceb);
    1114             baos.write(DataHelper.toLong(4, tsA));
    1115 
    1116             int base = baos.size() + Signature.SIGNATURE_BYTES;
    1117             int rem = base % 16;
    1118             int padding = 0;
    1119             if (rem > 0)
    1120                 padding = 16 - rem;
    1121             byte pad[] = new byte[padding];
    1122             ctx.random().nextBytes(pad);
    1123             baos.write(pad);
    1124             base += padding;
    1125 
    1126             ByteArrayOutputStream sbaos = new ByteArrayOutputStream(512);
    1127             sbaos.write(X);
    1128             sbaos.write(Y);
    1129             sbaos.write(bih);
    1130             sbaos.write(DataHelper.toLong(4, tsA));
    1131             sbaos.write(DataHelper.toLong(4, tsB));
    1132             //sbaos.write(pad);
    1133             Signature sig = ctx.dsa().sign(sbaos.toByteArray(), spriv);
    1134             baos.write(sig.toByteArray());
    1135 
    1136             byte unencrypted[] = baos.toByteArray();
    1137             byte toWrite[] = new byte[unencrypted.length];
    1138             System.out.println("unencrypted.length = " + unencrypted.length + " alice.size = " + aliceb.length + " padding = " + padding + " base = " + base);
    1139             ctx.aes().encrypt(unencrypted, 0, toWrite, 0, dh.getSessionKey(), hx_xor_bih, 16, unencrypted.length);
    1140 
    1141             out.write(toWrite);
    1142             out.flush();
    1143 
    1144             System.out.println("unencrypted: " + Base64.encode(unencrypted));
    1145             System.out.println("encrypted: " + Base64.encode(toWrite));
    1146             System.out.println("Local peer: " + alice.calculateHash().toBase64());
    1147 
    1148             // now check bob's signature
    1149 
    1150             SigningPublicKey bobPubKey = null;
    1151             try {
    1152                 RouterInfo info = new RouterInfo();
    1153                 info.readBytes(new FileInputStream("/home/jrandom/routers/router1/netDb/routerInfo-HuRdDx9t-RaZfYkYvacRwP~6s9mvbdkYzIMrpUCsZIo=.dat"));
    1154                 bobPubKey = info.getIdentity().getSigningPublicKey();
    1155             } catch (Exception e) {
    1156                 e.printStackTrace();
    1157                 return;
    1158             }
    1159 
    1160             System.out.println("Reading in bob's sig");
    1161 
    1162             byte bobRead[] = new byte[48];
    1163             read = 0;
    1164             while (read < bobRead.length) {
    1165                 int r = in.read(bobRead, read, bobRead.length-read);
    1166                 if (r == -1)
    1167                     throw new EOFException("eof at read=" + read);
    1168                 read += r;
    1169             }
    1170 
    1171             // bob should have sent E(S(X+Y+Alice.identHash+tsA+tsB)+padding, sk, prev)
    1172             byte preSig[] = new byte[Signature.SIGNATURE_BYTES+8];
    1173             ctx.aes().decrypt(bobRead, 0, preSig, 0, dh.getSessionKey(), toRead, toRead.length-16, preSig.length);
    1174             byte bobSigData[] = new byte[Signature.SIGNATURE_BYTES];
    1175             System.arraycopy(preSig, 0, bobSigData, 0, Signature.SIGNATURE_BYTES); // ignore the padding
    1176             System.out.println("Bob's sig: " + Base64.encode(bobSigData));
    1177 
    1178             byte signed[] = new byte[256+256+32+4+4];
    1179             int off = 0;
    1180             System.arraycopy(X, 0, signed, off, 256); off += 256;
    1181             System.arraycopy(Y, 0, signed, off, 256); off += 256;
    1182             Hash h = alice.calculateHash();
    1183             System.arraycopy(h.getData(), 0, signed, off, 32); off += 32;
    1184             DataHelper.toLong(signed, off, 4, tsA); off += 4;
    1185             DataHelper.toLong(signed, off, 4, tsB); off += 4;
    1186 
    1187             Signature bobSig = new Signature(bobSigData);
    1188             boolean ok = ctx.dsa().verifySignature(bobSig, signed, bobPubKey);
    1189 
    1190             System.out.println("bob's sig matches? " + ok);
    1191 
    1192             try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
    1193             byte fakeI2NPbuf[] = new byte[128];
    1194             ctx.random().nextBytes(fakeI2NPbuf);
    1195             out.write(fakeI2NPbuf);
    1196             out.flush();
    1197 
    1198             try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
    1199             s.close();
    1200         } catch (Exception e) {
    1201             e.printStackTrace();
    1202         }
    1203     }
    1204 *******/
    1205 
    1206     /**
    1207      *  Mark a string for extraction by xgettext and translation.
    1208      *  Use this only in static initializers.
    1209      *  It does not translate!
    1210      *  @return s
    1211      */
    1212     private static final String _x(String s) {
    1213         return s;
    1214     }
    1215 
     61    public Exception getException();
    121662}
  • router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java

    r363aaadb r06106c75  
    191191        _decryptBlockBuf = new byte[BLOCK_SIZE];
    192192        _curReadState = new ReadState();
    193         _establishState = new EstablishState(ctx, transport, this);
     193        _establishState = new InboundEstablishState(ctx, transport, this);
    194194        _conKey = key;
    195195        _conKey.attach(this);
     
    217217        _outbound = new PriBlockingQueue<OutNetMessage>(ctx, "NTCP-Connection", 32);
    218218        _isInbound = false;
    219         _establishState = new EstablishState(ctx, transport, this);
     219        _establishState = new OutboundEstablishState(ctx, transport, this);
    220220        _decryptBlockBuf = new byte[BLOCK_SIZE];
    221221        _curReadState = new ReadState();
     
    310310        _nextMetaTime = _establishedOn + (META_FREQUENCY / 2) + _context.random().nextInt(META_FREQUENCY);
    311311        _nextInfoTime = _establishedOn + (INFO_FREQUENCY / 2) + _context.random().nextInt(INFO_FREQUENCY);
    312         _establishState = EstablishState.VERIFIED;
     312        _establishState = EstablishBase.VERIFIED;
    313313        return rv;
    314314    }
     
    428428        if (_chan != null) try { _chan.close(); } catch (IOException ioe) { }
    429429        if (_conKey != null) _conKey.cancel();
    430         _establishState = EstablishState.FAILED;
     430        _establishState = EstablishBase.FAILED;
    431431        NTCPConnection old = _transport.removeCon(this);
    432432        _transport.getReader().connectionClosed(this);
     
    533533
    534534        _establishedOn = _context.clock().now();
    535         _establishState = EstablishState.VERIFIED;
     535        _establishState = EstablishBase.VERIFIED;
    536536        _transport.markReachable(getRemotePeer().calculateHash(), false);
    537537        boolean msgs = !_outbound.isEmpty();
Note: See TracChangeset for help on using the changeset viewer.