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