2 import java.util.HashMap;
3 import java.util.Arrays;
4 import javax.crypto.spec.*;
9 HashMap<IoTString, KeyValue> table=new HashMap<IoTString, KeyValue>();
10 HashMap<Long, Long> lastmessage=new HashMap<Long, Long>();
17 public Table(String baseurl, String password, long _machineid) {
19 buffer = new SlotBuffer();
21 initCloud(baseurl, password);
24 private void initCloud(String baseurl, String password) {
26 SecretKeySpec secret=getKey(password);
27 Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
28 encryptCipher.init(Cipher.ENCRYPT_MODE, secret);
29 Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
30 decryptCipher.init(Cipher.DECRYPT_MODE, secret);
31 hmac = Mac.getInstance("HmacSHA256");
33 cloud=new CloudComm(baseurl, encryptCipher, decryptCipher, hmac);
34 } catch (Exception e) {
35 throw new Error("Failed To Initialize Ciphers");
39 private SecretKeySpec getKey(String password) {
41 PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray());
42 SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec);
43 SecretKeySpec secret = new SecretKeySpec(key.getEncoded(), "AES");
45 } catch (Exception e) {
46 throw new Error("Failed generating key.");
50 public void update() {
51 Slot[] newslots=cloud.getSlots(sequencenumber);
52 validateandupdate(newslots);
55 void validateandupdate(Slot[] newslots) {
56 //The cloud communication layer has checked slot HMACs already
58 if (newslots.length==0)
61 long firstseqnum=newslots[0].getSequenceNumber();
62 if (firstseqnum < sequencenumber)
63 throw new Error("Server Error: Sent older slots!");
65 SlotIndexer indexer = new SlotIndexer(newslots, buffer);
66 checkHMACChain(indexer, newslots);
67 for(Slot slot: newslots) {
68 processSlot(indexer, slot);
73 void processEntry(KeyValue entry, SlotIndexer indexer, Slot slot) {
74 IoTString key=entry.getKey();
75 KeyValue oldvalue=table.get(key);
76 if (oldvalue != null) {
79 table.put(key, entry);
82 void processEntry(LastMessage entry, SlotIndexer indexer, Slot slot) {
83 updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), null, entry);
86 void processEntry(RejectedMessage entry, SlotIndexer indexer, Slot slot) {
90 void processEntry(TableStatus entry, SlotIndexer indexer, Slot slot) {
94 void updateLastMessage(long machineid, long seqnum, Slot slot, LastMessage entry) {
98 void processSlot(SlotIndexer indexer, Slot slot) {
99 updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, null);
101 for(Entry entry : slot.getEntries()) {
102 switch(entry.getType()) {
103 case Entry.TypeKeyValue:
104 processEntry((KeyValue)entry, indexer, slot);
106 case Entry.TypeLastMessage:
107 processEntry((LastMessage)entry, indexer, slot);
109 case Entry.TypeRejectedMessage:
110 processEntry((RejectedMessage)entry, indexer, slot);
112 case Entry.TypeTableStatus:
113 processEntry((TableStatus)entry, indexer, slot);
116 throw new Error("Unrecognized type: "+entry.getType());
121 void checkHMACChain(SlotIndexer indexer, Slot[] newslots) {
122 for(int i=0; i < newslots.length; i++) {
123 Slot currslot=newslots[i];
124 Slot prevslot=indexer.getSlot(currslot.getSequenceNumber()-1);
125 if (prevslot != null &&
126 !Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC()))
127 throw new Error("Server Error: Invalid HMAC Chain");