tomp2p / TomP2P

A P2P-based high performance key-value pair storage library
http://tomp2p.net
Apache License 2.0
438 stars 122 forks source link

Protection not really working? #104

Closed Menooker closed 9 years ago

Menooker commented 9 years ago

When I used a keypair to protect an entry, I found that there are still chances that the peer with a wrong key can overwrite the protected entry after several trials. Here are my test codes, which are almost the same as dht/TestSecurity.java

This line should show the problem. assertEquals(testData1, (String) futureGet2.data().object()); peer1 protects the entry with keyPairData. But peer2 can modify it with its own key. I'm using version 5.0 beta 7

///////////////////////////////////////////////////////////////////////////

static void assertFalse(boolean t) throws Exception {
    assertTrue(!t);
}

static void assertTrue(boolean t) throws Exception {
    if (!t) {
        Exception e = new Exception();
        throw e;
    }
}

static void assertEquals(String a, String b) throws Exception {
    if (!a.equals(b)) {
        System.out.println(a);
        System.out.println(b);
        Exception e = new Exception();
        throw e;
    }
}

static void Test() {
    KeyPairGenerator keyGen;
    PeerDHT p1 = null, p2 = null;
    try {
        keyGen = KeyPairGenerator.getInstance("DSA");

        KeyPair keyPairPeer1 = keyGen.generateKeyPair();
        KeyPair keyPairPeer2 = keyGen.generateKeyPair();
        KeyPair keyPairData = keyGen.generateKeyPair();

        p1 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash(1))
                .ports(4838).keyPair(keyPairPeer1).start()).start();

        p1.peer().bootstrap().peerAddress(p1.peerAddress()).start()
                .awaitUninterruptibly();
        p1.storageLayer().protection(ProtectionEnable.ALL, ProtectionMode.MASTER_PUBLIC_KEY, ProtectionEnable.ALL,
                ProtectionMode.MASTER_PUBLIC_KEY);
        String locationKey = "location";
        Number160 lKey = Number160.createHash(locationKey);
        String contentKey = "content";
        Number160 cKey = Number160.createHash(contentKey);

        String testData1 = "data1";
        Data data = new Data(testData1).protectEntry(keyPairData);
        // put trough peer 1 with key pair
        // -------------------------------------------------------
        FuturePut futurePut1 = p1.put(lKey).data(cKey, data)
                .keyPair(keyPairData).start();
        futurePut1.awaitUninterruptibly();
        assertTrue(futurePut1.isSuccess());

        FutureGet futureGet1a = p1.get(lKey).contentKey(cKey).start();
        futureGet1a.awaitUninterruptibly();

        // put trough peer 2 without key pair
        // ----------------------------------------------------
        for(int i=0;i<20;i++)
        {
            System.out.println(i);

            p2 = new PeerBuilderDHT(new PeerBuilder(Number160.createHash(2)).keyPair(keyPairPeer2).start())
            .start();

            p2.peer().bootstrap().peerAddress(p1.peerAddress()).start()
            .awaitUninterruptibly();

            String testData2 = "data2";
            Data data2 = new Data(testData2);
            FuturePut futurePut2 = p2.put(lKey).data(cKey, data2).keyPair(keyPairPeer2).start();
            futurePut2.awaitUninterruptibly();
            // PutStatus.FAILED_SECURITY
            assertFalse(futurePut2.isSuccess());

            FutureGet futureGet2 = p2.get(lKey).contentKey(cKey).start();
            futureGet2.awaitUninterruptibly();
            assertTrue(futureGet2.isSuccess());
            // should have been not modified
            assertEquals(testData1, (String) futureGet2.data().object());
            // put trough peer 1 without key pair
            // ----------------------------------------------------
            p2.shutdown();

        }

    } catch (Exception e) {
        e.printStackTrace();
    }
    finally
    {
        if(p1!=null)
            p1.shutdown();
        if(p2!=null)
            p2.shutdown();
    }

}

public static void main(String[] args) throws Exception {
    Test();
    System.out.println("OK");
}
tbocek commented 9 years ago

Its not a bug, its a feature :)

Peer 2 only fails to store the data on Peer 1, but it can store the data on itself (which happens if you have a small network). The get() then fetches any both content, from Peer 1 and Peer 2 and the evaluation mechanism will return the data from Peer2, thus giving you the impression that you overwrote a protected entry.

Please note that the protection is "best effort" security, and any malicious peer can ignore this. Thus, removing data will always be possible with malicious peers.

Menooker commented 9 years ago

@tbocek Thanks for your replying. This is my first issue submitted on github. ^.^ So I guess there is no reliable mechanism in tomp2p so far to make sure 'get()' returns the original data before peer2 'overwrites' the entry?

Menooker commented 9 years ago

If my program needs a more reliable way to protect the entries, could you tell me how to do so?

tbocek commented 9 years ago

@Menooker You could do a get first, before you do a put to see what content is already available. So peer 2 would make a get first, see that there is already something stored, so it won't make the put.