679421ec518cb0c739a5de139c4653fc05881fa9
[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, IoTString> table=new HashMap<IoTString, IoTString>();
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
75         }
76
77         void processEntry(LastMessage entry, SlotIndexer indexer, Slot slot) {
78
79         }
80
81         void processEntry(RejectedMessage entry, SlotIndexer indexer, Slot slot) {
82
83         }
84
85         void processEntry(TableStatus entry, SlotIndexer indexer, Slot slot) {
86
87         }
88         
89         void processSlot(SlotIndexer indexer, Slot slot) {
90                 for(Entry entry : slot.getEntries()) {
91                         switch(entry.getType()) {
92                         case Entry.TypeKeyValue:
93                                 processEntry((KeyValue)entry, indexer, slot);
94                                 break;
95                         case Entry.TypeLastMessage:
96                                 processEntry((LastMessage)entry, indexer, slot);
97                                 break;
98                         case Entry.TypeRejectedMessage:
99                                 processEntry((RejectedMessage)entry, indexer, slot);
100                                 break;
101                         case Entry.TypeTableStatus:
102                                 processEntry((TableStatus)entry, indexer, slot);
103                                 break;
104                         default:
105                                 throw new Error("Unrecognized type: "+entry.getType());
106                         }
107                 }
108         }
109         
110         void checkHMACChain(SlotIndexer indexer, Slot[] newslots) {
111                 for(int i=0; i < newslots.length; i++) {
112                         Slot currslot=newslots[i];
113                         Slot prevslot=indexer.getSlot(currslot.getSequenceNumber()-1);
114                         if (prevslot != null &&
115                                         !Arrays.equals(prevslot.getHMAC(), currslot.getPrevHMAC()))
116                                 throw new Error("Server Error: Invalid HMAC Chain");
117                 }
118         }
119 }