package iotcloud; import java.util.HashMap; import java.util.Arrays; import javax.crypto.spec.*; import javax.crypto.*; public class Table { int numslots; HashMap table=new HashMap(); HashMap lastmessage=new HashMap(); SlotBuffer buffer; CloudComm cloud; private Mac hmac; long sequencenumber; long machineid; public Table(String baseurl, String password, long _machineid) { machineid=_machineid; buffer = new SlotBuffer(); sequencenumber = 1; initCloud(baseurl, password); } private void initCloud(String baseurl, String password) { try { SecretKeySpec secret=getKey(password); Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); encryptCipher.init(Cipher.ENCRYPT_MODE, secret); Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); decryptCipher.init(Cipher.DECRYPT_MODE, secret); hmac = Mac.getInstance("HmacSHA256"); hmac.init(secret); cloud=new CloudComm(baseurl, encryptCipher, decryptCipher, hmac); } catch (Exception e) { throw new Error("Failed To Initialize Ciphers"); } } private SecretKeySpec getKey(String password) { try { PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray()); SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec); SecretKeySpec secret = new SecretKeySpec(key.getEncoded(), "AES"); return secret; } catch (Exception e) { throw new Error("Failed generating key."); } } public void update() { Slot[] newslots=cloud.getSlots(sequencenumber); validateandupdate(newslots); } void validateandupdate(Slot[] newslots) { //The cloud communication layer has checked slot HMACs already //before decoding if (newslots.length==0) return; long firstseqnum=newslots[0].getSequenceNumber(); if (firstseqnum < sequencenumber) throw new Error("Server Error: Sent older slots!"); SlotIndexer indexer = new SlotIndexer(newslots, buffer); checkHMACChain(indexer, newslots); for(Slot slot: newslots) { processSlot(indexer, slot); } } void processEntry(KeyValue entry, SlotIndexer indexer, Slot slot) { IoTString key=entry.getKey(); KeyValue oldvalue=table.get(key); if (oldvalue != null) { oldvalue.setDead(); } table.put(key, entry); } void processEntry(LastMessage entry, SlotIndexer indexer, Slot slot) { updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), null, entry); } void processEntry(RejectedMessage entry, SlotIndexer indexer, Slot slot) { } void processEntry(TableStatus entry, SlotIndexer indexer, Slot slot) { } void updateLastMessage(long machineid, long seqnum, Slot slot, LastMessage entry) { } void processSlot(SlotIndexer indexer, Slot slot) { updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, null); for(Entry entry : slot.getEntries()) { switch(entry.getType()) { case Entry.TypeKeyValue: processEntry((KeyValue)entry, indexer, slot); break; case Entry.TypeLastMessage: processEntry((LastMessage)entry, indexer, slot); break; case Entry.TypeRejectedMessage: processEntry((RejectedMessage)entry, indexer, slot); break; case Entry.TypeTableStatus: processEntry((TableStatus)entry, indexer, slot); break; default: throw new Error("Unrecognized type: "+entry.getType()); } } } void checkHMACChain(SlotIndexer indexer, Slot[] newslots) { for(int i=0; i < newslots.length; i++) { Slot currslot=newslots[i]; Slot prevslot=indexer.getSlot(currslot.getSequenceNumber()-1); if (prevslot != null && !Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC())) throw new Error("Server Error: Invalid HMAC Chain"); } } }