IV changes
[iotcloud.git] / version2 / 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 /**
8  * Data structuring for holding Slot information.
9  * @author Brian Demsky
10  * @version 1.0
11  */
12
13 class Slot implements Liveness {
14         /** Sets the slot size. */
15         static final int SLOT_SIZE = 2048;
16         /** Sets the size for the HMAC. */
17         static final int HMAC_SIZE = 32;
18
19         /** Sequence number of the slot. */
20         private long seqnum;
21         /** HMAC of previous slot. */
22         private byte[] prevhmac;
23         /** HMAC of this slot. */
24         private byte[] hmac;
25         /** Machine that sent this slot. */
26         private long machineid;
27         /** Vector of entries in this slot. */
28         private Vector<Entry> entries;
29         /** Pieces of information that are live. */
30         private int livecount;
31         /** Flag that indicates whether this slot is still live for
32          * recording the machine that sent it. */
33         private boolean seqnumlive;
34         /** Number of bytes of free space. */
35         private int freespace;
36         /** Reference to Table */
37         private Table table;
38
39         private long localSequenceNumber;
40
41         Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac, long _localSequenceNumber) {
42                 seqnum = _seqnum;
43                 machineid = _machineid;
44                 prevhmac = _prevhmac;
45                 hmac = _hmac;
46                 entries = new Vector<Entry>();
47                 livecount = 1;
48                 seqnumlive = true;
49                 freespace = SLOT_SIZE - getBaseSize();
50                 table = _table;
51                 localSequenceNumber = _localSequenceNumber;
52         }
53
54         Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, long _localSequenceNumber) {
55                 this(_table, _seqnum, _machineid, _prevhmac, null, _localSequenceNumber);
56         }
57
58         Slot(Table _table, long _seqnum, long _machineid, long _localSequenceNumber) {
59                 this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null, _localSequenceNumber);
60         }
61
62         byte[] getHMAC() {
63                 return hmac;
64         }
65
66         byte[] getPrevHMAC() {
67                 return prevhmac;
68         }
69
70         Entry addEntry(Entry e) {
71                 e = e.getCopy(this);
72                 entries.add(e);
73                 livecount++;
74                 freespace -= e.getSize();
75                 return e;
76         }
77
78         void removeEntry(Entry e) {
79                 entries.remove(e);
80                 livecount--;
81                 freespace += e.getSize();
82         }
83
84         private void addShallowEntry(Entry e) {
85                 entries.add(e);
86                 livecount++;
87                 freespace -= e.getSize();
88         }
89
90         /**
91          * Returns true if the slot has free space to hold the entry without
92          * using its reserved space. */
93
94         boolean hasSpace(Entry e) {
95                 int newfreespace = freespace - e.getSize();
96                 return newfreespace >= 0;
97         }
98
99         Vector<Entry> getEntries() {
100                 return entries;
101         }
102
103         static Slot decode(Table table, byte[] array, Mac mac) {
104                 mac.update(array, HMAC_SIZE, array.length - HMAC_SIZE);
105                 byte[] realmac = mac.doFinal();
106
107                 ByteBuffer bb = ByteBuffer.wrap(array);
108                 byte[] hmac = new byte[HMAC_SIZE];
109                 byte[] prevhmac = new byte[HMAC_SIZE];
110                 bb.get(hmac);
111                 bb.get(prevhmac);
112                 if (!Arrays.equals(realmac, hmac))
113                         throw new Error("Server Error: Invalid HMAC!  Potential Attack!");
114
115                 long seqnum = bb.getLong();
116                 long machineid = bb.getLong();
117                 int numentries = bb.getInt();
118                 Slot slot = new Slot(table, seqnum, machineid, prevhmac, hmac, -1);
119
120                 for (int i = 0; i < numentries; i++) {
121                         slot.addShallowEntry(Entry.decode(slot, bb));
122                 }
123
124                 return slot;
125         }
126
127         byte[] encode(Mac mac) {
128                 byte[] array = new byte[SLOT_SIZE];
129                 ByteBuffer bb = ByteBuffer.wrap(array);
130                 /* Leave space for the slot HMAC.  */
131                 bb.position(HMAC_SIZE);
132                 bb.put(prevhmac);
133                 bb.putLong(seqnum);
134                 bb.putLong(machineid);
135                 bb.putInt(entries.size());
136                 for (Entry entry : entries) {
137                         entry.encode(bb);
138                 }
139                 /* Compute our HMAC */
140                 mac.update(array, HMAC_SIZE, array.length - HMAC_SIZE);
141                 byte[] realmac = mac.doFinal();
142                 hmac = realmac;
143                 bb.position(0);
144                 bb.put(realmac);
145                 return array;
146         }
147
148         /**
149          * Returns the empty size of a Slot. Includes 2 HMACs, the machine
150          * identifier, the sequence number, and the number of entries.
151          */
152         int getBaseSize() {
153                 return 2 * HMAC_SIZE + 2 * Long.BYTES + Integer.BYTES;
154         }
155
156         /**
157          * Returns the live set of entries for this Slot.  Generates a fake
158          * LastMessage entry to represent the information stored by the slot
159          * itself.
160          */
161
162         Vector<Entry> getLiveEntries(boolean resize) {
163                 Vector<Entry> liveEntries = new Vector<Entry>();
164                 for (Entry entry : entries) {
165                         if (entry.isLive()) {
166                                 if (!resize || entry.getType() != Entry.TypeTableStatus)
167                                         liveEntries.add(entry);
168                         }
169                 }
170
171                 if (seqnumlive && !resize)
172                         liveEntries.add(new LastMessage(this, machineid, seqnum));
173
174                 return liveEntries;
175         }
176
177         /**
178          * Returns the sequence number of the slot.
179          */
180
181         long getSequenceNumber() {
182                 return seqnum;
183         }
184
185         /**
186          * Returns the machine that sent this slot.
187          */
188
189         long getMachineID() {
190                 return machineid;
191         }
192
193         /**
194          * Records that a newer slot records the fact that this slot was
195          * sent by the relevant machine.
196          */
197
198         void setDead() {
199                 seqnumlive = false;
200                 decrementLiveCount();
201         }
202
203         /**
204          * Update the count of live entries.
205          */
206
207         void decrementLiveCount() {
208                 livecount--;
209                 if (livecount == 0) {
210                         table.decrementLiveCount();
211                 }
212         }
213
214         /**
215          * Returns whether the slot stores any live information.
216          */
217
218         boolean isLive() {
219                 return livecount > 0;
220         }
221
222         public byte[] getSlotCryptIV() {
223                 ByteBuffer buffer = ByteBuffer.allocate(CloudComm.IV_SIZE);
224                 buffer.putLong(machineid);
225                 long localSequenceNumberShift = localSequenceNumber << 16;
226                 buffer.putLong(localSequenceNumberShift);
227                 return buffer.array();
228         }
229
230         public String toString() {
231                 return "<" + getSequenceNumber() + ">";
232         }
233 }