NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
// create custom RSA factories
SignatureFactory factory = new H2HSignatureFactory();
SignatureCodec codec = new H2HSignatureCodec();
// replace default signature factories
ChannelClientConfiguration clientConfig = PeerMaker.createDefaultChannelClientConfiguration();
clientConfig.signatureFactory(factory);
ChannelServerConficuration serverConfig = PeerMaker.createDefaultChannelServerConfiguration();
serverConfig.signatureFactory(factory);
KeyPair keyPairPeer1 = gen.generateKeyPair();
Peer p1 = new PeerMaker(Number160.createHash(1)).ports(4834).keyPair(keyPairPeer1)
.setEnableIndirectReplication(true).channelClientConfiguration(clientConfig)
.channelServerConfiguration(serverConfig).makeAndListen();
KeyPair keyPairPeer2 = gen.generateKeyPair();
Peer p2 = new PeerMaker(Number160.createHash(2)).masterPeer(p1).keyPair(keyPairPeer2)
.setEnableIndirectReplication(true).channelClientConfiguration(clientConfig)
.channelServerConfiguration(serverConfig).makeAndListen();
p2.bootstrap().setPeerAddress(p1.getPeerAddress()).start().awaitUninterruptibly();
p1.bootstrap().setPeerAddress(p2.getPeerAddress()).start().awaitUninterruptibly();
KeyPair keyPair1 = gen.generateKeyPair();
KeyPair keyPair2 = gen.generateKeyPair();
Number160 lKey = Number160.createHash("location");
Number160 dKey = Number160.createHash("domain");
Number160 cKey = Number160.createHash("content");
Number160 vKey = Number160.createHash("version");
Number160 bKey = Number160.createHash("based on");
int ttl = 10;
// initial put with data signature and entry protection
Data intialData = new Data("data").setProtectedEntry();
intialData.ttlSeconds(ttl).basedOn(bKey).sign(keyPair1, factory);
// put using content protection key 1 to sign message
FuturePut futureIntialPut = p1.put(lKey).setDomainKey(dKey).setData(cKey, intialData)
.setVersionKey(vKey).keyPair(keyPair1).start();
futureIntialPut.awaitUninterruptibly();
Assert.assertTrue(futureIntialPut.isSuccess());
// verify put
Data retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify data signature
Assert.assertTrue(retData.verify(keyPair1.getPublic(), factory));
// try to overwrite without content protection and data signature (expected to fail)
Data data = new Data("dataA");
data.ttlSeconds(ttl).basedOn(bKey).sign(keyPair1, factory);
// put using content protection key 1 to sign message
FuturePut futureTryOverwrite = p1.put(lKey).setDomainKey(dKey).setData(cKey, data)
.setVersionKey(vKey).start();
futureTryOverwrite.awaitUninterruptibly();
Assert.assertFalse(futureTryOverwrite.isSuccess());
// verify that nothing changed
retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify that data signature is still the same
Assert.assertTrue(retData.verify(keyPair1.getPublic(), factory));
// try to overwrite with wrong protection keys 2 and data signature (expected to fail)
data = new Data("dataB").setProtectedEntry();
data.ttlSeconds(ttl).basedOn(bKey).sign(keyPair1, factory);
// put using wrong content protection keys 2 to sign message
futureTryOverwrite = p1.put(lKey).setDomainKey(dKey).setData(cKey, data).setVersionKey(vKey)
.keyPair(keyPair2).start();
futureTryOverwrite.awaitUninterruptibly();
Assert.assertFalse(futureTryOverwrite.isSuccess());
// verify that nothing changed
retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify that data signature is still the same
Assert.assertTrue(retData.verify(keyPair1.getPublic(), factory));
// try to overwrite without content protection and without data signature (expected to fail)
data = new Data("dataC");
data.ttlSeconds(ttl).basedOn(bKey).sign(keyPair1, factory);
// put using wrong content protection keys 2 to sign message
futureTryOverwrite = p1.put(lKey).setDomainKey(dKey).setData(cKey, data).setVersionKey(vKey).start();
futureTryOverwrite.awaitUninterruptibly();
Assert.assertFalse(futureTryOverwrite.isSuccess());
// verify that nothing changed
retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify that data signature is still the same
Assert.assertTrue(retData.verify(keyPair1.getPublic(), factory));
// try to overwrite with wrong protection keys 2 and without data signature (expected to fail)
data = new Data("dataD").setProtectedEntry();
data.ttlSeconds(ttl).basedOn(bKey).sign(keyPair1, factory);
// put using wrong content protection keys 2 to sign message
futureTryOverwrite = p1.put(lKey).setDomainKey(dKey).setData(cKey, data).setVersionKey(vKey)
.keyPair(keyPair2).start();
futureTryOverwrite.awaitUninterruptibly();
Assert.assertFalse(futureTryOverwrite.isSuccess());
// verify that nothing changed
retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify that data signature is still the same
Assert.assertTrue(retData.verify(keyPair1.getPublic(), factory));
// overwrite with content protection keys 1 and no data signature
intialData = new Data("data2").setProtectedEntry();
intialData.ttlSeconds(ttl).basedOn(bKey);
// put using content protection key 1 to sign message
FuturePut futureOverwrite1 = p1.put(lKey).setDomainKey(dKey).setData(cKey, intialData)
.setVersionKey(vKey).keyPair(keyPair1).start();
futureOverwrite1.awaitUninterruptibly();
Assert.assertTrue(futureOverwrite1.isSuccess());
// verify overwrite
retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data2", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify no signature
Assert.assertNull(retData.signature());
// overwrite with content protection key1 and with data signature
intialData = new Data("data3").setProtectedEntry();
intialData.ttlSeconds(ttl).basedOn(bKey).sign(keyPair1, factory);
// put using content protection key 1 to sign message
FuturePut futureOverwrite2 = p1.put(lKey).setDomainKey(dKey).setData(cKey, intialData)
.setVersionKey(vKey).keyPair(keyPair1).start();
futureOverwrite2.awaitUninterruptibly();
Assert.assertTrue(futureOverwrite2.isSuccess());
// verify overwrite
retData = p1.get(lKey).setDomainKey(dKey).setContentKey(cKey).setVersionKey(vKey).start()
.awaitUninterruptibly().getData();
Assert.assertEquals("data3", (String) retData.object());
Assert.assertEquals(keyPair1.getPublic(), retData.publicKey());
// verify that data signature is still the same
Assert.assertTrue(retData.verify(keyPair1.getPublic(), factory));
// create signature with keys 1 having the data object
byte[] signature1 = factory.sign(keyPair1.getPrivate(), intialData.buffer()).encode();
// decrypt signature to get hash of the object
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, keyPair1.getPublic());
byte[] hash = rsa.doFinal(signature1);
// encrypt hash with new key pair to get the new signature (without having the data object)
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, keyPair2.getPrivate());
byte[] signatureNew = rsa.doFinal(hash);
// change data signature to keys 2, assign the reused hash from signature
data = new Data().ttlSeconds(ttl).signature(codec.decode(signatureNew)).setProtectedEntry();
// don't forget to set signed flag, create meta data
data.signed(true).duplicateMeta();
// put meta using content content protection key 1 to sign message
FuturePut futurePutMeta = p1.put(lKey).setDomainKey(dKey).putMeta().setData(cKey, data)
.setVersionKey(vKey).keyPair(keyPair1).start();