224018ba63671f23f6632264f37998d367df769a
[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(_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                 password = NULL;// drop password
111                 mac = new Mac();
112                 mac->init(key);
113         } catch (Exception *e) {
114                 throw new Error("Failed To Initialize Ciphers");
115         }
116 }
117
118 /*
119  * Builds the URL for the given request.
120  */
121 IoTString *CloudComm::buildRequest(bool isput, int64_t sequencenumber, int64_t maxentries) {
122         const char *reqstring = isput ? "req=putslot" : "req=getslot";
123         char *buffer = (char *) malloc(baseurl->length() + 200);
124         memcpy(buffer, baseurl->internalBytes(), baseurl->length());
125         int offset = baseurl->length();
126         offset += sprintf(&buffer[offset], "?%s&seq=%" PRId64, reqstring, sequencenumber);
127         if (maxentries != 0)
128                 sprintf(&buffer[offset], "&max=%" PRId64, maxentries);
129         IoTString *urlstr = new IoTString(buffer);
130         return urlstr;
131 }
132
133 void loopWrite(int fd, char * array, int bytestowrite) {
134         int byteswritten = 0;
135         while (bytestowrite) {
136                 int bytes = write(fd, & array[byteswritten], bytestowrite);
137                 if (bytes >= 0) {
138                         byteswritten += bytes;
139                         bytestowrite -= bytes;
140                 } else {
141                         printf("Error in write\n");
142                         exit(-1);
143                 }
144         }
145 }
146
147 void loopRead(int fd, char * array, int bytestoread) {
148         int bytesread = 0;
149         while (bytestoread) {
150                 int bytes = read(fd, & array[bytesread], bytestoread);
151                 if (bytes >= 0) {
152                         bytesread += bytes;
153                         bytestoread -= bytes;
154                 } else {
155                         printf("Error in read\n");
156                         exit(-1);
157                 }
158         }
159 }
160
161 int openURL(IoTString *url) {
162         if (url->length() < 7 || memcmp(url->internalBytes()->internalArray(), "http://", 7)) {
163                 printf("BOGUS URL\n");
164                 exit(-1);
165         }
166         int i = 7;
167         for(; i < url->length(); i++)
168                 if (url->get(i) == '/')
169                         break;
170
171         if ( i == url->length()) {
172                 printf("ERROR in openURL\n");
173                 exit(-1);
174         }
175         
176         char * host = (char *) malloc(i - 6);
177         memcpy(host, &url->internalBytes()->internalArray()[7], i-7);
178         host[i-7] = 0;
179         printf("%s\n", host);
180
181         char * message = (char *)malloc(sizeof("POST  HTTP/1.1\r\n") + sizeof("Host: \r\n") + 2*url->length());
182         
183         /* fill in the parameters */
184         int post = sprintf(message,"POST ");
185         /* copy data */
186         memcpy(&message[post], url->internalBytes()->internalArray(), url->length());
187         int endpost = sprintf(&message[post+url->length()], " HTTP/1.1\r\n");
188
189         int hostlen = sprintf(&message[endpost + post + url->length()], "Host: ");
190         memcpy(&message[endpost + post + url->length()+hostlen], url->internalBytes()->internalArray(), url->length());
191         sprintf(&message[endpost + post + 2*url->length()+hostlen], "\r\n");
192         
193         /* create the socket */
194         int sockfd = socket(AF_INET, SOCK_STREAM, 0);
195         if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);}
196         
197         /* lookup the ip address */
198         struct hostent *server = gethostbyname(host);
199         free(host);
200         
201         if (server == NULL) {printf("ERROR, no such host"); exit(-1);}
202         
203         /* fill in the structure */
204         struct sockaddr_in serv_addr;
205
206         memset(&serv_addr,0,sizeof(serv_addr));
207         serv_addr.sin_family = AF_INET;
208         serv_addr.sin_port = htons(80);
209         memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
210         
211         /* connect the socket */
212         if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
213                 printf("ERROR connecting");
214                 exit(-1);
215         }
216
217         /* send the request */
218         int total = strlen(message);
219         loopWrite(sockfd, message, total);
220
221         return sockfd;
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 >> 8) & 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) array[0]) << 24) |
314                 (((int32_t) array[1]) << 16) |
315                 (((int32_t) array[2]) << 8) |
316                 ((int32_t) array[3]);
317 }
318
319 void readSocketData(int fd, Array<char> *data) {
320         loopRead(fd, data->internalArray(), data->length());
321 }
322
323 void writeURLDataAndClose(int fd, Array<char> *data) {
324         dprintf(fd, "Content-Length: %d\r\n\r\n", data->length());
325         loopWrite(fd, data->internalArray(), data->length());
326 }
327
328 void closeURLReq(int fd) {
329         dprintf(fd, "\r\n");
330 }
331
332 void readURLData(int fd, Array<char> *output) {
333         loopRead(fd, output->internalArray(), output->length());
334 }
335
336 int readURLInt(int fd) {
337         char array[4];
338         loopRead(fd, array, 4);
339         return (((int32_t) array[0]) << 24) |
340                 (((int32_t) array[1]) << 16) |
341                 (((int32_t) array[2]) << 8) |
342                 ((int32_t) array[3]);
343 }
344
345 int getResponseCode(int fd) {
346         char response[600];
347         int offset = 0;
348         char newchar;
349         while(true) {
350                 int bytes = read(fd, &newchar, 1);
351                 if (bytes <= 0)
352                         break;
353                 if (offset == (sizeof(response) - 1)) {
354                         printf("Response too long");
355                         exit(-1);
356                 }
357                 response[offset++] = newchar;
358                 if (newchar == '\n')
359                         break;
360         }
361         response[offset] = 0;
362         int ver1 = 0, ver2 = 0, respcode = 0;
363         sscanf(response, "HTTP/%d.%d %d", &ver1, &ver2, &respcode);
364         printf("Response code %d\n", respcode);
365         return respcode;
366 }
367
368 void CloudComm::setSalt() {
369         if (salt != NULL) {
370                 // Salt already sent to server so don't set it again
371                 return;
372         }
373
374         int fd = -1;
375         try {
376                 Array<char> *saltTmp = new Array<char>(CloudComm_SALT_SIZE);
377                 random->nextBytes(saltTmp);
378
379                 char *buffer = (char *) malloc(baseurl->length() + 100);
380                 memcpy(buffer, baseurl->internalBytes(), baseurl->length());
381                 int offset = baseurl->length();
382                 offset += sprintf(&buffer[offset], "?req=setsalt");
383                 IoTString *urlstr = new IoTString(buffer);
384                 free(buffer);
385
386                 timer->startTime();
387                 fd = openURL(urlstr);
388                 writeURLDataAndClose(fd, saltTmp);
389
390                 int responsecode = getResponseCode(fd);
391                 if (responsecode != HttpURLConnection_HTTP_OK) {
392                         throw new Error("Invalid response");
393                 }
394
395                 timer->endTime();
396                 salt = saltTmp;
397         } catch (Exception *e) {
398                 timer->endTime();
399                 throw new ServerException("Failed setting salt", ServerException_TypeConnectTimeout);
400         }
401 }
402
403 bool CloudComm::getSalt() {
404         int fd = -1;
405         IoTString *urlstr = NULL;
406
407         try {
408                 char *buffer = (char *) malloc(baseurl->length() + 100);
409                 memcpy(buffer, baseurl->internalBytes(), baseurl->length());
410                 int offset = baseurl->length();
411                 offset += sprintf(&buffer[offset], "?req=getsalt");
412                 urlstr = new IoTString(buffer);
413                 free(buffer);
414         } catch (Exception *e) {
415                 throw new Error("getSlot failed");
416         }
417         try {
418                 timer->startTime();
419                 fd = openURL(urlstr);
420                 closeURLReq(fd);
421                 timer->endTime();
422         } catch (SocketTimeoutException *e) {
423                 timer->endTime();
424                 throw new ServerException("getSalt failed", ServerException_TypeConnectTimeout);
425         } catch (Exception *e) {
426                 throw new Error("getSlot failed");
427         }
428
429         try {
430                 timer->startTime();
431                 int responsecode = getResponseCode(fd);
432                 if (responsecode != HttpURLConnection_HTTP_OK) {
433                         throw new Error("Invalid response");
434                 }
435                 int salt_length = readURLInt(fd);
436                 Array<char> *tmp = new Array<char>(salt_length);
437                 readURLData(fd, tmp);
438                 salt = tmp;
439                 timer->endTime();
440                 return true;
441         } catch (SocketTimeoutException *e) {
442                 timer->endTime();
443                 throw new ServerException("getSalt failed", ServerException_TypeInputTimeout);
444         } catch (Exception *e) {
445                 throw new Error("getSlot failed");
446         }
447 }
448
449 Array<char> *CloudComm::createIV(int64_t machineId, int64_t localSequenceNumber) {
450         ByteBuffer *buffer = ByteBuffer_allocate(CloudComm_IV_SIZE);
451         buffer->putLong(machineId);
452         int64_t localSequenceNumberShifted = localSequenceNumber << 16;
453         buffer->putLong(localSequenceNumberShifted);
454         return buffer->array();
455 }
456
457 Array<char> *AESEncrypt(Array<char> *ivBytes, AESKey *key, Array<char> *data) {
458         Array<char> * output=new Array<char>(data->length());
459         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());
460         return output;
461 }
462
463 Array<char> *AESDecrypt(Array<char> *ivBytes, AESKey *key, Array<char> *data) {
464         Array<char> * output=new Array<char>(data->length());
465         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());
466         return output;
467 }
468
469 Array<char> *CloudComm::encryptSlotAndPrependIV(Array<char> *rawData, Array<char> *ivBytes) {
470         try {
471                 Array<char> *encryptedBytes = AESEncrypt(ivBytes, key, rawData);
472                 Array<char> *chars = new Array<char>(encryptedBytes->length() + CloudComm_IV_SIZE);
473                 System_arraycopy(ivBytes, 0, chars, 0, ivBytes->length());
474                 System_arraycopy(encryptedBytes, 0, chars, CloudComm_IV_SIZE, encryptedBytes->length());
475
476                 return chars;
477         } catch (Exception *e) {
478                 throw new Error("Failed To Encrypt");
479         }
480 }
481
482 Array<char> *CloudComm::stripIVAndDecryptSlot(Array<char> *rawData) {
483         try {
484                 Array<char> *ivBytes = new Array<char>(CloudComm_IV_SIZE);
485                 Array<char> *encryptedBytes = new Array<char>(rawData->length() - CloudComm_IV_SIZE);
486                 System_arraycopy(rawData, 0, ivBytes, 0, CloudComm_IV_SIZE);
487                 System_arraycopy(rawData, CloudComm_IV_SIZE, encryptedBytes, 0, encryptedBytes->length());
488                 return AESDecrypt(ivBytes, key, encryptedBytes);
489         } catch (Exception *e) {
490                 throw new Error("Failed To Decrypt");
491         }
492 }
493
494 /*
495  * API for putting a slot into the queue.  Returns NULL on success.
496  * On failure, the server will send slots with newer sequence
497  * numbers.
498  */
499 Array<Slot *> *CloudComm::putSlot(Slot *slot, int max) {
500         int fd = -1;
501         try {
502                 if (salt == NULL) {
503                         if (!getSalt()) {
504                                 throw new ServerException("putSlot failed", ServerException_TypeSalt);
505                         }
506                         initCrypt();
507                 }
508
509                 int64_t sequencenumber = slot->getSequenceNumber();
510                 Array<char> *slotBytes = slot->encode(mac);
511                 Array<char> *chars = encryptSlotAndPrependIV(slotBytes, slot->getSlotCryptIV());
512                 IoTString *url = buildRequest(true, sequencenumber, max);
513                 timer->startTime();
514                 fd = openURL(url);
515                 writeURLDataAndClose(fd, chars);
516                 timer->endTime();
517         } catch (ServerException *e) {
518                 timer->endTime();
519                 throw e;
520         } catch (SocketTimeoutException *e) {
521                 timer->endTime();
522                 throw new ServerException("putSlot failed", ServerException_TypeConnectTimeout);
523         } catch (Exception *e) {
524                 throw new Error("putSlot failed");
525         }
526
527         try {
528                 int respcode = getResponseCode(fd);
529                 timer->startTime();
530                 Array<char> *resptype = new Array<char>(7);
531                 readURLData(fd, resptype);
532                 timer->endTime();
533
534                 if (resptype->equals(getslot)) {
535                         return processSlots(fd);
536                 } else if (resptype->equals(putslot)) {
537                         return NULL;
538                 } else
539                         throw new Error("Bad response to putslot");
540         } catch (SocketTimeoutException *e) {
541                 timer->endTime();
542                 throw new ServerException("putSlot failed", ServerException_TypeInputTimeout);
543         } catch (Exception *e) {
544                 throw new Error("putSlot failed");
545         }
546 }
547
548 /**
549  * Request the server to send all slots with the given
550  * sequencenumber or newer->
551  */
552 Array<Slot *> *CloudComm::getSlots(int64_t sequencenumber) {
553         int fd = -1;
554         try {
555                 if (salt == NULL) {
556                         if (!getSalt()) {
557                                 throw new ServerException("getSlots failed", ServerException_TypeSalt);
558                         }
559                         initCrypt();
560                 }
561
562                 IoTString *url = buildRequest(false, sequencenumber, 0);
563                 timer->startTime();
564                 fd = openURL(url);
565                 closeURLReq(fd);
566                 timer->endTime();
567         } catch (SocketTimeoutException *e) {
568                 timer->endTime();
569                 throw new ServerException("getSlots failed", ServerException_TypeConnectTimeout);
570         } catch (ServerException *e) {
571                 timer->endTime();
572
573                 throw e;
574         } catch (Exception *e) {
575                 throw new Error("getSlots failed");
576         }
577
578         try {
579                 timer->startTime();
580                 int responsecode = getResponseCode(fd);
581                 Array<char> *resptype = new Array<char>(7);
582                 readURLData(fd, resptype);
583                 timer->endTime();
584                 if (!resptype->equals(getslot))
585                         throw new Error("Bad Response: ");
586
587                 return processSlots(fd);
588         } catch (SocketTimeoutException *e) {
589                 timer->endTime();
590                 throw new ServerException("getSlots failed", ServerException_TypeInputTimeout);
591         } catch (Exception *e) {
592                 throw new Error("getSlots failed");
593         }
594 }
595
596 /**
597  * Method that actually handles building Slot objects from the
598  * server response.  Shared by both putSlot and getSlots.
599  */
600 Array<Slot *> *CloudComm::processSlots(int fd) {
601         int numberofslots = readURLInt(fd);
602         Array<int> *sizesofslots = new Array<int>(numberofslots);
603         Array<Slot *> *slots = new Array<Slot *>(numberofslots);
604
605         for (int i = 0; i < numberofslots; i++)
606                 sizesofslots->set(i, readURLInt(fd));
607         for (int i = 0; i < numberofslots; i++) {
608                 Array<char> *rawData = new Array<char>(sizesofslots->get(i));
609                 readURLData(fd, rawData);
610                 Array<char> *data = stripIVAndDecryptSlot(rawData);
611                 slots->set(i, Slot_decode(table, data, mac));
612         }
613         return slots;
614 }
615
616 Array<char> *CloudComm::sendLocalData(Array<char> *sendData, int64_t localSequenceNumber, IoTString *host, int port) {
617         if (salt == NULL)
618                 return NULL;
619         try {
620                 printf("Passing Locally\n");
621                 mac->update(sendData, 0, sendData->length());
622                 Array<char> *genmac = mac->doFinal();
623                 Array<char> *totalData = new Array<char>(sendData->length() + genmac->length());
624                 System_arraycopy(sendData, 0, totalData, 0, sendData->length());
625                 System_arraycopy(genmac, 0, totalData, sendData->length(), genmac->length());
626
627                 // Encrypt the data for sending
628                 Array<char> *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber());
629                 Array<char> *encryptedData = encryptSlotAndPrependIV(totalData, iv);
630
631                 // Open a TCP socket connection to a local device
632                 int socket = createSocket(host, port);
633
634                 timer->startTime();
635                 // Send data to output (length of data, the data)
636                 writeSocketInt(socket, encryptedData->length());
637                 writeSocketData(socket, encryptedData);
638
639                 int lengthOfReturnData = readSocketInt(socket);
640                 Array<char> *returnData = new Array<char>(lengthOfReturnData);
641                 readSocketData(socket, returnData);
642                 timer->endTime();
643                 returnData = stripIVAndDecryptSlot(returnData);
644
645                 // We are done with this socket
646                 close(socket);
647                 mac->update(returnData, 0, returnData->length() - CloudComm_HMAC_SIZE);
648                 Array<char> *realmac = mac->doFinal();
649                 Array<char> *recmac = new Array<char>(CloudComm_HMAC_SIZE);
650                 System_arraycopy(returnData, returnData->length() - realmac->length(), recmac, 0, realmac->length());
651
652                 if (!recmac->equals(realmac))
653                         throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
654
655                 Array<char> *returnData2 = new Array<char>(lengthOfReturnData - recmac->length());
656                 System_arraycopy(returnData, 0, returnData2, 0, returnData2->length());
657
658                 return returnData2;
659         } catch (Exception *e) {
660                 printf("Exception\n");
661         }
662
663         return NULL;
664 }
665
666 void CloudComm::localServerWorkerFunction() {
667         int inputSocket = -1;
668
669         try {
670                 // Local server socket
671                 inputSocket = createSocket(listeningPort);
672         } catch (Exception *e) {
673                 throw new Error("Local server setup failure...");
674         }
675
676         while (!doEnd) {
677                 try {
678                         // Accept incoming socket
679                         int socket = acceptSocket(inputSocket);
680
681                         // Get the encrypted data from the server
682                         int dataSize = readSocketInt(socket);
683                         Array<char> *readData = new Array<char>(dataSize);
684                         readSocketData(socket, readData);
685                         timer->endTime();
686
687                         // Decrypt the data
688                         readData = stripIVAndDecryptSlot(readData);
689                         mac->update(readData, 0, readData->length() - CloudComm_HMAC_SIZE);
690                         Array<char> *genmac = mac->doFinal();
691                         Array<char> *recmac = new Array<char>(CloudComm_HMAC_SIZE);
692                         System_arraycopy(readData, readData->length() - recmac->length(), recmac, 0, recmac->length());
693
694                         if (!recmac->equals(genmac))
695                                 throw new Error("Local Error: Invalid HMAC!  Potential Attack!");
696
697                         Array<char> *returnData = new Array<char>(readData->length() - recmac->length());
698                         System_arraycopy(readData, 0, returnData, 0, returnData->length());
699
700                         // Process the data
701                         Array<char> *sendData = table->acceptDataFromLocal(returnData);
702                         mac->update(sendData, 0, sendData->length());
703                         Array<char> *realmac = mac->doFinal();
704                         Array<char> *totalData = new Array<char>(sendData->length() + realmac->length());
705                         System_arraycopy(sendData, 0, totalData, 0, sendData->length());
706                         System_arraycopy(realmac, 0, totalData, sendData->length(), realmac->length());
707
708                         // Encrypt the data for sending
709                         Array<char> *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber());
710                         Array<char> *encryptedData = encryptSlotAndPrependIV(totalData, iv);
711
712                         timer->startTime();
713                         // Send data to output (length of data, the data)
714                         writeSocketInt(socket, encryptedData->length());
715                         writeSocketData(socket, encryptedData);
716                         close(socket);
717                 } catch (Exception *e) {
718                 }
719         }
720
721         if (inputSocket != -1) {
722                 try {
723                         close(inputSocket);
724                 } catch (Exception *e) {
725                         throw new Error("Local server close failure...");
726                 }
727         }
728 }
729
730 void CloudComm::closeCloud() {
731         doEnd = true;
732
733         if (listeningPort > 0) {
734                 if (pthread_join(localServerThread, NULL) != 0)
735                         throw new Error("Local Server thread join issue...");
736         }
737 }