package mobisocial.musubi.encoding;
import mobisocial.crypto.IBEncryptionScheme;
import mobisocial.crypto.IBHashedIdentity;
import mobisocial.crypto.IBHashedIdentity.Authority;
import mobisocial.crypto.IBIdentity;
import mobisocial.crypto.IBSignatureScheme;
import mobisocial.musubi.encoding.TransientTransportDataProvider.BlacklistProvider;
import mobisocial.musubi.encoding.TransientTransportDataProvider.EncryptionController;
import mobisocial.musubi.encoding.TransientTransportDataProvider.SignatureController;
import mobisocial.musubi.model.MEncodedMessage;
import mobisocial.musubi.model.MIdentity;
import mobisocial.musubi.util.Util;
import mobisocial.test.TestBase;
public class EncodingTest extends TestBase {
IBEncryptionScheme encryptionScheme_ = new IBEncryptionScheme();
IBSignatureScheme signatureScheme_ = new IBSignatureScheme();
public void testSelfMessageDetectedAsDuplicate() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { om.fromIdentity_ };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp);
try {
decoder.processMessage(encodedIncoming);
fail("this should have been detected as a duplicate");
} catch (DiscardMessage.Duplicate e) {
//GOOD!
} catch (DiscardMessage e) {
throw e;
} catch (NeedsKey e) {
throw e;
}
}
public void testSelfMessageAcrossDevices() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_device0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
TransientTransportDataProvider tdp_device1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_device0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_device0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { om.fromIdentity_ };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_device1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_device1);
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
} catch (Exception e) {
throw e;
}
assertMessagesEqual(om, im);
}
public void testMessageBetweenFriends() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity you = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_user0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
TransientTransportDataProvider tdp_user1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, you, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_user0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_user0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { tdp_user0.addClaimedIdentity(you) };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_user1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_user1);
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
} catch (Exception e) {
throw e;
}
assertMessagesEqual(om, im);
}
public void testBroadcastMessageBetweenFriends() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity you = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_user0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
TransientTransportDataProvider tdp_user1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, you, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_user0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_user0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { tdp_user0.addClaimedIdentity(you) };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
//this changes the signature, computation, so we use this
//test to verify that it works right
om.blind_ = true;
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_user1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_user1);
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
} catch (Exception e) {
throw e;
}
assertMessagesEqual(om, im);
}
public void testMessageMisrouted() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity you = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity bob = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_user0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
TransientTransportDataProvider tdp_user1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, you, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_user0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_user0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { tdp_user0.addClaimedIdentity(bob) };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_user1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_user1);
@SuppressWarnings("unused")
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
fail("message was not addressed to you and this should have failed");
} catch(DiscardMessage.NotToMe e) {
//GOOD!
} catch (Exception e) {
throw e;
}
}
public void testMessageBlacklist() throws Exception {
final IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity you = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_user0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
BlacklistProvider blacklist = new BlacklistProvider() {
public boolean isBlacklisted(IBHashedIdentity hid) {
return hid.equals(me);
}
};
TransientTransportDataProvider tdp_user1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, you, blacklist, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_user0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_user0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { tdp_user0.addClaimedIdentity(you) };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_user1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_user1);
@SuppressWarnings("unused")
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
fail("message to a blacklisted user, this should have failed");
} catch(DiscardMessage.Blacklist e) {
//GOOD!
} catch (Exception e) {
throw e;
}
}
public void testMissingSigningKey() throws Exception {
final IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity you = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
SignatureController signature_controller = new SignatureController() {
public int t = 0;
public long signingTime(IBHashedIdentity hid) {
return t++;
}
public boolean hasSignatureKey(IBHashedIdentity hid) {
return hid.temporalFrame_ == 0;
}
};
TransientTransportDataProvider tdp_user0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, signature_controller, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_user0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_user0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { tdp_user0.addClaimedIdentity(you) };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
@SuppressWarnings("unused")
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//second time it will try with the new signing time, which should fail
try {
encodedOutgoing = encoder.processMessage(om);
fail("signature key should not have been available");
} catch(NeedsKey.Signature e) {
//GOOD!
} catch (Exception e) {
throw e;
}
}
public void testMissingEncryptionKey() throws Exception {
final IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
IBIdentity you = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
EncryptionController encryption_controller = new EncryptionController() {
public int t = 0;
public long encryptionTime(IBHashedIdentity hid) {
return t++;
}
public boolean hasEncryptionKey(IBHashedIdentity hid) {
return hid.temporalFrame_ == 0;
}
};
TransientTransportDataProvider tdp_user0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, encryption_controller);
TransientTransportDataProvider tdp_user1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, you, null, null, encryption_controller);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_user0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_user0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { tdp_user0.addClaimedIdentity(you) };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
MEncodedMessage encodedOutgoingUnreadable;
//second time it will try with the new signing time, which should fail
try {
encodedOutgoingUnreadable = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_user1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_user1);
@SuppressWarnings("unused")
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
} catch(DiscardMessage.Blacklist e) {
//GOOD!
} catch (Exception e) {
throw e;
}
//try to decode the one we wont have a key for
encodedIncoming = tdp_user1.insertEncodedMessage(encodedOutgoingUnreadable.encoded_);
try {
im = decoder.processMessage(encodedIncoming);
fail("message should have needed a different encryption key");
} catch(NeedsKey.Encryption e) {
//GOOD!
} catch (Exception e) {
throw e;
}
}
public void testCorruptedPacket() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_device0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
TransientTransportDataProvider tdp_device1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_device0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_device0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { om.fromIdentity_ };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
for(int i = 0; i < encodedOutgoing.encoded_.length; ++i) {
encodedOutgoing.encoded_[i] += 37;
}
//pop the message into the transient provider
MEncodedMessage encodedIncoming = tdp_device1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_device1);
try {
decoder.processMessage(encodedIncoming);
fail("this should have been detected as corrupted");
} catch (DiscardMessage.Corrupted e) {
//GOOD!
} catch (Exception e) {
throw e;
}
}
public void testCorruptedBody() throws Exception {
IBIdentity me = new IBIdentity(Authority.Email, randomUniquePrincipal(), 0);
TransientTransportDataProvider tdp_device0 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
TransientTransportDataProvider tdp_device1 = new TransientTransportDataProvider(encryptionScheme_, signatureScheme_, me, null, null, null);
//encode a message
MessageEncoder encoder = new MessageEncoder(tdp_device0);
OutgoingMessage om = new OutgoingMessage();
om.fromIdentity_ = tdp_device0.addClaimedIdentity(me);
om.recipients_ = new MIdentity[] { om.fromIdentity_ };
om.data_ = new byte[16];
r.nextBytes(om.data_);
om.app_ = new byte[32];
r.nextBytes(om.app_);
om.hash_ = Util.sha256(om.data_);
MEncodedMessage encodedOutgoing;
try {
encodedOutgoing = encoder.processMessage(om);
} catch (Exception e) {
throw e;
}
//pop the message into the transient provider
encodedOutgoing.encoded_[encodedOutgoing.encoded_.length - 17] += 37;
MEncodedMessage encodedIncoming = tdp_device1.insertEncodedMessage(encodedOutgoing.encoded_);
//decode it
MessageDecoder decoder = new MessageDecoder(tdp_device1);
@SuppressWarnings("unused")
IncomingMessage im;
try {
im = decoder.processMessage(encodedIncoming);
} catch (DiscardMessage.BadSignature e) {
//GOOD!
} catch (Exception e) {
throw e;
}
}
}