updates
[iotcloud.git] / src / java / iotcloud / Table.java
1 package iotcloud;
2 import java.util.HashMap;
3 import java.util.Arrays;
4 import javax.crypto.spec.*;
5 import javax.crypto.*;
6
7 public class Table {
8         int numslots;
9         HashMap<IoTString, KeyValue> table=new HashMap<IoTString, KeyValue>();
10         HashMap<Long, Long> lastmessage=new HashMap<Long, Long>();
11         SlotBuffer buffer;
12         CloudComm cloud;
13         private Mac hmac;
14         long sequencenumber;
15         long machineid;
16         
17         public Table(String baseurl, String password, long _machineid) {
18                 machineid=_machineid;
19                 buffer = new SlotBuffer();
20                 sequencenumber = 1;
21                 initCloud(baseurl, password);
22         }
23
24         private void initCloud(String baseurl, String password) {
25                 try {
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");
32                         hmac.init(secret);
33                         cloud=new CloudComm(baseurl, encryptCipher, decryptCipher, hmac);
34                 } catch (Exception e) {
35                         throw new Error("Failed To Initialize Ciphers");
36                 }
37         }
38
39         private SecretKeySpec getKey(String password) {
40                 try {
41                         PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray());
42                         SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec);
43                         SecretKeySpec secret = new SecretKeySpec(key.getEncoded(), "AES");
44                         return secret;
45                 } catch (Exception e) {
46                         throw new Error("Failed generating key.");
47                 }
48         }
49
50         public void update() {
51                 Slot[] newslots=cloud.getSlots(sequencenumber);
52                 validateandupdate(newslots);
53         }
54
55         void validateandupdate(Slot[] newslots) {
56                 //The cloud communication layer has checked slot HMACs already
57                 //before decoding
58                 if (newslots.length==0)
59                         return;
60
61                 long firstseqnum=newslots[0].getSequenceNumber();
62                 if (firstseqnum < sequencenumber)
63                         throw new Error("Server Error: Sent older slots!");
64
65                 SlotIndexer indexer = new SlotIndexer(newslots, buffer);
66                 checkHMACChain(indexer, newslots);
67                 for(Slot slot: newslots) {
68                         processSlot(indexer, slot);
69                 }
70                 
71         }
72
73         void processEntry(KeyValue entry, SlotIndexer indexer, Slot slot) {
74                 IoTString key=entry.getKey();
75                 KeyValue oldvalue=table.get(key);
76                 if (oldvalue != null) {
77                         oldvalue.setDead();
78                 }
79                 table.put(key, entry);
80         }
81
82         void processEntry(LastMessage entry, SlotIndexer indexer, Slot slot) {
83                 updateLastMessage(entry.getMachineID(), entry.getSequenceNumber(), null, entry);
84         }
85
86         void processEntry(RejectedMessage entry, SlotIndexer indexer, Slot slot) {
87                 
88         }
89
90         void processEntry(TableStatus entry, SlotIndexer indexer, Slot slot) {
91
92         }
93
94         void updateLastMessage(long machineid, long seqnum, Slot slot, LastMessage entry) {
95                 
96         }
97         
98         void processSlot(SlotIndexer indexer, Slot slot) {
99                 updateLastMessage(slot.getMachineID(), slot.getSequenceNumber(), slot, null);
100
101                 for(Entry entry : slot.getEntries()) {
102                         switch(entry.getType()) {
103                         case Entry.TypeKeyValue:
104                                 processEntry((KeyValue)entry, indexer, slot);
105                                 break;
106                         case Entry.TypeLastMessage:
107                                 processEntry((LastMessage)entry, indexer, slot);
108                                 break;
109                         case Entry.TypeRejectedMessage:
110                                 processEntry((RejectedMessage)entry, indexer, slot);
111                                 break;
112                         case Entry.TypeTableStatus:
113                                 processEntry((TableStatus)entry, indexer, slot);
114                                 break;
115                         default:
116                                 throw new Error("Unrecognized type: "+entry.getType());
117                         }
118                 }
119         }
120         
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");
128                 }
129         }
130 }