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