package mobisocial.musubi.encoding; import gnu.trove.list.array.TByteArrayList; import gnu.trove.list.linked.TLongLinkedList; import gnu.trove.map.hash.TLongLongHashMap; import gnu.trove.map.hash.TLongObjectHashMap; import gnu.trove.map.hash.TObjectLongHashMap; import gnu.trove.procedure.TLongLongProcedure; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Random; import mobisocial.crypto.IBEncryptionScheme; import mobisocial.crypto.IBHashedIdentity; import mobisocial.crypto.IBHashedIdentity.Authority; import mobisocial.crypto.IBIdentity; import mobisocial.crypto.IBSignatureScheme; import mobisocial.musubi.model.MDevice; import mobisocial.musubi.model.MEncodedMessage; import mobisocial.musubi.model.MIdentity; import mobisocial.musubi.model.MIncomingSecret; import mobisocial.musubi.model.MOutgoingSecret; import org.javatuples.Pair; import org.javatuples.Quartet; import org.javatuples.Triplet; public class TransientTransportDataProvider implements TransportDataProvider { public interface BlacklistProvider { boolean isBlacklisted(IBHashedIdentity hid); } public interface SignatureController { boolean hasSignatureKey(IBHashedIdentity hid); long signingTime(IBHashedIdentity hid); } public interface EncryptionController { boolean hasEncryptionKey(IBHashedIdentity hid); long encryptionTime(IBHashedIdentity hid); } IBEncryptionScheme encryptionScheme_; IBSignatureScheme signatureScheme_; SignatureController signatureController_; EncryptionController encryptionController_; long deviceName_ = new Random().nextLong(); IBIdentity me_; TLongObjectHashMap<MIdentity> identities_ = new TLongObjectHashMap<MIdentity>(); HashMap<Pair<Authority, TByteArrayList>, MIdentity> identityLookup_ = new HashMap<Pair<Authority, TByteArrayList>, MIdentity>(); BlacklistProvider blacklist_; TLongObjectHashMap<MDevice> devices_ = new TLongObjectHashMap<MDevice>(); HashMap<Pair<Long /*id*/, Long /*dev*/>, MDevice> deviceLookup_ = new HashMap<Pair<Long,Long>, MDevice>(); HashMap<Pair<Long /*from*/, Long /*device*/>, TLongLinkedList> missingSequenceNumber_ = new HashMap<Pair<Long,Long>, TLongLinkedList>(); HashMap<TByteArrayList, MEncodedMessage> encodedMessageLookup_ = new HashMap<TByteArrayList, MEncodedMessage>(); TLongObjectHashMap<MEncodedMessage> encodedMessages_ = new TLongObjectHashMap<MEncodedMessage>(); HashMap< Quartet<Long /*from*/, Long /*to*/, Long /*sign time*/, Long /*enc time*/>, MOutgoingSecret > outgoingSecrets_ = new HashMap<Quartet<Long, Long, Long, Long>, MOutgoingSecret>(); HashMap< Triplet<Long /*from*/, Long /*to*/, TByteArrayList /*sig*/>, MIncomingSecret > incomingSecrets_ = new HashMap<Triplet<Long, Long, TByteArrayList>, MIncomingSecret>(); TObjectLongHashMap<Pair<Long /*to*/, Long /*seq*/>> encodedMessageForPersonBySequenceNumber = new TObjectLongHashMap<Pair<Long,Long>>(); /* pass in an encryption scheme because you need on identity provider per user */ public TransientTransportDataProvider(IBEncryptionScheme encryptionScheme, IBSignatureScheme signatureScheme, IBIdentity me, BlacklistProvider blacklist, SignatureController signatureController, EncryptionController encryptionController) { encryptionScheme_ = encryptionScheme; signatureScheme_ = signatureScheme; me_ = me; if(blacklist != null) { blacklist_ = blacklist; } else { //default to blank blacklist blacklist_ = new BlacklistProvider() { public boolean isBlacklisted(IBHashedIdentity hid) { return false; } }; } if(signatureController != null) { signatureController_ = signatureController; } else { signatureController_ = new SignatureController() { public boolean hasSignatureKey(IBHashedIdentity hid) { return true; } public long signingTime(IBHashedIdentity hid) { return ByteBuffer.wrap(hid.hashed_).getLong(); } }; } if(encryptionController != null) { encryptionController_ = encryptionController; } else { encryptionController_ = new EncryptionController() { public boolean hasEncryptionKey(IBHashedIdentity hid) { return true; } public long encryptionTime(IBHashedIdentity hid) { return ByteBuffer.wrap(hid.hashed_).getLong(); } }; } MIdentity ident = new MIdentity(); ident.id_ = identities_.size() + 1; ident.claimed_ = true; ident.owned_ = true; ident.type_ = Authority.Email; ident.principal_ = me_.principal_; ident.principalHash_ = me_.hashed_; ident.principalShortHash_ = ByteBuffer.wrap(me_.hashed_).getLong(); identities_.put(ident.id_, ident); identityLookup_.put(Pair.with(ident.type_, new TByteArrayList(ident.principalHash_)), ident); addDevice(ident, deviceName_); } public IBEncryptionScheme getEncryptionScheme() { return encryptionScheme_; } public IBSignatureScheme getSignatureScheme() { return signatureScheme_; } public IBSignatureScheme.UserKey getSignatureKey(MIdentity from, IBHashedIdentity me) throws NeedsKey.Signature { if(!signatureController_.hasSignatureKey(me)) throw new NeedsKey.Signature(me); return signatureScheme_.userKey(me); } public IBEncryptionScheme.UserKey getEncryptionKey(MIdentity to, IBHashedIdentity me) throws NeedsKey.Encryption { if(!encryptionController_.hasEncryptionKey(me)) throw new NeedsKey.Encryption(me); return encryptionScheme_.userKey(me); } public long getSignatureTime(MIdentity from) { return signatureController_.signingTime(new IBHashedIdentity(from.type_, from.principalHash_, 0)); } public long getEncryptionTime(MIdentity to) { return encryptionController_.encryptionTime(new IBHashedIdentity(to.type_, to.principalHash_, 0)); } public long getDeviceName() { return deviceName_; } public MIdentity addUnclaimedIdentity(IBHashedIdentity hid) { MIdentity ident = identityLookup_.get(Pair.with(hid.authority_, new TByteArrayList(hid.hashed_))); if(ident != null) return ident; ident = new MIdentity(); ident.id_ = identities_.size() + 1; ident.claimed_ = false; ident.owned_ = false; ident.type_ = Authority.Email; ident.principalHash_ = hid.hashed_; ident.principalShortHash_ = ByteBuffer.wrap(hid.hashed_).getLong(); identities_.put(ident.id_, ident); identityLookup_.put(Pair.with(ident.type_, new TByteArrayList(ident.principalHash_)), ident); return ident; } public MIdentity addClaimedIdentity(IBHashedIdentity hid) { MIdentity ident = identityLookup_.get(Pair.with(hid.authority_, new TByteArrayList(hid.hashed_))); if(ident != null) return ident; ident = new MIdentity(); ident.id_ = identities_.size() + 1; ident.claimed_ = true; ident.owned_ = false; ident.type_ = Authority.Email; ident.principalHash_ = hid.hashed_; ident.principalShortHash_ = ByteBuffer.wrap(hid.hashed_).getLong(); identities_.put(ident.id_, ident); identityLookup_.put(Pair.with(ident.type_, new TByteArrayList(ident.principalHash_)), ident); return ident; } public MDevice addDevice(MIdentity ident, long deviceName) { MDevice d = deviceLookup_.get(Pair.with(ident.id_, deviceName)); if(d != null) return d; d = new MDevice(); d.id_ = devices_.size() + 1; d.identityId_ = ident.id_; d.deviceName_ = deviceName; d.maxSequenceNumber_ = -1; devices_.put(d.id_, d); deviceLookup_.put(Pair.with(d.identityId_, d.deviceName_), d); return d; } public MEncodedMessage insertEncodedMessage(byte[] encodedData) { MEncodedMessage encoded = new MEncodedMessage(); encoded.encoded_ = encodedData; encodedMessages_.put(encoded.id_, encoded); return encoded; } public MOutgoingSecret lookupOutgoingSecret(MIdentity from, MIdentity to, IBHashedIdentity me, IBHashedIdentity you) { return outgoingSecrets_.get(new Quartet<Long, Long, Long, Long>(from.id_, to.id_, me.temporalFrame_, you.temporalFrame_)); } public void insertOutgoingSecret(IBHashedIdentity me, IBHashedIdentity you, MOutgoingSecret os) { outgoingSecrets_.put(new Quartet<Long, Long, Long, Long>(os.myIdentityId_, os.otherIdentityId_, me.temporalFrame_, you.temporalFrame_), os); } public MIncomingSecret lookupIncomingSecret(MIdentity from, MDevice fromDevice, MIdentity to, byte[] signature, IBHashedIdentity you, IBHashedIdentity me) { return incomingSecrets_.get(new Quartet<Long, Long, TByteArrayList, IBHashedIdentity>(fromDevice.id_, to.id_, new TByteArrayList(signature), you)); } public void insertIncomingSecret(IBHashedIdentity you, IBHashedIdentity me, MIncomingSecret is) { incomingSecrets_.put(new Triplet<Long, Long, TByteArrayList>(is.deviceId_, is.myIdentityId_, new TByteArrayList(is.signature_)), is); } public void incrementSequenceNumber(MIdentity to) { MIdentity ident = identities_.get(to.id_); ident.nextSequenceNumber_++; } public void storeSequenceNumbers(final MEncodedMessage encoded, TLongLongHashMap sequence_numbers) { sequence_numbers.forEachEntry(new TLongLongProcedure() { public boolean execute(long identityId, long sequenceNumber) { encodedMessageForPersonBySequenceNumber.put(Pair.with(identityId, sequenceNumber), encoded.id_); return true; } }); } public void receivedSequenceNumber(MDevice from, long sequenceNumber) { Pair<Long, Long> k = new Pair<Long, Long>(from.identityId_, from.deviceName_); long maxSequenceNumber = devices_.get(from.id_).maxSequenceNumber_; if(sequenceNumber > maxSequenceNumber) devices_.get(from.id_).maxSequenceNumber_ = maxSequenceNumber; TLongLinkedList missing = missingSequenceNumber_.get(k); if(missing != null) missing.remove(sequenceNumber); if(sequenceNumber > maxSequenceNumber + 1) { if(missing == null) { missing = new TLongLinkedList(); missingSequenceNumber_.put(k, missing); } for(long q = maxSequenceNumber + 1; q < sequenceNumber; ++q) { missing.add(q); } } } public boolean haveHash(byte[] hash) { MEncodedMessage encoded = encodedMessageLookup_.get(new TByteArrayList(hash)); return encoded != null; } public boolean isBlacklisted(MIdentity from) { return blacklist_.isBlacklisted(new IBHashedIdentity(from.type_, from.principalHash_, 0)); } public boolean isMe(IBHashedIdentity ibHashedIdentity) { return ibHashedIdentity.equalsStable(me_); } public void updateEncodedMetadata(MEncodedMessage encoded) { encodedMessageLookup_.put(new TByteArrayList(encoded.hash_), encoded); } public void insertEncodedMessage(OutgoingMessage om, MEncodedMessage encoded) { assert(encoded.id_ == 0); encodedMessages_.put(encoded.id_, encoded); encodedMessageLookup_.put(new TByteArrayList(encoded.hash_), encoded); } @Override public void setTransactionSuccessful() { } @Override public void beginTransaction() { } @Override public void endTransaction() { } }