c20488dd268d59632d09634068961b918a9a878c
[iotcloud.git] / version2 / src / C / CloudComm.cc
1 #include "CloudComm.h"
2 #include "TimingSingleton.h"
3 #include "SecureRandom.h"
4 #include "IoTString.h"
5 #include "Error.h"
6 #include "URL.h"
7 #include "Mac.h"
8 #include "Table.h"
9 #include "Slot.h"
10 #include "Crypto.h"
11 #include "ByteBuffer.h"
12 #include "aes.h"
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <arpa/inet.h>
16 #include <netinet/tcp.h>
17 #include <unistd.h>
18 #include <netdb.h>
19
20 /**
21  * Empty Constructor needed for child class.
22  */
23 CloudComm::CloudComm() :
24         baseurl(NULL),
25         key(NULL),
26         mac(NULL),
27         password(NULL),
28         random(NULL),
29         salt(NULL),
30         table(NULL),
31         listeningPort(-1),
32         doEnd(false),
33         timer(TimingSingleton_getInstance()),
34         getslot(new Array<char>("getslot", 7)),
35         putslot(new Array<char>("putslot", 7))
36 {
37 }
38
39 void *threadWrapper(void *cloud) {
40         CloudComm *c = (CloudComm *) cloud;
41         c->localServerWorkerFunction();
42         return NULL;
43 }
44
45 /**
46  * Constructor for actual use. Takes in the url and password.
47  */
48 CloudComm::CloudComm(Table *_table,  IoTString *_baseurl, IoTString *_password, int _listeningPort) :
49         baseurl(_baseurl),
50         key(NULL),
51         mac(NULL),
52         password(new IoTString(_password)),
53         random(new SecureRandom()),
54         salt(NULL),
55         table(_table),
56         listeningPort(_listeningPort),
57         doEnd(false),
58         timer(TimingSingleton_getInstance()),
59         getslot(new Array<char>("getslot", 7)),
60         putslot(new Array<char>("putslot", 7)) {
61         if (listeningPort > 0) {
62                 pthread_create(&localServerThread, NULL, threadWrapper, this);
63         }
64 }
65
66 CloudComm::~CloudComm() {
67         delete random;
68         delete getslot;
69         delete putslot;
70 }
71
72 /**
73  * Generates Key from password.
74  */
75 AESKey *CloudComm::initKey() {
76         try {
77                 AESKey *key = new AESKey(password->internalBytes(),
78                                                                                                                  salt,
79                                                                                                                  65536,
80                                                                                                                  128);
81                 return key;
82         } catch (Exception *e) {
83                 throw new Error("Failed generating key.");
84         }
85 }
86
87 /**
88  * Inits all the security stuff
89  */
90
91 void CloudComm::initSecurity() {
92         // try to get the salt and if one does not exist set one
93         if (!getSalt()) {
94                 //Set the salt
95                 setSalt();
96         }
97
98         initCrypt();
99 }
100
101 /**
102  * Inits the HMAC generator.
103  */
104 void CloudComm::initCrypt() {
105         if (password == NULL) {
106                 return;
107         }
108         try {
109                 key = initKey();
110                 delete password;
111                 password = NULL;// drop password
112                 mac = new Mac();
113                 mac->init(key);
114         } catch (Exception *e) {
115                 throw new Error("Failed To Initialize Ciphers");
116         }
117 }
118
119 /*
120  * Builds the URL for the given request.
121  */
122 IoTString *CloudComm::buildRequest(bool isput, int64_t sequencenumber, int64_t maxentries) {
123         const char *reqstring = isput ? "req=putslot" : "req=getslot";
124         char *buffer = (char *) malloc(baseurl->length() + 200);
125         memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length());
126         int offset = baseurl->length();
127         offset += sprintf(&buffer[offset], "?%s&seq=%" PRId64, reqstring, sequencenumber);
128         if (maxentries != 0)
129                 sprintf(&buffer[offset], "&max=%" PRId64, maxentries);
130         IoTString *urlstr = new IoTString(buffer);
131         return urlstr;
132 }
133
134 void loopWrite(int fd, char *array, int bytestowrite) {
135         int byteswritten = 0;
136         while (bytestowrite) {
137                 int bytes = write(fd, &array[byteswritten], bytestowrite);
138                 if (bytes >= 0) {
139                         byteswritten += bytes;
140                         bytestowrite -= bytes;
141                 } else {
142                         printf("Error in write\n");
143                         exit(-1);
144                 }
145         }
146 }
147
148 void loopRead(int fd, char *array, int bytestoread) {
149         int bytesread = 0;
150         while (bytestoread) {
151                 int bytes = read(fd, &array[bytesread], bytestoread);
152                 if (bytes >= 0) {
153                         bytesread += bytes;
154                         bytestoread -= bytes;
155                 } else {
156                         printf("Error in read\n");
157                         exit(-1);
158                 }
159         }
160 }
161
162 WebConnection openURL(IoTString *url) {
163         if (url->length() < 7 || memcmp(url->internalBytes()->internalArray(), "http://", 7)) {
164                 printf("BOGUS URL\n");
165                 exit(-1);
166         }
167         int i = 7;
168         for (; i < url->length(); i++)
169                 if (url->get(i) == '/')
170                         break;
171
172         if ( i == url->length()) {
173                 printf("ERROR in openURL\n");
174                 exit(-1);
175         }
176
177         char *host = (char *) malloc(i - 6);
178         memcpy(host, &url->internalBytes()->internalArray()[7], i - 7);
179         host[i - 7] = 0;
180         printf("%s\n", host);
181
182         char *message = (char *)malloc(sizeof("POST  HTTP/1.1\r\n") + sizeof("Host: \r\n") + 2 * url->length());
183
184         /* fill in the parameters */
185         int post = sprintf(message,"POST ");
186         /* copy data */
187         memcpy(&message[post], &url->internalBytes()->internalArray()[i], url->length() - i);
188         int endpost = sprintf(&message[post + url->length() - i], " HTTP/1.1\r\n");
189
190         int hostlen = sprintf(&message[endpost + post + url->length() - i], "Host: ");
191         memcpy(&message[endpost + post + url->length() + hostlen - i], host, i - 7);
192         sprintf(&message[endpost + post + url->length() + hostlen - 7], "\r\n");
193
194         /* create the socket */
195         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
196         if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);}
197
198         /* lookup the ip address */
199         struct hostent *server = gethostbyname(host);
200         free(host);
201
202         if (server == NULL) {printf("ERROR, no such host"); exit(-1);}
203
204         /* fill in the structure */
205         struct sockaddr_in serv_addr;
206
207         memset(&serv_addr,0,sizeof(serv_addr));
208         serv_addr.sin_family = AF_INET;
209         serv_addr.sin_port = htons(80);
210         memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
211
212         /* connect the socket */
213         if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
214                 printf("ERROR connecting");
215                 exit(-1);
216         }
217
218         /* send the request */
219         int total = strlen(message);
220         loopWrite(sockfd, message, total);
221         return (WebConnection) {sockfd, -1};
222 }
223
224 int createSocket(IoTString *name, int port) {
225         char *host = (char *) malloc(name->length() + 1);
226         memcpy(host, name->internalBytes()->internalArray(), name->length());
227         host[name->length()] = 0;
228         printf("%s\n", host);
229         /* How big is the message? */
230
231         /* create the socket */
232         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
233         if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);}
234
235         /* lookup the ip address */
236         struct hostent *server = gethostbyname(host);
237         free(host);
238
239         if (server == NULL) {printf("ERROR, no such host"); exit(-1);}
240
241         /* fill in the structure */
242         struct sockaddr_in serv_addr;
243
244         memset(&serv_addr,0,sizeof(serv_addr));
245         serv_addr.sin_family = AF_INET;
246         serv_addr.sin_port = htons(port);
247         memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
248
249         /* connect the socket */
250         if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
251                 printf("ERROR connecting");
252                 exit(-1);
253         }
254
255         return sockfd;
256 }
257
258 int createSocket(int port) {
259         int fd;
260         struct sockaddr_in sin;
261
262         bzero(&sin, sizeof(sin));
263         sin.sin_family = AF_INET;
264         sin.sin_port = htons(port);
265         sin.sin_addr.s_addr = htonl(INADDR_ANY);
266         fd = socket(AF_INET, SOCK_STREAM, 0);
267         int n = 1;
268         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof (n)) < 0) {
269                 close(fd);
270                 printf("Create Socket Error\n");
271                 exit(-1);
272         }
273         if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
274                 close(fd);
275                 exit(-1);
276         }
277         if (listen(fd, 5) < 0) {
278                 close(fd);
279                 exit(-1);
280         }
281         return fd;
282 }
283
284 int acceptSocket(int socket) {
285         struct sockaddr_in sin;
286         unsigned int sinlen = sizeof(sin);
287         int newfd = accept(socket, (struct sockaddr *)&sin, &sinlen);
288         int flag = 1;
289         setsockopt(newfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag));
290         if (newfd < 0) {
291                 printf("Accept Error\n");
292                 exit(-1);
293         }
294         return newfd;
295 }
296
297 void writeSocketData(int fd, Array<char> *data) {
298         loopWrite(fd, data->internalArray(), data->length());
299 }
300
301 void writeSocketInt(int fd, int32_t value) {
302         char array[4];
303         array[0] = value >> 24;
304         array[1] = (value >> 16) & 0xff;
305         array[2] = (value >> 8) & 0xff;
306         array[3] = value & 0xff;
307         loopWrite(fd, array, 4);
308 }
309
310 int readSocketInt(int fd) {
311         char array[4];
312         loopRead(fd, array, 4);
313         return (((int32_t)(unsigned char) array[0]) << 24) |
314                                  (((int32_t)(unsigned char) array[1]) << 16) |
315                                  (((int32_t)(unsigned char) array[2]) << 8) |
316                                  ((int32_t)(unsigned char) array[3]);
317 }
318
319 void readSocketData(int fd, Array<char> *data) {
320         loopRead(fd, data->internalArray(), data->length());
321 }
322
323 void writeURLDataAndClose(WebConnection *wc, Array<char> *data) {
324         dprintf(wc->fd, "Content-Length: %d\r\n\r\n", data->length());
325         loopWrite(wc->fd, data->internalArray(), data->length());
326 }
327
328 void closeURLReq(WebConnection *wc) {
329         dprintf(wc->fd, "\r\n");
330 }
331
332 void readURLData(WebConnection *wc, Array<char> *output) {
333         loopRead(wc->fd, output->internalArray(), output->length());
334 }
335
336 int readURLInt(WebConnection *wc) {
337         char array[4];
338         loopRead(wc->fd, array, 4);
339         return (((int32_t)(unsigned char) array[0]) << 24) |
340                                  (((int32_t)(unsigned char) array[1]) << 16) |
341                                  (((int32_t)(unsigned char) array[2]) << 8) |
342                                  ((int32_t)(unsigned char) array[3]);
343 }
344
345 void readLine(WebConnection *wc, char *response, int numBytes) {
346         int offset = 0;
347         char newchar;
348         while (true) {
349                 int bytes = read(wc->fd, &newchar, 1);
350                 if (bytes <= 0)
351                         break;
352                 if (offset == (numBytes - 1)) {
353                         printf("Response too long");
354                         exit(-1);
355                 }
356                 response[offset++] = newchar;
357                 if (newchar == '\n')
358                         break;
359         }
360         response[offset] = 0;
361 }
362
363 int getResponseCode(WebConnection *wc) {
364         char response[600];
365         readLine(wc, response, sizeof(response));
366         int ver1 = 0, ver2 = 0, respcode = 0;
367         sscanf(response, "HTTP/%d.%d %d", &ver1, &ver2, &respcode);
368         printf("Response code %d\n", respcode);
369         return respcode;
370 }
371
372 void readHeaders(WebConnection *wc) {
373         char response[600];
374         int numBytes;
375
376         while (true) {
377                 readLine(wc, response, sizeof(response));
378                 if (response[0] == '\r')
379                         return;
380                 else if (memcmp(response, "Content-Length:", sizeof("Content-Length:") - 1) == 0) {
381                         sscanf(response, "Content-Length: %d", &numBytes);
382                         wc->numBytes = numBytes;
383                 }
384         }
385 }
386
387 void CloudComm::setSalt() {
388         if (salt != NULL) {
389                 // Salt already sent to server so don't set it again
390                 return;
391         }
392
393         WebConnection wc = {-1, -1};
394         try {
395                 Array<char> *saltTmp = new Array<char>(CloudComm_SALT_SIZE);
396                 random->nextBytes(saltTmp);
397
398                 char *buffer = (char *) malloc(baseurl->length() + 100);
399                 memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length());
400                 int offset = baseurl->length();
401                 offset += sprintf(&buffer[offset], "?req=setsalt");
402                 IoTString *urlstr = new IoTString(buffer);
403                 free(buffer);
404
405                 timer->startTime();
406                 wc = openURL(urlstr);
407                 writeURLDataAndClose(&wc, saltTmp);
408
409                 int responsecode = getResponseCode(&wc);
410                 if (responsecode != HttpURLConnection_HTTP_OK) {
411                         throw new Error("Invalid response");
412                 }
413                 close(wc.fd);
414
415                 timer->endTime();
416                 salt = saltTmp;
417         } catch (Exception *e) {
418                 timer->endTime();
419                 throw new ServerException("Failed setting salt", ServerException_TypeConnectTimeout);
420         }
421 }
422
423 bool CloudComm::getSalt() {
424         WebConnection wc = {-1, -1};
425         IoTString *urlstr = NULL;
426
427         try {
428                 char *buffer = (char *) malloc(baseurl->length() + 100);
429                 memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length());
430                 int offset = baseurl->length();
431                 offset += sprintf(&buffer[offset], "?req=getsalt");
432                 urlstr = new IoTString(buffer);
433                 free(buffer);
434         } catch (Exception *e) {
435                 throw new Error("getSlot failed");
436         }
437         try {
438                 timer->startTime();
439                 wc = openURL(urlstr);
440                 closeURLReq(&wc);
441                 timer->endTime();
442         } catch (SocketTimeoutException *e) {
443                 timer->endTime();
444                 throw new ServerException("getSalt failed", ServerException_TypeConnectTimeout);
445         } catch (Exception *e) {
446                 throw new Error("getSlot failed");
447         }
448
449         try {
450                 timer->startTime();
451                 int responsecode = getResponseCode(&wc);
452                 readHeaders(&wc);
453                 if (responsecode != HttpURLConnection_HTTP_OK) {
454                         throw new Error("Invalid response");
455                 }
456                 if (wc.numBytes == 0) {
457                         timer->endTime();
458                         close(wc.fd);
459                         return false;
460                 }
461
462
463                 int salt_length = readURLInt(&wc);
464                 Array<char> *tmp = new Array<char>(salt_length);
465                 readURLData(&wc, tmp);
466                 close(wc.fd);
467
468                 salt = tmp;
469                 timer->endTime();
470                 return true;
471         } catch (SocketTimeoutException *e) {
472                 timer->endTime();
473                 throw new ServerException("getSalt failed", ServerException_TypeInputTimeout);
474         } catch (Exception *e) {
475                 throw new Error("getSlot failed");
476         }
477 }
478
479 Array<char> *CloudComm::createIV(int64_t machineId, int64_t localSequenceNumber) {
480         ByteBuffer *buffer = ByteBuffer_allocate(CloudComm_IV_SIZE);
481         buffer->putLong(machineId);
482         int64_t localSequenceNumberShifted = localSequenceNumber << 16;
483         buffer->putLong(localSequenceNumberShifted);
484         return buffer->array();
485 }
486
487 Array<char> *AESEncrypt(Array<char> *ivBytes, AESKey *key, Array<char> *data) {
488         Array<char> *output = new Array<char>(data->length());
489         aes_encrypt_ctr((BYTE *)data->internalArray(), data->length(), (BYTE *) output->internalArray(), (WORD *)key->getKeySchedule(), key->getKey()->length() * 8, (BYTE *)ivBytes->internalArray());
490         return output;
491 }
492
493 Array<char> *AESDecrypt(Array<char> *ivBytes, AESKey *key, Array<char> *data) {
494         Array<char> *output = new Array<char>(data->length());
495         aes_decrypt_ctr((BYTE *)data->internalArray(), data->length(), (BYTE *)output->internalArray(), (WORD *)key->getKeySchedule(), key->getKey()->length() * 8, (BYTE *)ivBytes->internalArray());
496         return output;
497 }
498
499 Array<char> *CloudComm::encryptSlotAndPrependIV(Array<char> *rawData, Array<char> *ivBytes) {
500         try {
501                 Array<char> *encryptedBytes = AESEncrypt(ivBytes, key, rawData);
502                 Array<char> *origBytes = AESDecrypt(ivBytes, key, encryptedBytes);
503                 if (!rawData->equals(origBytes))
504                         throw new Error("BAD");
505                 Array<char> *chars = new Array<char>(encryptedBytes->length() + CloudComm_IV_SIZE);
506                 System_arraycopy(ivBytes, 0, chars, 0, ivBytes->length());
507                 System_arraycopy(encryptedBytes, 0, chars, CloudComm_IV_SIZE, encryptedBytes->length());
508
509                 return chars;
510         } catch (Exception *e) {
511                 throw new Error("Failed To Encrypt");
512         }
513 }
514
515 Array<char> *CloudComm::stripIVAndDecryptSlot(Array<char> *rawData) {
516         try {
517                 Array<char> *ivBytes = new Array<char>(CloudComm_IV_SIZE);
518                 Array<char> *encryptedBytes = new Array<char>(rawData->length() - CloudComm_IV_SIZE);
519                 System_arraycopy(rawData, 0, ivBytes, 0, CloudComm_IV_SIZE);
520                 System_arraycopy(rawData, CloudComm_IV_SIZE, encryptedBytes, 0, encryptedBytes->length());
521                 return AESDecrypt(ivBytes, key, encryptedBytes);
522         } catch (Exception *e) {
523                 throw new Error("Failed To Decrypt");
524         }
525 }
526
527 /*
528  * API for putting a slot into the queue.  Returns NULL on success.
529  * On failure, the server will send slots with newer sequence
530  * numbers.
531  */
532 Array<Slot *> *CloudComm::putSlot(Slot *slot, int max) {
533         WebConnection wc = {-1, -1};
534         try {
535                 if (salt == NULL) {
536                         if (!getSalt()) {
537                                 throw new ServerException("putSlot failed", ServerException_TypeSalt);
538                         }
539                         initCrypt();
540                 }
541
542                 int64_t sequencenumber = slot->getSequenceNumber();
543                 Array<char> *slotBytes = slot->encode(mac);
544                 Array<char> *chars = encryptSlotAndPrependIV(slotBytes, slot->getSlotCryptIV());
545                 IoTString *url = buildRequest(true, sequencenumber, max);
546                 timer->startTime();
547                 wc = openURL(url);
548                 writeURLDataAndClose(&wc, chars);
549                 timer->endTime();
550         } catch (ServerException *e) {
551                 timer->endTime();
552                 throw e;
553         } catch (SocketTimeoutException *e) {
554                 timer->endTime();
555                 throw new ServerException("putSlot failed", ServerException_TypeConnectTimeout);
556         } catch (Exception *e) {
557                 throw new Error("putSlot failed");
558         }
559
560         try {
561                 int respcode = getResponseCode(&wc);
562                 readHeaders(&wc);
563                 timer->startTime();
564                 Array<char> *resptype = new Array<char>(7);
565                 readURLData(&wc, resptype);
566                 timer->endTime();
567
568                 if (resptype->equals(getslot)) {
569                         Array<Slot *> *tmp = processSlots(&wc);
570                         close(wc.fd);
571                         return tmp;
572                 } else if (resptype->equals(putslot)) {
573                         close(wc.fd);
574                         return NULL;
575                 } else {
576                         close(wc.fd);
577                         throw new Error("Bad response to putslot");
578                 }
579         } catch (SocketTimeoutException *e) {
580                 timer->endTime();
581                 close(wc.fd);
582                 throw new ServerException("putSlot failed", ServerException_TypeInputTimeout);
583         } catch (Exception *e) {
584                 throw new Error("putSlot failed");
585         }
586 }
587
588 /**
589  * Request the server to send all slots with the given
590  * sequencenumber or newer->
591  */
592 Array<Slot *> *CloudComm::getSlots(int64_t sequencenumber) {
593         WebConnection wc = {-1, -1};
594         try {
595                 if (salt == NULL) {
596                         if (!getSalt()) {
597                                 throw new ServerException("getSlots failed", ServerException_TypeSalt);
598                         }
599                         initCrypt();
600                 }
601
602                 IoTString *url = buildRequest(false, sequencenumber, 0);
603                 timer->startTime();
604                 wc = openURL(url);
605                 closeURLReq(&wc);
606                 timer->endTime();
607         } catch (SocketTimeoutException *e) {
608                 timer->endTime();
609                 throw new ServerException("getSlots failed", ServerException_TypeConnectTimeout);
610         } catch (ServerException *e) {
611                 timer->endTime();
612
613                 throw e;
614         } catch (Exception *e) {
615                 throw new Error("getSlots failed");
616         }
617
618         try {
619                 timer->startTime();
620                 int responsecode = getResponseCode(&wc);
621                 readHeaders(&wc);
622                 Array<char> *resptype = new Array<char>(7);
623                 readURLData(&wc, resptype);
624                 timer->endTime();
625                 if (!resptype->equals(getslot))
626                         throw new Error("Bad Response: ");
627
628                 Array<Slot *> *tmp = processSlots(&wc);
629                 close(wc.fd);
630                 return tmp;
631         } catch (SocketTimeoutException *e) {
632                 timer->endTime();
633                 close(wc.fd);
634                 throw new ServerException("getSlots failed", ServerException_TypeInputTimeout);
635         } catch (Exception *e) {
636                 throw new Error("getSlots failed");
637         }
638 }
639
640 /**
641  * Method that actually handles building Slot objects from the
642  * server response.  Shared by both putSlot and getSlots.
643  */
644 Array<Slot *> *CloudComm::processSlots(WebConnection *wc) {
645         int numberofslots = readURLInt(wc);
646         Array<int> *sizesofslots = new Array<int>(numberofslots);
647         Array<Slot *> *slots = new Array<Slot *>(numberofslots);
648
649         for (int i = 0; i < numberofslots; i++)
650                 sizesofslots->set(i, readURLInt(wc));
651         for (int i = 0; i < numberofslots; i++) {
652                 Array<char> *rawData = new Array<char>(sizesofslots->get(i));
653                 readURLData(wc, rawData);
654                 Array<char> *data = stripIVAndDecryptSlot(rawData);
655                 slots->set(i, Slot_decode(table, data, mac));
656         }
657         return slots;
658 }
659
660 Array<char> *CloudComm::sendLocalData(Array<char> *sendData, int64_t localSequenceNumber, IoTString *host, int port) {
661         if (salt == NULL)
662                 return NULL;
663         try {
664                 printf("Passing Locally\n");
665                 mac->update(sendData, 0, sendData->length());
666                 Array<char> *genmac = mac->doFinal();
667                 Array<char> *totalData = new Array<char>(sendData->length() + genmac->length());
668                 System_arraycopy(sendData, 0, totalData, 0, sendData->length());
669                 System_arraycopy(genmac, 0, totalData, sendData->length(), genmac->length());
670
671                 // Encrypt the data for sending
672                 Array<char> *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber());
673                 Array<char> *encryptedData = encryptSlotAndPrependIV(totalData, iv);
674
675                 // Open a TCP socket connection to a local device
676                 int socket = createSocket(host, port);
677
678                 timer->startTime();
679                 // Send data to output (length of data, the data)
680                 writeSocketInt(socket, encryptedData->length());
681                 writeSocketData(socket, encryptedData);
682
683                 int lengthOfReturnData = readSocketInt(socket);
684                 Array<char> *returnData = new Array<char>(lengthOfReturnData);
685                 readSocketData(socket, returnData);
686                 timer->endTime();
687                 returnData = stripIVAndDecryptSlot(returnData);
688
689                 // We are done with this socket
690                 close(socket);
691                 mac->update(returnData, 0, returnData->length() - CloudComm_HMAC_SIZE);
692                 Array<char> *realmac = mac->doFinal();
693                 Array<char> *recmac = new Array<char>(CloudComm_HMAC_SIZE);
694                 System_arraycopy(returnData, returnData->length() - realmac->length(), recmac, 0, realmac->length());
695
696                 if (!recmac->equals(realmac))
697                         throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
698
699                 Array<char> *returnData2 = new Array<char>(lengthOfReturnData - recmac->length());
700                 System_arraycopy(returnData, 0, returnData2, 0, returnData2->length());
701
702                 return returnData2;
703         } catch (Exception *e) {
704                 printf("Exception\n");
705         }
706
707         return NULL;
708 }
709
710 void CloudComm::localServerWorkerFunction() {
711         int inputSocket = -1;
712
713         try {
714                 // Local server socket
715                 inputSocket = createSocket(listeningPort);
716         } catch (Exception *e) {
717                 throw new Error("Local server setup failure...");
718         }
719
720         while (!doEnd) {
721                 try {
722                         // Accept incoming socket
723                         int socket = acceptSocket(inputSocket);
724
725                         // Get the encrypted data from the server
726                         int dataSize = readSocketInt(socket);
727                         Array<char> *readData = new Array<char>(dataSize);
728                         readSocketData(socket, readData);
729                         timer->endTime();
730
731                         // Decrypt the data
732                         readData = stripIVAndDecryptSlot(readData);
733                         mac->update(readData, 0, readData->length() - CloudComm_HMAC_SIZE);
734                         Array<char> *genmac = mac->doFinal();
735                         Array<char> *recmac = new Array<char>(CloudComm_HMAC_SIZE);
736                         System_arraycopy(readData, readData->length() - recmac->length(), recmac, 0, recmac->length());
737
738                         if (!recmac->equals(genmac))
739                                 throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
740
741                         Array<char> *returnData = new Array<char>(readData->length() - recmac->length());
742                         System_arraycopy(readData, 0, returnData, 0, returnData->length());
743
744                         // Process the data
745                         Array<char> *sendData = table->acceptDataFromLocal(returnData);
746                         mac->update(sendData, 0, sendData->length());
747                         Array<char> *realmac = mac->doFinal();
748                         Array<char> *totalData = new Array<char>(sendData->length() + realmac->length());
749                         System_arraycopy(sendData, 0, totalData, 0, sendData->length());
750                         System_arraycopy(realmac, 0, totalData, sendData->length(), realmac->length());
751
752                         // Encrypt the data for sending
753                         Array<char> *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber());
754                         Array<char> *encryptedData = encryptSlotAndPrependIV(totalData, iv);
755
756                         timer->startTime();
757                         // Send data to output (length of data, the data)
758                         writeSocketInt(socket, encryptedData->length());
759                         writeSocketData(socket, encryptedData);
760                         close(socket);
761                 } catch (Exception *e) {
762                 }
763         }
764
765         if (inputSocket != -1) {
766                 try {
767                         close(inputSocket);
768                 } catch (Exception *e) {
769                         throw new Error("Local server close failure...");
770                 }
771         }
772 }
773
774 void CloudComm::closeCloud() {
775         doEnd = true;
776
777         if (listeningPort > 0) {
778                 if (pthread_join(localServerThread, NULL) != 0)
779                         throw new Error("Local Server thread join issue...");
780         }
781 }