more changes
[iotcloud.git] / src / java / iotcloud / Slot.java
1 package iotcloud;
2 import java.util.Vector;
3 import java.nio.ByteBuffer;
4 import javax.crypto.Mac;
5 import java.util.Arrays;
6
7 class Slot implements Liveness {
8         static final int SLOT_SIZE=2048;
9         static final int HMAC_SIZE=32;
10
11         private long seqnum;
12         private byte[] prevhmac;
13         private byte[] hmac;
14         private long machineid;
15         private Vector<Entry> entries;
16         private int livecount;
17         private boolean seqnumlive;
18         
19         Slot(long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) {
20                 seqnum=_seqnum;
21                 machineid=_machineid;
22                 prevhmac=_prevhmac;
23                 hmac=_hmac;
24                 entries=new Vector<Entry>();
25                 livecount=1;
26                 seqnumlive=true;
27         }
28
29         Slot(long _seqnum, long _machineid, byte[] _prevhmac) {
30                 this(_seqnum, _machineid, _prevhmac, new byte[HMAC_SIZE]);
31         }
32
33         byte[] getHMAC() {
34                 return hmac;
35         }
36
37         byte[] getPrevHMAC() {
38                 return prevhmac;
39         }
40
41         void addEntry(Entry e) {
42                 entries.add(e);
43                 livecount++;
44         }
45
46         Vector<Entry> getEntries() {
47                 return entries;
48         }
49
50         static Slot decode(byte[] array, Mac mac) {
51                 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
52                 byte[] realmac=mac.doFinal();
53
54                 ByteBuffer bb=ByteBuffer.wrap(array);
55                 byte[] hmac=new byte[HMAC_SIZE];
56                 byte[] prevhmac=new byte[HMAC_SIZE];
57                 bb.get(hmac);
58                 bb.get(prevhmac);
59                 if (!Arrays.equals(realmac, hmac))
60                         throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
61
62                 long seqnum=bb.getLong();
63                 long machineid=bb.getLong();
64                 int numentries=bb.getInt();
65                 Slot slot=new Slot(seqnum, machineid, prevhmac, hmac);
66
67                 for(int i=0; i<numentries; i++) {
68                         slot.addEntry(Entry.decode(slot, bb));
69                 }
70
71                 return slot;
72         }
73
74         byte[] encode(Mac mac) {
75                 byte[] array=new byte[SLOT_SIZE];
76                 ByteBuffer bb=ByteBuffer.wrap(array);
77                 bb.position(HMAC_SIZE);                                                                                                                                                                                                                                                 //Leave space for the HMACs
78                 bb.put(prevhmac);
79                 bb.putLong(seqnum);
80                 bb.putLong(machineid);
81                 bb.putInt(entries.size());
82                 for(Entry entry:entries) {
83                         entry.encode(bb);
84                 }
85                 //Compute our HMAC
86                 mac.update(array, HMAC_SIZE, array.length-HMAC_SIZE);
87                 byte[] realmac=mac.doFinal();
88                 bb.position(0);
89                 bb.put(realmac);
90                 return array;
91         }
92
93         long getSequenceNumber() {
94                 return seqnum;
95         }
96
97         long getMachineID() {
98                 return machineid;
99         }
100
101         byte[] getBytes() {
102                 return null;
103         }
104
105         void setDead() {
106                 decrementLiveCount();
107                 seqnumlive=false;
108         }
109         
110         void decrementLiveCount() {
111                 livecount--;
112         }
113
114         boolean isLive() {
115                 return livecount > 0;
116         }
117
118         public String toString() {
119                 return "<"+getSequenceNumber()+", "+new String(getBytes())+">";
120         }
121 }