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