From da3251e24dcc3c3503834cd70bc5b23a97b3eee0 Mon Sep 17 00:00:00 2001 From: Brian Demsky <bdemsky@plrg.eecs.uci.edu> Date: Tue, 26 Jul 2016 18:37:50 -0700 Subject: [PATCH] Add support for salts and crypto --- src/java/iotcloud/CloudComm.java | 99 +++++++++++++++++++++----------- src/java/iotcloud/Table.java | 1 + src/java/iotcloud/issues.txt | 3 +- src/server/iotquery.cpp | 78 +++++++++++++++++++++++-- src/server/iotquery.h | 7 +++ 5 files changed, 145 insertions(+), 43 deletions(-) diff --git a/src/java/iotcloud/CloudComm.java b/src/java/iotcloud/CloudComm.java index 49217ec..964b7c0 100644 --- a/src/java/iotcloud/CloudComm.java +++ b/src/java/iotcloud/CloudComm.java @@ -22,8 +22,8 @@ class CloudComm { String password; SecureRandom random; static final int SALT_SIZE = 8; - static final int IV_SIZE = 16; - + byte salt[]; + /** * Empty Constructor needed for child class. */ @@ -45,7 +45,7 @@ class CloudComm { * Generates Key from password. */ - private SecretKeySpec initKey(byte[] salt) { + private SecretKeySpec initKey() { try { PBEKeySpec keyspec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128); SecretKey tmpkey = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(keyspec); @@ -60,27 +60,16 @@ class CloudComm { * Inits the HMAC generator. */ - private byte[] initCrypt(byte[] salt) { + private void initCrypt() { try { - SecretKeySpec key=initKey(salt); + SecretKeySpec key=initKey(); + password = null; // drop password mac = Mac.getInstance("HmacSHA256"); mac.init(key); - encryptCipher =Cipher.getInstance("AES/CBC/PKCS5Padding"); + encryptCipher =Cipher.getInstance("AES/ECB/PKCS5Padding"); encryptCipher.init(Cipher.ENCRYPT_MODE, key); - return encryptCipher.getIV(); - } catch (Exception e) { - e.printStackTrace(); - throw new Error("Failed To Initialize Ciphers"); - } - } - - private void initDeCrypt(byte[] salt, byte[] iv) { - try { - SecretKeySpec key=initKey(salt); - mac = Mac.getInstance("HmacSHA256"); - mac.init(key); - Cipher decryptCipher =Cipher.getInstance("AES/CBC/PKCS5Padding"); - decryptCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + decryptCipher =Cipher.getInstance("AES/ECB/PKCS5Padding"); + decryptCipher.init(Cipher.DECRYPT_MODE, key); } catch (Exception e) { e.printStackTrace(); throw new Error("Failed To Initialize Ciphers"); @@ -98,33 +87,72 @@ class CloudComm { urlstr += "&max="+maxentries; return new URL(urlstr); } + + public void setSalt() { + try { + salt = new byte[SALT_SIZE]; + random.nextBytes(salt); + URL url=new URL(baseurl+"?req=setsalt"); + URLConnection con=url.openConnection(); + HttpURLConnection http = (HttpURLConnection) con; + http.setRequestMethod("POST"); + http.setFixedLengthStreamingMode(salt.length); + http.setDoOutput(true); + http.connect(); + OutputStream os=http.getOutputStream(); + os.write(salt); + int responsecode=http.getResponseCode(); + if (responsecode != HttpURLConnection.HTTP_OK) + throw new Error("Invalid response"); + } catch (Exception e) { + e.printStackTrace(); + throw new Error("Failed setting salt"); + } + initCrypt(); + } + private void getSalt() throws Exception { + URL url=new URL(baseurl+"?req=getsalt"); + URLConnection con=url.openConnection(); + HttpURLConnection http = (HttpURLConnection) con; + http.setRequestMethod("POST"); + http.connect(); + + InputStream is=http.getInputStream(); + DataInputStream dis=new DataInputStream(is); + int salt_length=dis.readInt(); + byte [] tmp=new byte[salt_length]; + dis.readFully(tmp); + salt=tmp; + } + /* * API for putting a slot into the queue. Returns null on success. * On failure, the server will send slots with newer sequence * numbers. */ - public Slot[] putSlot(Slot slot, int max) { + Slot[] putSlot(Slot slot, int max) { try { - long sequencenumber=slot.getSequenceNumber(); - byte[] salt=new byte[SALT_SIZE]; - random.nextBytes(salt); - byte[] iv=initCrypt(salt); + if (salt == null) { + getSalt(); + initCrypt(); + } + long sequencenumber=slot.getSequenceNumber(); byte[] bytes=slot.encode(mac); + bytes = encryptCipher.doFinal(bytes); + URL url=buildRequest(true, sequencenumber, max); URLConnection con=url.openConnection(); HttpURLConnection http = (HttpURLConnection) con; + http.setRequestMethod("POST"); http.setFixedLengthStreamingMode(bytes.length); http.setDoOutput(true); http.connect(); OutputStream os=http.getOutputStream(); - os.write(salt); - os.write(iv); - bytes = encryptCipher.doFinal(bytes); os.write(bytes); InputStream is=http.getInputStream(); @@ -138,6 +166,7 @@ class CloudComm { else throw new Error("Bad response to putslot"); } catch (Exception e) { + e.printStackTrace(); throw new Error("putSlot failed"); } } @@ -147,8 +176,13 @@ class CloudComm { * sequencenumber or newer. */ - public Slot[] getSlots(long sequencenumber) { + Slot[] getSlots(long sequencenumber) { try { + if (salt == null) { + getSalt(); + initCrypt(); + } + URL url=buildRequest(false, sequencenumber, 0); URLConnection con=url.openConnection(); HttpURLConnection http = (HttpURLConnection) con; @@ -165,6 +199,7 @@ class CloudComm { else return processSlots(dis); } catch (Exception e) { + e.printStackTrace(); throw new Error("getSlots failed"); } } @@ -182,12 +217,6 @@ class CloudComm { sizesofslots[i]=dis.readInt(); for(int i=0; i<numberofslots; i++) { - byte[] salt=new byte[SALT_SIZE]; - byte[] iv=new byte[IV_SIZE]; - dis.readFully(salt); - dis.readFully(iv); - initDeCrypt(salt, iv); - byte[] data=new byte[sizesofslots[i]]; dis.readFully(data); diff --git a/src/java/iotcloud/Table.java b/src/java/iotcloud/Table.java index 26fc7a1..028025f 100644 --- a/src/java/iotcloud/Table.java +++ b/src/java/iotcloud/Table.java @@ -62,6 +62,7 @@ final public class Table { } public void initTable() { + cloud.setSalt();//Set the salt Slot s=new Slot(1, localmachineid); TableStatus status=new TableStatus(s, numslots); s.addEntry(status); diff --git a/src/java/iotcloud/issues.txt b/src/java/iotcloud/issues.txt index 07e6788..816b6b1 100644 --- a/src/java/iotcloud/issues.txt +++ b/src/java/iotcloud/issues.txt @@ -1,2 +1 @@ -1) add crypto -2) handle Salt +1) add better resizing support...gets stuck when it is full now... diff --git a/src/server/iotquery.cpp b/src/server/iotquery.cpp index 117ca30..0b1c4b3 100644 --- a/src/server/iotquery.cpp +++ b/src/server/iotquery.cpp @@ -32,7 +32,9 @@ IoTQuery::IoTQuery(FCGX_Request *request) : numqueueentries(DEFAULT_SIZE), fd(-1), reqGetSlot(false), - reqPutSlot(false) { + reqPutSlot(false), + reqSetSalt(false), + reqGetSalt(false) { } IoTQuery::~IoTQuery() { @@ -67,14 +69,17 @@ void IoTQuery::decodeQuery() { char * str=new char[len+1]; memcpy(str, query, len+1); char *tok_ptr=str; - + /* Parse commands */ char *command=strsep(&tok_ptr, "&"); if (strncmp(command, "req=putslot", 11) == 0) reqPutSlot = true; - - if (strncmp(command, "req=getslot", 11) == 0) + else if (strncmp(command, "req=getslot", 11) == 0) reqGetSlot = true; + else if (strncmp(command, "req=setsalt", 11) == 0) + reqSetSalt = true; + else if (strncmp(command, "req=getsalt", 11) == 0) + reqGetSalt = true; /* Load Sequence Number for request */ char *sequencenumber_str = strsep(&tok_ptr, "&"); @@ -200,6 +205,48 @@ void IoTQuery::getSlot() { } } +/** + * The method setSalt handles a setSalt request from the client. + */ + +void IoTQuery::setSalt() { + /* Write the slot data we received to a SLOT file */ + char *filename = getSaltFileName(); + int saltfd = open(filename, O_CREAT|O_WRONLY, S_IRUSR| S_IWUSR); + doWrite(saltfd, data, length); + char response[0]; + sendResponse(response, 0); + close(saltfd); + delete filename; +} + +/** + * The method getSalt handles a setSalt request from the client. + */ + +void IoTQuery::getSalt() { + /* Write the slot data we received to a SLOT file */ + char *filename = getSaltFileName(); + int filesize = 0; + struct stat st; + if (stat(filename, &st) == 0) { + filesize=st.st_size; + } else { + delete filename; + return; + } + int saltfd = open(filename, O_RDONLY); + int responsesize = filesize + sizeof(int); + char * response = new char[responsesize]; + doRead(saltfd, response+ sizeof(int), filesize); + int n_filesize=htonl(filesize); + *((int*) response) = n_filesize; + sendResponse(response, responsesize); + close(saltfd); + delete filename; + delete response; +} + /** * The method putSlot handles a putSlot request from the client */ @@ -258,7 +305,22 @@ char * IoTQuery::getSlotFileName(long long seqnum) { directory size*/ char * filename=new char[25+directorylen]; - snprintf(filename, 24+directorylen+1, "%s/SLOT%lld", directory, seqnum); + snprintf(filename, 25+directorylen, "%s/SLOT%lld", directory, seqnum); + return filename; +} + +/** + * Computes the name for a salt file + */ + +char * IoTQuery::getSaltFileName() { + int directorylen=strlen(directory); + + /* Size is 4 characters for SALT string + 1 character for null + termination + directory size*/ + + char * filename=new char[6+directorylen]; + snprintf(filename, 6+directorylen, "%s/SALT", directory); return filename; } @@ -309,12 +371,16 @@ void IoTQuery::processQuery() { /* Decode query. */ decodeQuery(); - + /* Handle request. */ if (reqGetSlot) getSlot(); else if (reqPutSlot) putSlot(); + else if (reqSetSalt) + setSalt(); + else if (reqGetSalt) + getSalt(); else { cerr << "No recognized request" << endl; return; diff --git a/src/server/iotquery.h b/src/server/iotquery.h index 3394b57..ae39366 100644 --- a/src/server/iotquery.h +++ b/src/server/iotquery.h @@ -26,8 +26,11 @@ private: void decodeQuery(); void getSlot(); void putSlot(); + void setSalt(); + void getSalt(); void removeOldestSlot(); char * getSlotFileName(long long); + char * getSaltFileName(); FCGX_Request * request; char *data; @@ -57,5 +60,9 @@ private: bool reqGetSlot; /* Is the request to put a slot? */ bool reqPutSlot; + /* Is the request to set the salt? */ + bool reqSetSalt; + /* Is the request to get the salt? */ + bool reqGetSalt; }; #endif -- 2.34.1