Changeset 5ba86ca


Ignore:
Timestamp:
Jun 22, 2013 7:09:55 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
ac9392b
Parents:
87826da
Message:
  • SSU:
    • Pad all messages with random data instead of zeros
    • Implement non-mod-16 padding, disabled for now
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • history.txt

    r87826da r5ba86ca  
    112013-06-22 zzz
    2  * SSU: Pad session created message with random data instead of zeros
     2 * SSU:
     3   - Pad messages with random data instead of zeros
     4   - Implement non-mod-16 padding, disabled for now
    35
    462013-06-22 meeh
  • router/java/src/net/i2p/router/RouterVersion.java

    r87826da r5ba86ca  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 11;
     21    public final static long BUILD = 12;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/transport/udp/PacketBuilder.java

    r87826da r5ba86ca  
    11package net.i2p.router.transport.udp;
    22
     3import java.net.DatagramPacket;
    34import java.net.InetAddress;
    45import java.net.UnknownHostException;
     
    155156     */
    156157    private static final int MAX_RESEND_ACKS_SMALL = 4;
     158
     159    private static final String PROP_PADDING = "i2np.udp.padding";
    157160
    158161    public PacketBuilder(I2PAppContext ctx, UDPTransport transport) {
     
    223226                                 List<ACKBitfield> partialACKsRemaining) {
    224227        UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4));
    225         byte data[] = packet.getPacket().getData();
     228        DatagramPacket pkt = packet.getPacket();
     229        byte data[] = pkt.getData();
    226230        int off = HEADER_SIZE;
    227231
     
    389393       
    390394        // pad up so we're on the encryption boundary
    391         // we could do additional random padding here if desired
    392         int mod = off % 16;
    393         if (mod > 0) {
    394             int padSize = 16 - mod;
    395             _context.random().nextBytes(data, off, padSize);
    396             off += padSize;
    397         }
    398         packet.getPacket().setLength(off);
     395        off = pad1(data, off);
     396        off = pad2(data, off, currentMTU);
     397        pkt.setLength(off);
    399398
    400399        authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey());
     
    445444    public UDPPacket buildACK(PeerState peer, List<ACKBitfield> ackBitfields) {
    446445        UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4));
    447         byte data[] = packet.getPacket().getData();
     446        DatagramPacket pkt = packet.getPacket();
     447        byte data[] = pkt.getData();
    448448        int off = HEADER_SIZE;
    449449       
     
    522522            _log.debug(msg.toString());
    523523       
    524         // we can pad here if we want, maybe randomized?
    525        
    526524        // pad up so we're on the encryption boundary
    527         if ( (off % 16) != 0)
    528             off += 16 - (off % 16);
    529         packet.getPacket().setLength(off);
     525        off = pad1(data, off);
     526        off = pad2(data, off);
     527        pkt.setLength(off);
    530528        authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey());
    531529        setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort());
     
    547545    public UDPPacket buildSessionCreatedPacket(InboundEstablishState state, int externalPort, SessionKey ourIntroKey) {
    548546        UDPPacket packet = buildPacketHeader(SESSION_CREATED_FLAG_BYTE);
    549         byte data[] = packet.getPacket().getData();
     547        DatagramPacket pkt = packet.getPacket();
     548        byte data[] = pkt.getData();
    550549        int off = HEADER_SIZE;
    551550       
     
    615614       
    616615        // pad up so we're on the encryption boundary
    617         int rem = off & 0x0f;
    618         if (rem != 0) {
    619             // typ. 12 for IPv4 and 0 for IPv6
    620             int pad = 16 - rem;
    621             //_log.debug("Adding padding: " + pad);
    622             _context.random().nextBytes(data, off, pad);
    623             off += pad;
    624         }
    625         packet.getPacket().setLength(off);
     616        off = pad1(data, off);
     617        off = pad2(data, off);
     618        pkt.setLength(off);
    626619        authenticate(packet, ourIntroKey, ourIntroKey, iv);
    627620        setTo(packet, to, state.getSentPort());
     
    645638    public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) {
    646639        UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE);
    647         byte data[] = packet.getPacket().getData();
     640        DatagramPacket pkt = packet.getPacket();
     641        byte data[] = pkt.getData();
    648642        int off = HEADER_SIZE;
    649643
     
    680674       
    681675        // pad up so we're on the encryption boundary
    682         if ( (off % 16) != 0)
    683             off += 16 - (off % 16);
    684         packet.getPacket().setLength(off);
     676        off = pad1(data, off);
     677        off = pad2(data, off);
     678        pkt.setLength(off);
    685679        authenticate(packet, state.getIntroKey(), state.getIntroKey());
    686680        setTo(packet, to, port);
     
    728722     * @return ready to send packets, or null if there was a problem
    729723     */
    730     public UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte identity[]) {
     724    private UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte identity[]) {
    731725        UDPPacket packet = buildPacketHeader(SESSION_CONFIRMED_FLAG_BYTE);
    732         byte data[] = packet.getPacket().getData();
     726        DatagramPacket pkt = packet.getPacket();
     727        byte data[] = pkt.getData();
    733728        int off = HEADER_SIZE;
    734729
     
    765760            off += 4;
    766761           
    767             int paddingRequired = 0;
    768762            // we need to pad this so we're at the encryption boundary
    769             if ( (off + Signature.SIGNATURE_BYTES) % 16 != 0)
    770                 paddingRequired += 16 - ((off + Signature.SIGNATURE_BYTES) % 16);
    771            
    772             // add an arbitrary number of 16byte pad blocks too...
    773            
    774             for (int i = 0; i < paddingRequired; i++) {
    775                 data[off] = (byte)_context.random().nextInt(255);
    776                 off++;
     763            int mod = (off + Signature.SIGNATURE_BYTES) & 0x0f;
     764            if (mod != 0) {
     765                int paddingRequired = 16 - mod;
     766                // add an arbitrary number of 16byte pad blocks too ???
     767                _context.random().nextBytes(data, off, paddingRequired);
     768                off += paddingRequired;
    777769            }
    778770           
     
    781773            off += Signature.SIGNATURE_BYTES;
    782774        } else {
    783             // nothing more to add beyond the identity fragment, though we can
    784             // pad here if we want.  maybe randomized?
    785 
     775            // We never get here (see above)
     776
     777            // nothing more to add beyond the identity fragment
    786778            // pad up so we're on the encryption boundary
    787             // TODO: why not random data?
    788             if ( (off % 16) != 0)
    789                 off += 16 - (off % 16);
     779            off = pad1(data, off);
    790780        }
    791         packet.getPacket().setLength(off);
     781        off = pad2(data, off);
     782        pkt.setLength(off);
    792783        authenticate(packet, state.getCipherKey(), state.getMACKey());
    793        
    794784        setTo(packet, to, state.getSentPort());
    795785        packet.setMessageType(TYPE_CONF);
     
    883873       
    884874        // pad up so we're on the encryption boundary
    885         if ( (off % 16) != 0)
    886             off += 16 - (off % 16);
    887         packet.getPacket().setLength(off);
     875        DatagramPacket pkt = packet.getPacket();
     876        byte data[] = pkt.getData();
     877        off = pad1(data, off);
     878        off = pad2(data, off);
     879        pkt.setLength(off);
    888880        authenticate(packet, cipherKey, macKey);
    889881        setTo(packet, addr, port);
     
    906898        return buildPeerTestFromAlice(toIP, toPort, toIntroKey, toIntroKey, nonce, aliceIntroKey);
    907899    }
    908     public UDPPacket buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey toCipherKey, SessionKey toMACKey, long nonce, SessionKey aliceIntroKey) {
     900
     901    /**
     902     * Build a packet as if we are Alice and we either want Bob to begin a
     903     * peer test or Charlie to finish a peer test.
     904     *
     905     * @return ready to send packet, or null if there was a problem
     906     */
     907    public UDPPacket buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey toCipherKey, SessionKey toMACKey,
     908                                            long nonce, SessionKey aliceIntroKey) {
    909909        UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
    910         byte data[] = packet.getPacket().getData();
     910        DatagramPacket pkt = packet.getPacket();
     911        byte data[] = pkt.getData();
    911912        int off = HEADER_SIZE;
    912913        if (_log.shouldLog(Log.DEBUG))
     
    923924        off += SessionKey.KEYSIZE_BYTES;
    924925       
    925         // we can pad here if we want, maybe randomized?
    926        
    927926        // pad up so we're on the encryption boundary
    928         if ( (off % 16) != 0)
    929             off += 16 - (off % 16);
    930         packet.getPacket().setLength(off);
     927        off = pad1(data, off);
     928        off = pad2(data, off);
     929        pkt.setLength(off);
    931930        authenticate(packet, toCipherKey, toMACKey);
    932931        setTo(packet, toIP, toPort);
     
    942941    public UDPPacket buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, SessionKey charlieIntroKey, long nonce) {
    943942        UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
    944         byte data[] = packet.getPacket().getData();
     943        DatagramPacket pkt = packet.getPacket();
     944        byte data[] = pkt.getData();
    945945        int off = HEADER_SIZE;
    946946        if (_log.shouldLog(Log.DEBUG))
     
    960960        off += SessionKey.KEYSIZE_BYTES;
    961961       
    962         // we can pad here if we want, maybe randomized?
    963        
    964962        // pad up so we're on the encryption boundary
    965         if ( (off % 16) != 0)
    966             off += 16 - (off % 16);
    967         packet.getPacket().setLength(off);
     963        off = pad1(data, off);
     964        off = pad2(data, off);
     965        pkt.setLength(off);
    968966        authenticate(packet, aliceIntroKey, aliceIntroKey);
    969967        setTo(packet, aliceIP, alicePort);
     
    981979                                            SessionKey charlieCipherKey, SessionKey charlieMACKey) {
    982980        UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
    983         byte data[] = packet.getPacket().getData();
     981        DatagramPacket pkt = packet.getPacket();
     982        byte data[] = pkt.getData();
    984983        int off = HEADER_SIZE;
    985984        if (_log.shouldLog(Log.DEBUG))
     
    999998        off += SessionKey.KEYSIZE_BYTES;
    1000999       
    1001         // we can pad here if we want, maybe randomized?
    1002        
    10031000        // pad up so we're on the encryption boundary
    1004         if ( (off % 16) != 0)
    1005             off += 16 - (off % 16);
    1006         packet.getPacket().setLength(off);
     1001        off = pad1(data, off);
     1002        off = pad2(data, off);
     1003        pkt.setLength(off);
    10071004        authenticate(packet, charlieCipherKey, charlieMACKey);
    10081005        setTo(packet, charlieIP, charliePort);
     
    10181015    public UDPPacket buildPeerTestToBob(InetAddress bobIP, int bobPort, InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, SessionKey bobCipherKey, SessionKey bobMACKey) {
    10191016        UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
    1020         byte data[] = packet.getPacket().getData();
     1017        DatagramPacket pkt = packet.getPacket();
     1018        byte data[] = pkt.getData();
    10211019        int off = HEADER_SIZE;
    10221020        if (_log.shouldLog(Log.DEBUG))
     
    10361034        off += SessionKey.KEYSIZE_BYTES;
    10371035       
    1038         // we can pad here if we want, maybe randomized?
    1039        
    10401036        // pad up so we're on the encryption boundary
    1041         if ( (off % 16) != 0)
    1042             off += 16 - (off % 16);
    1043         packet.getPacket().setLength(off);
     1037        off = pad1(data, off);
     1038        off = pad2(data, off);
     1039        pkt.setLength(off);
    10441040        authenticate(packet, bobCipherKey, bobMACKey);
    10451041        setTo(packet, bobIP, bobPort);
     
    10881084    }
    10891085   
    1090     public UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[], long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) {
     1086    private UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[],
     1087                                        long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) {
    10911088        UDPPacket packet = buildPacketHeader(PEER_RELAY_REQUEST_FLAG_BYTE);
    1092         byte data[] = packet.getPacket().getData();
     1089        DatagramPacket pkt = packet.getPacket();
     1090        byte data[] = pkt.getData();
    10931091        int off = HEADER_SIZE;
    10941092       
     
    11311129        off += 4;
    11321130       
    1133         // we can pad here if we want, maybe randomized?
    1134        
    11351131        // pad up so we're on the encryption boundary
    1136         if ( (off % 16) != 0)
    1137             off += 16 - (off % 16);
    1138         packet.getPacket().setLength(off);
     1132        off = pad1(data, off);
     1133        off = pad2(data, off);
     1134        pkt.setLength(off);
    11391135        if (encrypt)
    11401136            authenticate(packet, new SessionKey(introKey), new SessionKey(introKey));
     
    11521148    UDPPacket buildRelayIntro(RemoteHostId alice, PeerState charlie, UDPPacketReader.RelayRequestReader request) {
    11531149        UDPPacket packet = buildPacketHeader(PEER_RELAY_INTRO_FLAG_BYTE);
    1154         byte data[] = packet.getPacket().getData();
     1150        DatagramPacket pkt = packet.getPacket();
     1151        byte data[] = pkt.getData();
    11551152        int off = HEADER_SIZE;
    11561153        if (_log.shouldLog(Log.INFO))
     
    11741171        }
    11751172       
    1176         // we can pad here if we want, maybe randomized?
    1177        
    11781173        // pad up so we're on the encryption boundary
    1179         if ( (off % 16) != 0)
    1180             off += 16 - (off % 16);
    1181         packet.getPacket().setLength(off);
     1174        off = pad1(data, off);
     1175        off = pad2(data, off);
     1176        pkt.setLength(off);
    11821177        authenticate(packet, charlie.getCurrentCipherKey(), charlie.getCurrentMACKey());
    11831178        setTo(packet, charlie.getRemoteIPAddress(), charlie.getRemotePort());
     
    12011196       
    12021197        UDPPacket packet = buildPacketHeader(PEER_RELAY_RESPONSE_FLAG_BYTE);
    1203         byte data[] = packet.getPacket().getData();
     1198        DatagramPacket pkt = packet.getPacket();
     1199        byte data[] = pkt.getData();
    12041200        int off = HEADER_SIZE;
    12051201       
     
    12271223        off += 4;
    12281224       
    1229         // we can pad here if we want, maybe randomized?
    1230        
    12311225        // pad up so we're on the encryption boundary
    1232         if ( (off % 16) != 0)
    1233             off += 16 - (off % 16);
    1234         packet.getPacket().setLength(off);
     1226        off = pad1(data, off);
     1227        off = pad2(data, off);
     1228        pkt.setLength(off);
    12351229        authenticate(packet, aliceIntroKey, aliceIntroKey);
    12361230        setTo(packet, aliceAddr, alice.getPort());
     
    12821276
    12831277    private static void setTo(UDPPacket packet, InetAddress ip, int port) {
    1284         packet.getPacket().setAddress(ip);
    1285         packet.getPacket().setPort(port);
    1286     }
    1287    
     1278        DatagramPacket pkt = packet.getPacket();
     1279        pkt.setAddress(ip);
     1280        pkt.setPort(port);
     1281    }
     1282
     1283    /**
     1284     * Pad up to next 16 byte boundary and return new offset.
     1285     * These bytes will be encrypted.
     1286     * This must be called before encryption.
     1287     *
     1288     * @return new offset
     1289     * @since 0.9.7
     1290     */
     1291    private int pad1(byte[] data, int off) {
     1292        int mod = off & 0x0f;
     1293        if (mod == 0)
     1294            return off;
     1295        int padSize = 16 - mod;
     1296        _context.random().nextBytes(data, off, padSize);
     1297        return off + padSize;
     1298    }
     1299
     1300    /** max is one less */
     1301    private static final int MAX_PAD2 = 16;
     1302
     1303    /**
     1304     * Pad a random amount (not mod 16) and return new offset.
     1305     * Packet must be well under the max length (MTU).
     1306     * These bytes will be included in the MAC calculation but not encrypted.
     1307     * This must be called before encryption.
     1308     *
     1309     * @return new offset
     1310     * @since 0.9.7
     1311     */
     1312    private int pad2(byte[] data, int off) {
     1313        if (!_context.getBooleanProperty(PROP_PADDING))
     1314            return off;
     1315        int padSize = _context.random().nextInt(MAX_PAD2);
     1316        if (padSize == 0)
     1317            return off;
     1318        _context.random().nextBytes(data, off, padSize);
     1319        return off + padSize;
     1320    }
     1321
     1322    /**
     1323     * Pad a random amount (not mod 16) and return new offset,
     1324     * while honoring the max length.
     1325     * These bytes will be included in the MAC calculation but not encrypted.
     1326     * This must be called before encryption.
     1327     *
     1328     * @return new offset
     1329     * @since 0.9.7
     1330     */
     1331    private int pad2(byte[] data, int off, int maxLen) {
     1332        if (!_context.getBooleanProperty(PROP_PADDING))
     1333            return off;
     1334        if (off >= maxLen)
     1335            return off;
     1336        int padSize = _context.random().nextInt(Math.min(MAX_PAD2, 1 + maxLen - off));
     1337        if (padSize == 0)
     1338            return off;
     1339        _context.random().nextBytes(data, off, padSize);
     1340        return off + padSize;
     1341    }
     1342
    12881343    /**
    12891344     * Encrypt the packet with the cipher key and a new random IV, generate a
     
    13091364     *
    13101365     * @param packet prepared packet with the first 32 bytes empty and a length
    1311      *               whose size is mod 16
     1366     *               whose size is mod 16.
     1367     *               As of 0.9.7, length non-mod-16 is allowed; the
     1368     *               last 1-15 bytes are included in the MAC calculation but are not encrypted.
    13121369     * @param cipherKey key to encrypt the payload
    13131370     * @param macKey key to generate the, er, MAC
     
    13161373    private void authenticate(UDPPacket packet, SessionKey cipherKey, SessionKey macKey, byte[] iv) {
    13171374        long before = System.currentTimeMillis();
    1318         int encryptOffset = packet.getPacket().getOffset() + UDPPacket.IV_SIZE + UDPPacket.MAC_SIZE;
    1319         int encryptSize = packet.getPacket().getLength() - UDPPacket.IV_SIZE - UDPPacket.MAC_SIZE - packet.getPacket().getOffset();
    1320         byte data[] = packet.getPacket().getData();
     1375        DatagramPacket pkt = packet.getPacket();
     1376        int off = pkt.getOffset();
     1377        int hmacOff = off;
     1378        int encryptOffset = off + UDPPacket.IV_SIZE + UDPPacket.MAC_SIZE;
     1379        // including 1-15 pad
     1380        int totalSize = pkt.getLength() - UDPPacket.IV_SIZE - UDPPacket.MAC_SIZE - off;
     1381        int mod = totalSize & 0x0f;
     1382        // not including 1-15 pad
     1383        int encryptSize = totalSize - mod;
     1384        byte data[] = pkt.getData();
    13211385        _context.aes().encrypt(data, encryptOffset, data, encryptOffset, cipherKey, iv, encryptSize);
    13221386       
    13231387        // ok, now we need to prepare things for the MAC, which requires reordering
    1324         int off = packet.getPacket().getOffset();
    1325         System.arraycopy(data, encryptOffset, data, off, encryptSize);
    1326         off += encryptSize;
     1388        // Payload + IV + payloadLength
     1389        System.arraycopy(data, encryptOffset, data, off, totalSize);
     1390        off += totalSize;
    13271391        System.arraycopy(iv, 0, data, off, UDPPacket.IV_SIZE);
    13281392        off += UDPPacket.IV_SIZE;
    1329         DataHelper.toLong(data, off, 2, encryptSize /* ^ PROTOCOL_VERSION */ );
    1330        
    1331         int hmacOff = packet.getPacket().getOffset();
    1332         int hmacLen = encryptSize + UDPPacket.IV_SIZE + 2;
     1393        DataHelper.toLong(data, off, 2, totalSize /* ^ PROTOCOL_VERSION */ );
     1394       
     1395        int hmacLen = totalSize + UDPPacket.IV_SIZE + 2;
    13331396        //Hash hmac = _context.hmac().calculate(macKey, data, hmacOff, hmacLen);
    13341397        byte[] ba = SimpleByteCache.acquire(Hash.HASH_LENGTH);
     
    13361399       
    13371400        if (_log.shouldLog(Log.DEBUG))
    1338             _log.debug("Authenticating " + packet.getPacket().getLength() +
     1401            _log.debug("Authenticating " + pkt.getLength() +
    13391402                       "\nIV: " + Base64.encode(iv) +
    13401403                       "\nraw mac: " + Base64.encode(ba) +
    13411404                       "\nMAC key: " + macKey);
    13421405        // ok, now lets put it back where it belongs...
    1343         System.arraycopy(data, hmacOff, data, encryptOffset, encryptSize);
     1406        // MAC + IV + payload
     1407        System.arraycopy(data, hmacOff, data, encryptOffset, totalSize);
    13441408        //System.arraycopy(hmac.getData(), 0, data, hmacOff, UDPPacket.MAC_SIZE);
    13451409        System.arraycopy(ba, 0, data, hmacOff, UDPPacket.MAC_SIZE);
     1410        SimpleByteCache.release(ba);
    13461411        System.arraycopy(iv, 0, data, hmacOff + UDPPacket.MAC_SIZE, UDPPacket.IV_SIZE);
    1347         SimpleByteCache.release(ba);
    13481412        long timeToAuth = System.currentTimeMillis() - before;
    13491413        _context.statManager().addRateData("udp.packetAuthTime", timeToAuth, timeToAuth);
Note: See TracChangeset for help on using the changeset viewer.