X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=version2%2Fsrc%2FC%2FCloudComm.cc;h=c20488dd268d59632d09634068961b918a9a878c;hb=b2bc9b5c707bd7d932d60cd4e8c1cb580b36b5b4;hp=c5da91a1b5d43166373797fc5c1af215aa300450;hpb=0b9aca2b62c74f68652b170a92271a98d5b96666;p=iotcloud.git diff --git a/version2/src/C/CloudComm.cc b/version2/src/C/CloudComm.cc index c5da91a..c20488d 100644 --- a/version2/src/C/CloudComm.cc +++ b/version2/src/C/CloudComm.cc @@ -1,4 +1,21 @@ #include "CloudComm.h" +#include "TimingSingleton.h" +#include "SecureRandom.h" +#include "IoTString.h" +#include "Error.h" +#include "URL.h" +#include "Mac.h" +#include "Table.h" +#include "Slot.h" +#include "Crypto.h" +#include "ByteBuffer.h" +#include "aes.h" +#include +#include +#include +#include +#include +#include /** * Empty Constructor needed for child class. @@ -12,50 +29,57 @@ CloudComm::CloudComm() : salt(NULL), table(NULL), listeningPort(-1), - localServerThread(NULL), - doEnd(false) - timer(TimingSingleton.getInstance()) + doEnd(false), + timer(TimingSingleton_getInstance()), + getslot(new Array("getslot", 7)), + putslot(new Array("putslot", 7)) { } +void *threadWrapper(void *cloud) { + CloudComm *c = (CloudComm *) cloud; + c->localServerWorkerFunction(); + return NULL; +} + /** * Constructor for actual use. Takes in the url and password. */ -CloudComm::CloudComm(Table _table, String _baseurl, String _password, int _listeningPort) : +CloudComm::CloudComm(Table *_table, IoTString *_baseurl, IoTString *_password, int _listeningPort) : baseurl(_baseurl), key(NULL), mac(NULL), - password(_password), + password(new IoTString(_password)), random(new SecureRandom()), salt(NULL), table(_table), listeningPort(_listeningPort), - localServerThread(NULL), - doEnd(false) - timer(TimingSingleton.getInstance()) { - if (this.listeningPort > 0) { - localServerThread = new Thread(new Runnable() { - void run() { - localServerWorkerFunction(); - } - }); - localServerThread.start(); + doEnd(false), + timer(TimingSingleton_getInstance()), + getslot(new Array("getslot", 7)), + putslot(new Array("putslot", 7)) { + if (listeningPort > 0) { + pthread_create(&localServerThread, NULL, threadWrapper, this); } } +CloudComm::~CloudComm() { + delete random; + delete getslot; + delete putslot; +} + /** * Generates Key from password. */ -SecretKeySpec *CloudComm::initKey() { +AESKey *CloudComm::initKey() { try { - PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), - salt, - 65536, - 128); - SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec); - return new SecretKeySpec(tmpkey.getEncoded(), "AES"); - } catch (Exception e) { - e.printStackTrace(); + AESKey *key = new AESKey(password->internalBytes(), + salt, + 65536, + 128); + return key; + } catch (Exception *e) { throw new Error("Failed generating key."); } } @@ -78,18 +102,16 @@ void CloudComm::initSecurity() { * Inits the HMAC generator. */ void CloudComm::initCrypt() { - if (password == NULL) { return; } - try { key = initKey(); + delete password; password = NULL;// drop password - mac = Mac.getInstance("HmacSHA256"); - mac.init(key); - } catch (Exception e) { - e.printStackTrace(); + mac = new Mac(); + mac->init(key); + } catch (Exception *e) { throw new Error("Failed To Initialize Ciphers"); } } @@ -97,335 +119,520 @@ void CloudComm::initCrypt() { /* * Builds the URL for the given request. */ -URL *CloudComm::buildRequest(bool isput, int64_t sequencenumber, int64_t maxentries) { - IoTString *reqstring = isput ? "req=putslot" : "req=getslot"; - IoTString *urlstr = baseurl + "?" + reqstring + "&seq=" + sequencenumber; +IoTString *CloudComm::buildRequest(bool isput, int64_t sequencenumber, int64_t maxentries) { + const char *reqstring = isput ? "req=putslot" : "req=getslot"; + char *buffer = (char *) malloc(baseurl->length() + 200); + memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length()); + int offset = baseurl->length(); + offset += sprintf(&buffer[offset], "?%s&seq=%" PRId64, reqstring, sequencenumber); if (maxentries != 0) - urlstr += "&max=" + maxentries; - return new URL(urlstr); + sprintf(&buffer[offset], "&max=%" PRId64, maxentries); + IoTString *urlstr = new IoTString(buffer); + return urlstr; } -void CloudComm::setSalt() { +void loopWrite(int fd, char *array, int bytestowrite) { + int byteswritten = 0; + while (bytestowrite) { + int bytes = write(fd, &array[byteswritten], bytestowrite); + if (bytes >= 0) { + byteswritten += bytes; + bytestowrite -= bytes; + } else { + printf("Error in write\n"); + exit(-1); + } + } +} - if (salt != NULL) { - // Salt already sent to server so dont set it again - return; +void loopRead(int fd, char *array, int bytestoread) { + int bytesread = 0; + while (bytestoread) { + int bytes = read(fd, &array[bytesread], bytestoread); + if (bytes >= 0) { + bytesread += bytes; + bytestoread -= bytes; + } else { + printf("Error in read\n"); + exit(-1); + } } +} - try { - char[] saltTmp = new char[SALT_SIZE]; - random.nextBytes(saltTmp); +WebConnection openURL(IoTString *url) { + if (url->length() < 7 || memcmp(url->internalBytes()->internalArray(), "http://", 7)) { + printf("BOGUS URL\n"); + exit(-1); + } + int i = 7; + for (; i < url->length(); i++) + if (url->get(i) == '/') + break; + + if ( i == url->length()) { + printf("ERROR in openURL\n"); + exit(-1); + } - for (int i = 0; i < SALT_SIZE; i++) { - System.out.println((int)saltTmp[i] & 255); - } + char *host = (char *) malloc(i - 6); + memcpy(host, &url->internalBytes()->internalArray()[7], i - 7); + host[i - 7] = 0; + printf("%s\n", host); + char *message = (char *)malloc(sizeof("POST HTTP/1.1\r\n") + sizeof("Host: \r\n") + 2 * url->length()); - URL url = new URL(baseurl + "?req=setsalt"); + /* fill in the parameters */ + int post = sprintf(message,"POST "); + /* copy data */ + memcpy(&message[post], &url->internalBytes()->internalArray()[i], url->length() - i); + int endpost = sprintf(&message[post + url->length() - i], " HTTP/1.1\r\n"); - timer.startTime(); - URLConnection con = url.openConnection(); - HttpURLConnection http = (HttpURLConnection) con; + int hostlen = sprintf(&message[endpost + post + url->length() - i], "Host: "); + memcpy(&message[endpost + post + url->length() + hostlen - i], host, i - 7); + sprintf(&message[endpost + post + url->length() + hostlen - 7], "\r\n"); - http.setRequestMethod("POST"); - http.setFixedLengthStreamingMode(saltTmp.length); - http.setDoOutput(true); - http.setConnectTimeout(TIMEOUT_MILLIS); + /* create the socket */ + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);} + /* lookup the ip address */ + struct hostent *server = gethostbyname(host); + free(host); - http.connect(); + if (server == NULL) {printf("ERROR, no such host"); exit(-1);} - OutputStream os = http.getOutputStream(); - os.write(saltTmp); - os.flush(); + /* fill in the structure */ + struct sockaddr_in serv_addr; - int responsecode = http.getResponseCode(); - if (responsecode != HttpURLConnection.HTTP_OK) { - // TODO: Remove this print - System.out.println(responsecode); - throw new Error("Invalid response"); + memset(&serv_addr,0,sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(80); + memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); + + /* connect the socket */ + if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) { + printf("ERROR connecting"); + exit(-1); + } + + /* send the request */ + int total = strlen(message); + loopWrite(sockfd, message, total); + return (WebConnection) {sockfd, -1}; +} + +int createSocket(IoTString *name, int port) { + char *host = (char *) malloc(name->length() + 1); + memcpy(host, name->internalBytes()->internalArray(), name->length()); + host[name->length()] = 0; + printf("%s\n", host); + /* How big is the message? */ + + /* create the socket */ + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) {printf("ERROR opening socket\n"); exit(-1);} + + /* lookup the ip address */ + struct hostent *server = gethostbyname(host); + free(host); + + if (server == NULL) {printf("ERROR, no such host"); exit(-1);} + + /* fill in the structure */ + struct sockaddr_in serv_addr; + + memset(&serv_addr,0,sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); + memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length); + + /* connect the socket */ + if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) { + printf("ERROR connecting"); + exit(-1); + } + + return sockfd; +} + +int createSocket(int port) { + int fd; + struct sockaddr_in sin; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = htonl(INADDR_ANY); + fd = socket(AF_INET, SOCK_STREAM, 0); + int n = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof (n)) < 0) { + close(fd); + printf("Create Socket Error\n"); + exit(-1); + } + if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + close(fd); + exit(-1); + } + if (listen(fd, 5) < 0) { + close(fd); + exit(-1); + } + return fd; +} + +int acceptSocket(int socket) { + struct sockaddr_in sin; + unsigned int sinlen = sizeof(sin); + int newfd = accept(socket, (struct sockaddr *)&sin, &sinlen); + int flag = 1; + setsockopt(newfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag)); + if (newfd < 0) { + printf("Accept Error\n"); + exit(-1); + } + return newfd; +} + +void writeSocketData(int fd, Array *data) { + loopWrite(fd, data->internalArray(), data->length()); +} + +void writeSocketInt(int fd, int32_t value) { + char array[4]; + array[0] = value >> 24; + array[1] = (value >> 16) & 0xff; + array[2] = (value >> 8) & 0xff; + array[3] = value & 0xff; + loopWrite(fd, array, 4); +} + +int readSocketInt(int fd) { + char array[4]; + loopRead(fd, array, 4); + return (((int32_t)(unsigned char) array[0]) << 24) | + (((int32_t)(unsigned char) array[1]) << 16) | + (((int32_t)(unsigned char) array[2]) << 8) | + ((int32_t)(unsigned char) array[3]); +} + +void readSocketData(int fd, Array *data) { + loopRead(fd, data->internalArray(), data->length()); +} + +void writeURLDataAndClose(WebConnection *wc, Array *data) { + dprintf(wc->fd, "Content-Length: %d\r\n\r\n", data->length()); + loopWrite(wc->fd, data->internalArray(), data->length()); +} + +void closeURLReq(WebConnection *wc) { + dprintf(wc->fd, "\r\n"); +} + +void readURLData(WebConnection *wc, Array *output) { + loopRead(wc->fd, output->internalArray(), output->length()); +} + +int readURLInt(WebConnection *wc) { + char array[4]; + loopRead(wc->fd, array, 4); + return (((int32_t)(unsigned char) array[0]) << 24) | + (((int32_t)(unsigned char) array[1]) << 16) | + (((int32_t)(unsigned char) array[2]) << 8) | + ((int32_t)(unsigned char) array[3]); +} + +void readLine(WebConnection *wc, char *response, int numBytes) { + int offset = 0; + char newchar; + while (true) { + int bytes = read(wc->fd, &newchar, 1); + if (bytes <= 0) + break; + if (offset == (numBytes - 1)) { + printf("Response too long"); + exit(-1); + } + response[offset++] = newchar; + if (newchar == '\n') + break; + } + response[offset] = 0; +} + +int getResponseCode(WebConnection *wc) { + char response[600]; + readLine(wc, response, sizeof(response)); + int ver1 = 0, ver2 = 0, respcode = 0; + sscanf(response, "HTTP/%d.%d %d", &ver1, &ver2, &respcode); + printf("Response code %d\n", respcode); + return respcode; +} + +void readHeaders(WebConnection *wc) { + char response[600]; + int numBytes; + + while (true) { + readLine(wc, response, sizeof(response)); + if (response[0] == '\r') + return; + else if (memcmp(response, "Content-Length:", sizeof("Content-Length:") - 1) == 0) { + sscanf(response, "Content-Length: %d", &numBytes); + wc->numBytes = numBytes; } + } +} - timer.endTime(); +void CloudComm::setSalt() { + if (salt != NULL) { + // Salt already sent to server so don't set it again + return; + } + + WebConnection wc = {-1, -1}; + try { + Array *saltTmp = new Array(CloudComm_SALT_SIZE); + random->nextBytes(saltTmp); + + char *buffer = (char *) malloc(baseurl->length() + 100); + memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length()); + int offset = baseurl->length(); + offset += sprintf(&buffer[offset], "?req=setsalt"); + IoTString *urlstr = new IoTString(buffer); + free(buffer); + + timer->startTime(); + wc = openURL(urlstr); + writeURLDataAndClose(&wc, saltTmp); + + int responsecode = getResponseCode(&wc); + if (responsecode != HttpURLConnection_HTTP_OK) { + throw new Error("Invalid response"); + } + close(wc.fd); + timer->endTime(); salt = saltTmp; - } catch (Exception e) { - // e.printStackTrace(); - timer.endTime(); - throw new ServerException("Failed setting salt", ServerException.TypeConnectTimeout); + } catch (Exception *e) { + timer->endTime(); + throw new ServerException("Failed setting salt", ServerException_TypeConnectTimeout); } } bool CloudComm::getSalt() { - URL *url = NULL; - URLConnection *con = NULL; - HttpURLConnection *http = NULL; + WebConnection wc = {-1, -1}; + IoTString *urlstr = NULL; try { - url = new URL(baseurl + "?req=getsalt"); - } catch (Exception e) { - // e.printStackTrace(); + char *buffer = (char *) malloc(baseurl->length() + 100); + memcpy(buffer, baseurl->internalBytes()->internalArray(), baseurl->length()); + int offset = baseurl->length(); + offset += sprintf(&buffer[offset], "?req=getsalt"); + urlstr = new IoTString(buffer); + free(buffer); + } catch (Exception *e) { throw new Error("getSlot failed"); } try { - - timer.startTime(); - con = url.openConnection(); - http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.setConnectTimeout(TIMEOUT_MILLIS); - http.setReadTimeout(TIMEOUT_MILLIS); - - - http.connect(); - timer.endTime(); - } catch (SocketTimeoutException e) { - timer.endTime(); - throw new ServerException("getSalt failed", ServerException.TypeConnectTimeout); - } catch (Exception e) { - // e.printStackTrace(); + timer->startTime(); + wc = openURL(urlstr); + closeURLReq(&wc); + timer->endTime(); + } catch (SocketTimeoutException *e) { + timer->endTime(); + throw new ServerException("getSalt failed", ServerException_TypeConnectTimeout); + } catch (Exception *e) { throw new Error("getSlot failed"); } try { - - timer.startTime(); - - int responsecode = http.getResponseCode(); - if (responsecode != HttpURLConnection.HTTP_OK) { - // TODO: Remove this print - // System.out.println(responsecode); + timer->startTime(); + int responsecode = getResponseCode(&wc); + readHeaders(&wc); + if (responsecode != HttpURLConnection_HTTP_OK) { throw new Error("Invalid response"); } - - InputStream is = http.getInputStream(); - if (is.available() > 0) { - DataInputStream dis = new DataInputStream(is); - int salt_length = dis.readInt(); - char [] tmp = new char[salt_length]; - dis.readFully(tmp); - salt = tmp; - timer.endTime(); - - return true; - } else { - timer.endTime(); - + if (wc.numBytes == 0) { + timer->endTime(); + close(wc.fd); return false; } - } catch (SocketTimeoutException e) { - timer.endTime(); - throw new ServerException("getSalt failed", ServerException.TypeInputTimeout); - } catch (Exception e) { - // e.printStackTrace(); + + int salt_length = readURLInt(&wc); + Array *tmp = new Array(salt_length); + readURLData(&wc, tmp); + close(wc.fd); + + salt = tmp; + timer->endTime(); + return true; + } catch (SocketTimeoutException *e) { + timer->endTime(); + throw new ServerException("getSalt failed", ServerException_TypeInputTimeout); + } catch (Exception *e) { throw new Error("getSlot failed"); } } Array *CloudComm::createIV(int64_t machineId, int64_t localSequenceNumber) { - ByteBuffer buffer = ByteBuffer.allocate(IV_SIZE); - buffer.putLong(machineId); + ByteBuffer *buffer = ByteBuffer_allocate(CloudComm_IV_SIZE); + buffer->putLong(machineId); int64_t localSequenceNumberShifted = localSequenceNumber << 16; - buffer.putLong(localSequenceNumberShifted); - return buffer.array(); + buffer->putLong(localSequenceNumberShifted); + return buffer->array(); } -Array *CloudComm::encryptSlotAndPrependIV(Array *rawData, Array *ivBytes) { - try { - IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); - Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); - cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); +Array *AESEncrypt(Array *ivBytes, AESKey *key, Array *data) { + Array *output = new Array(data->length()); + aes_encrypt_ctr((BYTE *)data->internalArray(), data->length(), (BYTE *) output->internalArray(), (WORD *)key->getKeySchedule(), key->getKey()->length() * 8, (BYTE *)ivBytes->internalArray()); + return output; +} - char[] encryptedBytes = cipher.doFinal(rawData); +Array *AESDecrypt(Array *ivBytes, AESKey *key, Array *data) { + Array *output = new Array(data->length()); + aes_decrypt_ctr((BYTE *)data->internalArray(), data->length(), (BYTE *)output->internalArray(), (WORD *)key->getKeySchedule(), key->getKey()->length() * 8, (BYTE *)ivBytes->internalArray()); + return output; +} - char[] chars = new char[encryptedBytes.length + IV_SIZE]; - System.arraycopy(ivBytes, 0, chars, 0, ivBytes.length); - System.arraycopy(encryptedBytes, 0, chars, IV_SIZE, encryptedBytes.length); +Array *CloudComm::encryptSlotAndPrependIV(Array *rawData, Array *ivBytes) { + try { + Array *encryptedBytes = AESEncrypt(ivBytes, key, rawData); + Array *origBytes = AESDecrypt(ivBytes, key, encryptedBytes); + if (!rawData->equals(origBytes)) + throw new Error("BAD"); + Array *chars = new Array(encryptedBytes->length() + CloudComm_IV_SIZE); + System_arraycopy(ivBytes, 0, chars, 0, ivBytes->length()); + System_arraycopy(encryptedBytes, 0, chars, CloudComm_IV_SIZE, encryptedBytes->length()); return chars; - - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception *e) { throw new Error("Failed To Encrypt"); } } - Array *CloudComm::stripIVAndDecryptSlot(Array *rawData) { try { - Array *ivBytes = new char[IV_SIZE]; - Array *encryptedBytes = new char[rawData.length - IV_SIZE]; - System.arraycopy(rawData, 0, ivBytes, 0, IV_SIZE); - System.arraycopy(rawData, IV_SIZE, encryptedBytes, 0, encryptedBytes.length); - - IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); - - Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, key, ivSpec); - return cipher.doFinal(encryptedBytes); - - } catch (Exception e) { - e.printStackTrace(); + Array *ivBytes = new Array(CloudComm_IV_SIZE); + Array *encryptedBytes = new Array(rawData->length() - CloudComm_IV_SIZE); + System_arraycopy(rawData, 0, ivBytes, 0, CloudComm_IV_SIZE); + System_arraycopy(rawData, CloudComm_IV_SIZE, encryptedBytes, 0, encryptedBytes->length()); + return AESDecrypt(ivBytes, key, encryptedBytes); + } catch (Exception *e) { throw new Error("Failed To Decrypt"); } } - /* * API for putting a slot into the queue. Returns NULL on success. * On failure, the server will send slots with newer sequence * numbers. */ Array *CloudComm::putSlot(Slot *slot, int max) { - URL url = NULL; - URLConnection con = NULL; - HttpURLConnection http = NULL; - + WebConnection wc = {-1, -1}; try { if (salt == NULL) { if (!getSalt()) { - throw new ServerException("putSlot failed", ServerException.TypeSalt); + throw new ServerException("putSlot failed", ServerException_TypeSalt); } initCrypt(); } - int64_t sequencenumber = slot.getSequenceNumber(); - char[] slotBytes = slot.encode(mac); - // slotBytes = encryptCipher.doFinal(slotBytes); - - // char[] iVBytes = slot.getSlotCryptIV(); - - // char[] chars = new char[slotBytes.length + IV_SIZE]; - // System.arraycopy(iVBytes, 0, chars, 0, iVBytes.length); - // System.arraycopy(slotBytes, 0, chars, IV_SIZE, slotBytes.length); - - - char[] chars = encryptSlotAndPrependIV(slotBytes, slot.getSlotCryptIV()); - - url = buildRequest(true, sequencenumber, max); - - timer.startTime(); - con = url.openConnection(); - http = (HttpURLConnection) con; - - http.setRequestMethod("POST"); - http.setFixedLengthStreamingMode(chars.length); - http.setDoOutput(true); - http.setConnectTimeout(TIMEOUT_MILLIS); - http.setReadTimeout(TIMEOUT_MILLIS); - http.connect(); - - OutputStream os = http.getOutputStream(); - os.write(chars); - os.flush(); - - timer.endTime(); - - - // System.out.println("Bytes Sent: " + chars.length); - } catch (ServerException e) { - timer.endTime(); - + int64_t sequencenumber = slot->getSequenceNumber(); + Array *slotBytes = slot->encode(mac); + Array *chars = encryptSlotAndPrependIV(slotBytes, slot->getSlotCryptIV()); + IoTString *url = buildRequest(true, sequencenumber, max); + timer->startTime(); + wc = openURL(url); + writeURLDataAndClose(&wc, chars); + timer->endTime(); + } catch (ServerException *e) { + timer->endTime(); throw e; - } catch (SocketTimeoutException e) { - timer.endTime(); - - throw new ServerException("putSlot failed", ServerException.TypeConnectTimeout); - } catch (Exception e) { - // e.printStackTrace(); + } catch (SocketTimeoutException *e) { + timer->endTime(); + throw new ServerException("putSlot failed", ServerException_TypeConnectTimeout); + } catch (Exception *e) { throw new Error("putSlot failed"); } - - try { - timer.startTime(); - InputStream is = http.getInputStream(); - DataInputStream dis = new DataInputStream(is); - char[] resptype = new char[7]; - dis.readFully(resptype); - timer.endTime(); - - if (Arrays.equals(resptype, "getslot".getBytes())) { - return processSlots(dis); - } else if (Arrays.equals(resptype, "putslot".getBytes())) { + int respcode = getResponseCode(&wc); + readHeaders(&wc); + timer->startTime(); + Array *resptype = new Array(7); + readURLData(&wc, resptype); + timer->endTime(); + + if (resptype->equals(getslot)) { + Array *tmp = processSlots(&wc); + close(wc.fd); + return tmp; + } else if (resptype->equals(putslot)) { + close(wc.fd); return NULL; - } else + } else { + close(wc.fd); throw new Error("Bad response to putslot"); - - } catch (SocketTimeoutException e) { - timer.endTime(); - throw new ServerException("putSlot failed", ServerException.TypeInputTimeout); - } catch (Exception e) { - // e.printStackTrace(); + } + } catch (SocketTimeoutException *e) { + timer->endTime(); + close(wc.fd); + throw new ServerException("putSlot failed", ServerException_TypeInputTimeout); + } catch (Exception *e) { throw new Error("putSlot failed"); } } /** * Request the server to send all slots with the given - * sequencenumber or newer. + * sequencenumber or newer-> */ Array *CloudComm::getSlots(int64_t sequencenumber) { - URL url = NULL; - URLConnection con = NULL; - HttpURLConnection http = NULL; - + WebConnection wc = {-1, -1}; try { if (salt == NULL) { if (!getSalt()) { - throw new ServerException("getSlots failed", ServerException.TypeSalt); + throw new ServerException("getSlots failed", ServerException_TypeSalt); } initCrypt(); } - url = buildRequest(false, sequencenumber, 0); - timer.startTime(); - con = url.openConnection(); - http = (HttpURLConnection) con; - http.setRequestMethod("POST"); - http.setConnectTimeout(TIMEOUT_MILLIS); - http.setReadTimeout(TIMEOUT_MILLIS); - - - - http.connect(); - timer.endTime(); - - } catch (SocketTimeoutException e) { - timer.endTime(); - - throw new ServerException("getSlots failed", ServerException.TypeConnectTimeout); - } catch (ServerException e) { - timer.endTime(); + IoTString *url = buildRequest(false, sequencenumber, 0); + timer->startTime(); + wc = openURL(url); + closeURLReq(&wc); + timer->endTime(); + } catch (SocketTimeoutException *e) { + timer->endTime(); + throw new ServerException("getSlots failed", ServerException_TypeConnectTimeout); + } catch (ServerException *e) { + timer->endTime(); throw e; - } catch (Exception e) { - // e.printStackTrace(); + } catch (Exception *e) { throw new Error("getSlots failed"); } try { - - timer.startTime(); - InputStream is = http.getInputStream(); - DataInputStream dis = new DataInputStream(is); - char[] resptype = new char[7]; - - dis.readFully(resptype); - timer.endTime(); - - if (!Arrays.equals(resptype, "getslot".getBytes())) - throw new Error("Bad Response: " + new String(resptype)); - - return processSlots(dis); - } catch (SocketTimeoutException e) { - timer.endTime(); - - throw new ServerException("getSlots failed", ServerException.TypeInputTimeout); - } catch (Exception e) { - // e.printStackTrace(); + timer->startTime(); + int responsecode = getResponseCode(&wc); + readHeaders(&wc); + Array *resptype = new Array(7); + readURLData(&wc, resptype); + timer->endTime(); + if (!resptype->equals(getslot)) + throw new Error("Bad Response: "); + + Array *tmp = processSlots(&wc); + close(wc.fd); + return tmp; + } catch (SocketTimeoutException *e) { + timer->endTime(); + close(wc.fd); + throw new ServerException("getSlots failed", ServerException_TypeInputTimeout); + } catch (Exception *e) { throw new Error("getSlots failed"); } } @@ -434,198 +641,141 @@ Array *CloudComm::getSlots(int64_t sequencenumber) { * Method that actually handles building Slot objects from the * server response. Shared by both putSlot and getSlots. */ -Array *CloudComm::processSlots(DataInputStream dis) { - int numberofslots = dis.readInt(); - int[] sizesofslots = new int[numberofslots]; +Array *CloudComm::processSlots(WebConnection *wc) { + int numberofslots = readURLInt(wc); + Array *sizesofslots = new Array(numberofslots); + Array *slots = new Array(numberofslots); - Slot[] slots = new Slot[numberofslots]; for (int i = 0; i < numberofslots; i++) - sizesofslots[i] = dis.readInt(); - + sizesofslots->set(i, readURLInt(wc)); for (int i = 0; i < numberofslots; i++) { - - char[] rawData = new char[sizesofslots[i]]; - dis.readFully(rawData); - - - // char[] data = new char[rawData.length - IV_SIZE]; - // System.arraycopy(rawData, IV_SIZE, data, 0, data.length); - - - char[] data = stripIVAndDecryptSlot(rawData); - - // data = decryptCipher.doFinal(data); - - slots[i] = Slot.decode(table, data, mac); + Array *rawData = new Array(sizesofslots->get(i)); + readURLData(wc, rawData); + Array *data = stripIVAndDecryptSlot(rawData); + slots->set(i, Slot_decode(table, data, mac)); } - dis.close(); return slots; } -Array *sendLocalData(Array *sendData, int64_t localSequenceNumber, String host, int port) { - - if (salt == NULL) { +Array *CloudComm::sendLocalData(Array *sendData, int64_t localSequenceNumber, IoTString *host, int port) { + if (salt == NULL) return NULL; - } try { - System.out.println("Passing Locally"); - - mac.update(sendData); - char[] genmac = mac.doFinal(); - char[] totalData = new char[sendData.length + genmac.length]; - System.arraycopy(sendData, 0, totalData, 0, sendData.length); - System.arraycopy(genmac, 0, totalData, sendData.length, genmac.length); + printf("Passing Locally\n"); + mac->update(sendData, 0, sendData->length()); + Array *genmac = mac->doFinal(); + Array *totalData = new Array(sendData->length() + genmac->length()); + System_arraycopy(sendData, 0, totalData, 0, sendData->length()); + System_arraycopy(genmac, 0, totalData, sendData->length(), genmac->length()); // Encrypt the data for sending - // char[] encryptedData = encryptCipher.doFinal(totalData); - // char[] encryptedData = encryptCipher.doFinal(totalData); - char[] iv = createIV(table.getMachineId(), table.getLocalSequenceNumber()); - char[] encryptedData = encryptSlotAndPrependIV(totalData, iv); + Array *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber()); + Array *encryptedData = encryptSlotAndPrependIV(totalData, iv); // Open a TCP socket connection to a local device - Socket socket = new Socket(host, port); - socket.setReuseAddress(true); - DataOutputStream output = new DataOutputStream(socket.getOutputStream()); - DataInputStream input = new DataInputStream(socket.getInputStream()); + int socket = createSocket(host, port); - - timer.startTime(); + timer->startTime(); // Send data to output (length of data, the data) - output.writeInt(encryptedData.length); - output.write(encryptedData, 0, encryptedData.length); - output.flush(); - - int lengthOfReturnData = input.readInt(); - char[] returnData = new char[lengthOfReturnData]; - input.readFully(returnData); - - timer.endTime(); + writeSocketInt(socket, encryptedData->length()); + writeSocketData(socket, encryptedData); - // returnData = decryptCipher.doFinal(returnData); + int lengthOfReturnData = readSocketInt(socket); + Array *returnData = new Array(lengthOfReturnData); + readSocketData(socket, returnData); + timer->endTime(); returnData = stripIVAndDecryptSlot(returnData); - // returnData = decryptCipher.doFinal(returnData); // We are done with this socket - socket.close(); + close(socket); + mac->update(returnData, 0, returnData->length() - CloudComm_HMAC_SIZE); + Array *realmac = mac->doFinal(); + Array *recmac = new Array(CloudComm_HMAC_SIZE); + System_arraycopy(returnData, returnData->length() - realmac->length(), recmac, 0, realmac->length()); - mac.update(returnData, 0, returnData.length - HMAC_SIZE); - char[] realmac = mac.doFinal(); - char[] recmac = new char[HMAC_SIZE]; - System.arraycopy(returnData, returnData.length - realmac.length, recmac, 0, realmac.length); - - if (!Arrays.equals(recmac, realmac)) + if (!recmac->equals(realmac)) throw new Error("Local Error: Invalid HMAC! Potential Attack!"); - char[] returnData2 = new char[lengthOfReturnData - recmac.length]; - System.arraycopy(returnData, 0, returnData2, 0, returnData2.length); + Array *returnData2 = new Array(lengthOfReturnData - recmac->length()); + System_arraycopy(returnData, 0, returnData2, 0, returnData2->length()); return returnData2; - } catch (Exception e) { - e.printStackTrace(); - // throw new Error("Local comms failure..."); - + } catch (Exception *e) { + printf("Exception\n"); } return NULL; } void CloudComm::localServerWorkerFunction() { - - ServerSocket inputSocket = NULL; + int inputSocket = -1; try { // Local server socket - inputSocket = new ServerSocket(listeningPort); - inputSocket.setReuseAddress(true); - inputSocket.setSoTimeout(TIMEOUT_MILLIS); - } catch (Exception e) { - e.printStackTrace(); + inputSocket = createSocket(listeningPort); + } catch (Exception *e) { throw new Error("Local server setup failure..."); } while (!doEnd) { - try { // Accept incoming socket - Socket socket = inputSocket.accept(); - - DataInputStream input = new DataInputStream(socket.getInputStream()); - DataOutputStream output = new DataOutputStream(socket.getOutputStream()); + int socket = acceptSocket(inputSocket); // Get the encrypted data from the server - int dataSize = input.readInt(); - char[] readData = new char[dataSize]; - input.readFully(readData); - - timer.endTime(); + int dataSize = readSocketInt(socket); + Array *readData = new Array(dataSize); + readSocketData(socket, readData); + timer->endTime(); // Decrypt the data - // readData = decryptCipher.doFinal(readData); readData = stripIVAndDecryptSlot(readData); + mac->update(readData, 0, readData->length() - CloudComm_HMAC_SIZE); + Array *genmac = mac->doFinal(); + Array *recmac = new Array(CloudComm_HMAC_SIZE); + System_arraycopy(readData, readData->length() - recmac->length(), recmac, 0, recmac->length()); - mac.update(readData, 0, readData.length - HMAC_SIZE); - char[] genmac = mac.doFinal(); - char[] recmac = new char[HMAC_SIZE]; - System.arraycopy(readData, readData.length - recmac.length, recmac, 0, recmac.length); - - if (!Arrays.equals(recmac, genmac)) + if (!recmac->equals(genmac)) throw new Error("Local Error: Invalid HMAC! Potential Attack!"); - char[] returnData = new char[readData.length - recmac.length]; - System.arraycopy(readData, 0, returnData, 0, returnData.length); + Array *returnData = new Array(readData->length() - recmac->length()); + System_arraycopy(readData, 0, returnData, 0, returnData->length()); // Process the data - // char[] sendData = table.acceptDataFromLocal(readData); - char[] sendData = table.acceptDataFromLocal(returnData); - - - mac.update(sendData); - char[] realmac = mac.doFinal(); - char[] totalData = new char[sendData.length + realmac.length]; - System.arraycopy(sendData, 0, totalData, 0, sendData.length); - System.arraycopy(realmac, 0, totalData, sendData.length, realmac.length); + Array *sendData = table->acceptDataFromLocal(returnData); + mac->update(sendData, 0, sendData->length()); + Array *realmac = mac->doFinal(); + Array *totalData = new Array(sendData->length() + realmac->length()); + System_arraycopy(sendData, 0, totalData, 0, sendData->length()); + System_arraycopy(realmac, 0, totalData, sendData->length(), realmac->length()); // Encrypt the data for sending - // char[] encryptedData = encryptCipher.doFinal(totalData); - char[] iv = createIV(table.getMachineId(), table.getLocalSequenceNumber()); - char[] encryptedData = encryptSlotAndPrependIV(totalData, iv); - + Array *iv = createIV(table->getMachineId(), table->getLocalSequenceNumber()); + Array *encryptedData = encryptSlotAndPrependIV(totalData, iv); - timer.startTime(); + timer->startTime(); // Send data to output (length of data, the data) - output.writeInt(encryptedData.length); - output.write(encryptedData, 0, encryptedData.length); - output.flush(); - - // close the socket - socket.close(); - } catch (Exception e) { - + writeSocketInt(socket, encryptedData->length()); + writeSocketData(socket, encryptedData); + close(socket); + } catch (Exception *e) { } } - if (inputSocket != NULL) { + if (inputSocket != -1) { try { - inputSocket.close(); - } catch (Exception e) { - e.printStackTrace(); + close(inputSocket); + } catch (Exception *e) { throw new Error("Local server close failure..."); } } } -void CloudComm::close() { +void CloudComm::closeCloud() { doEnd = true; - if (localServerThread != NULL) { - try { - localServerThread.join(); - } catch (Exception e) { - e.printStackTrace(); + if (listeningPort > 0) { + if (pthread_join(localServerThread, NULL) != 0) throw new Error("Local Server thread join issue..."); - } } - - // System.out.println("Done Closing Cloud Comm"); } -