From: Ali Younis Date: Tue, 3 Oct 2017 04:36:11 +0000 (-0700) Subject: Changed AES to CTR mode X-Git-Url: http://plrg.eecs.uci.edu/git/?p=iotcloud.git;a=commitdiff_plain;h=61832540fe0818008a5535f347d1fa78645304ef Changed AES to CTR mode --- diff --git a/version2/src/java/iotcloud/CloudComm.java b/version2/src/java/iotcloud/CloudComm.java index 064fae0..d0a514d 100644 --- a/version2/src/java/iotcloud/CloudComm.java +++ b/version2/src/java/iotcloud/CloudComm.java @@ -6,6 +6,7 @@ import java.util.Arrays; import javax.crypto.*; import javax.crypto.spec.*; import java.security.SecureRandom; +import java.nio.ByteBuffer; /** * This class provides a communication API to the webserver. It also @@ -18,13 +19,13 @@ import java.security.SecureRandom; class CloudComm { private static final int SALT_SIZE = 8; private static final int TIMEOUT_MILLIS = 2000; // 100 + public static final int IV_SIZE = 16; /** Sets the size for the HMAC. */ static final int HMAC_SIZE = 32; private String baseurl; - private Cipher encryptCipher; - private Cipher decryptCipher; + private SecretKeySpec key; private Mac mac; private String password; private SecureRandom random; @@ -104,14 +105,10 @@ class CloudComm { } try { - SecretKeySpec key = initKey(); + key = initKey(); password = null; // drop password mac = Mac.getInstance("HmacSHA256"); mac.init(key); - encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - encryptCipher.init(Cipher.ENCRYPT_MODE, key); - decryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); - decryptCipher.init(Cipher.DECRYPT_MODE, key); } catch (Exception e) { e.printStackTrace(); throw new Error("Failed To Initialize Ciphers"); @@ -140,14 +137,13 @@ class CloudComm { byte[] saltTmp = new byte[SALT_SIZE]; random.nextBytes(saltTmp); - for(int i = 0; i < SALT_SIZE;i++) - { - System.out.println((int)saltTmp[i]&255); + for (int i = 0; i < SALT_SIZE; i++) { + System.out.println((int)saltTmp[i] & 255); } URL url = new URL(baseurl + "?req=setsalt"); - + timer.startTime(); URLConnection con = url.openConnection(); HttpURLConnection http = (HttpURLConnection) con; @@ -157,13 +153,13 @@ class CloudComm { http.setDoOutput(true); http.setConnectTimeout(TIMEOUT_MILLIS); - + http.connect(); OutputStream os = http.getOutputStream(); os.write(saltTmp); os.flush(); - + int responsecode = http.getResponseCode(); if (responsecode != HttpURLConnection.HTTP_OK) { // TODO: Remove this print @@ -201,7 +197,7 @@ class CloudComm { http.setConnectTimeout(TIMEOUT_MILLIS); http.setReadTimeout(TIMEOUT_MILLIS); - + http.connect(); timer.endTime(); } catch (SocketTimeoutException e) { @@ -248,6 +244,56 @@ class CloudComm { } } + private byte[] createIV(long machineId, long localSequenceNumber) { + ByteBuffer buffer = ByteBuffer.allocate(IV_SIZE); + buffer.putLong(machineId); + buffer.putLong(localSequenceNumber); + return buffer.array(); + + } + + private byte[] encryptSlotAndPrependIV(byte[] rawData, byte[] ivBytes) { + try { + IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); + Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); + + byte[] encryptedBytes = cipher.doFinal(rawData); + + byte[] bytes = new byte[encryptedBytes.length + IV_SIZE]; + System.arraycopy(ivBytes, 0, bytes, 0, ivBytes.length); + System.arraycopy(encryptedBytes, 0, bytes, IV_SIZE, encryptedBytes.length); + + return bytes; + + } catch (Exception e) { + e.printStackTrace(); + throw new Error("Failed To Encrypt"); + } + } + + + private byte[] stripIVAndDecryptSlot(byte[] rawData) { + try { + byte[] ivBytes = new byte[IV_SIZE]; + byte[] encryptedBytes = new byte[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/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, key, ivSpec); + + return cipher.doFinal(encryptedBytes); + + } catch (Exception e) { + e.printStackTrace(); + 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 @@ -267,12 +313,18 @@ class CloudComm { } long sequencenumber = slot.getSequenceNumber(); - byte[] bytes = slot.encode(mac); - bytes = encryptCipher.doFinal(bytes); + byte[] slotBytes = slot.encode(mac); + // slotBytes = encryptCipher.doFinal(slotBytes); + // byte[] iVBytes = slot.getSlotCryptIV(); + // byte[] bytes = new byte[slotBytes.length + IV_SIZE]; + // System.arraycopy(iVBytes, 0, bytes, 0, iVBytes.length); + // System.arraycopy(slotBytes, 0, bytes, IV_SIZE, slotBytes.length); + byte[] bytes = encryptSlotAndPrependIV(slotBytes, slot.getSlotCryptIV()); + url = buildRequest(true, sequencenumber, max); timer.startTime(); @@ -317,19 +369,15 @@ class CloudComm { dis.readFully(resptype); timer.endTime(); - if (Arrays.equals(resptype, "getslot".getBytes())) - { + if (Arrays.equals(resptype, "getslot".getBytes())) { return processSlots(dis); - } - else if (Arrays.equals(resptype, "putslot".getBytes())) - { + } else if (Arrays.equals(resptype, "putslot".getBytes())) { return null; - } - else + } else throw new Error("Bad response to putslot"); } catch (SocketTimeoutException e) { - timer.endTime(); + timer.endTime(); throw new ServerException("putSlot failed", ServerException.TypeInputTimeout); } catch (Exception e) { // e.printStackTrace(); @@ -362,7 +410,7 @@ class CloudComm { http.setConnectTimeout(TIMEOUT_MILLIS); http.setReadTimeout(TIMEOUT_MILLIS); - + http.connect(); timer.endTime(); @@ -381,12 +429,12 @@ class CloudComm { } try { - + timer.startTime(); - InputStream is = http.getInputStream(); + InputStream is = http.getInputStream(); DataInputStream dis = new DataInputStream(is); byte[] resptype = new byte[7]; - + dis.readFully(resptype); timer.endTime(); @@ -418,10 +466,17 @@ class CloudComm { for (int i = 0; i < numberofslots; i++) { - byte[] data = new byte[sizesofslots[i]]; - dis.readFully(data); + byte[] rawData = new byte[sizesofslots[i]]; + dis.readFully(rawData); + + + // byte[] data = new byte[rawData.length - IV_SIZE]; + // System.arraycopy(rawData, IV_SIZE, data, 0, data.length); + - data = decryptCipher.doFinal(data); + byte[] data = stripIVAndDecryptSlot(rawData); + + // data = decryptCipher.doFinal(data); slots[i] = Slot.decode(table, data, mac); } @@ -429,13 +484,12 @@ class CloudComm { return slots; } - public byte[] sendLocalData(byte[] sendData, String host, int port) { + public byte[] sendLocalData(byte[] sendData, long localSequenceNumber, String host, int port) { if (salt == null) { return null; } try { - System.out.println("Passing Locally"); mac.update(sendData); @@ -446,7 +500,9 @@ class CloudComm { // Encrypt the data for sending // byte[] encryptedData = encryptCipher.doFinal(totalData); - byte[] encryptedData = encryptCipher.doFinal(totalData); + // byte[] encryptedData = encryptCipher.doFinal(totalData); + byte[] iv = createIV(table.getMachineId(), table.getLocalSequenceNumber()); + byte[] encryptedData = encryptSlotAndPrependIV(totalData, iv); // Open a TCP socket connection to a local device Socket socket = new Socket(host, port); @@ -467,7 +523,9 @@ class CloudComm { timer.endTime(); - returnData = decryptCipher.doFinal(returnData); + // returnData = decryptCipher.doFinal(returnData); + returnData = stripIVAndDecryptSlot(returnData); + // returnData = decryptCipher.doFinal(returnData); // We are done with this socket socket.close(); @@ -484,15 +542,9 @@ class CloudComm { System.arraycopy(returnData, 0, returnData2, 0, returnData2.length); return returnData2; - } catch (SocketTimeoutException e) { - - } catch (BadPaddingException e) { - - } catch (IllegalBlockSizeException e) { - - } catch (UnknownHostException e) { - - } catch (IOException e) { + } catch (Exception e) { + e.printStackTrace(); + // throw new Error("Local comms failure..."); } @@ -530,7 +582,8 @@ class CloudComm { timer.endTime(); // Decrypt the data - readData = decryptCipher.doFinal(readData); + // readData = decryptCipher.doFinal(readData); + readData = stripIVAndDecryptSlot(readData); mac.update(readData, 0, readData.length - HMAC_SIZE); byte[] genmac = mac.doFinal(); @@ -547,6 +600,7 @@ class CloudComm { // byte[] sendData = table.acceptDataFromLocal(readData); byte[] sendData = table.acceptDataFromLocal(returnData); + mac.update(sendData); byte[] realmac = mac.doFinal(); byte[] totalData = new byte[sendData.length + realmac.length]; @@ -554,7 +608,9 @@ class CloudComm { System.arraycopy(realmac, 0, totalData, sendData.length, realmac.length); // Encrypt the data for sending - byte[] encryptedData = encryptCipher.doFinal(totalData); + // byte[] encryptedData = encryptCipher.doFinal(totalData); + byte[] iv = createIV(table.getMachineId(), table.getLocalSequenceNumber()); + byte[] encryptedData = encryptSlotAndPrependIV(totalData, iv); timer.startTime(); @@ -565,15 +621,7 @@ class CloudComm { // close the socket socket.close(); - } catch (SocketTimeoutException e) { - - } catch (BadPaddingException e) { - - } catch (IllegalBlockSizeException e) { - - } catch (UnknownHostException e) { - - } catch (IOException e) { + } catch (Exception e) { } } @@ -610,5 +658,4 @@ class CloudComm { super.finalize(); } } - } diff --git a/version2/src/java/iotcloud/Slot.java b/version2/src/java/iotcloud/Slot.java index ab04359..b881efe 100644 --- a/version2/src/java/iotcloud/Slot.java +++ b/version2/src/java/iotcloud/Slot.java @@ -36,7 +36,9 @@ class Slot implements Liveness { /** Reference to Table */ private Table table; - Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) { + private long localSequenceNumber; + + Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac, long _localSequenceNumber) { seqnum = _seqnum; machineid = _machineid; prevhmac = _prevhmac; @@ -46,14 +48,15 @@ class Slot implements Liveness { seqnumlive = true; freespace = SLOT_SIZE - getBaseSize(); table = _table; + localSequenceNumber = _localSequenceNumber; } - Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac) { - this(_table, _seqnum, _machineid, _prevhmac, null); + Slot(Table _table, long _seqnum, long _machineid, byte[] _prevhmac, long _localSequenceNumber) { + this(_table, _seqnum, _machineid, _prevhmac, null, _localSequenceNumber); } - Slot(Table _table, long _seqnum, long _machineid) { - this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null); + Slot(Table _table, long _seqnum, long _machineid, long _localSequenceNumber) { + this(_table, _seqnum, _machineid, new byte[HMAC_SIZE], null, _localSequenceNumber); } byte[] getHMAC() { @@ -112,7 +115,7 @@ class Slot implements Liveness { long seqnum = bb.getLong(); long machineid = bb.getLong(); int numentries = bb.getInt(); - Slot slot = new Slot(table, seqnum, machineid, prevhmac, hmac); + Slot slot = new Slot(table, seqnum, machineid, prevhmac, hmac, -1); for (int i = 0; i < numentries; i++) { slot.addShallowEntry(Entry.decode(slot, bb)); @@ -216,6 +219,14 @@ class Slot implements Liveness { return livecount > 0; } + public byte[] getSlotCryptIV() { + ByteBuffer buffer = ByteBuffer.allocate(CloudComm.IV_SIZE); + buffer.putLong(machineid); + buffer.putLong(localSequenceNumber); + return buffer.array(); + } + + public String toString() { return "<" + getSequenceNumber() + ">"; } diff --git a/version2/src/java/iotcloud/Table.java b/version2/src/java/iotcloud/Table.java index b6801c0..e446152 100644 --- a/version2/src/java/iotcloud/Table.java +++ b/version2/src/java/iotcloud/Table.java @@ -44,6 +44,8 @@ final public class Table { private long oldestLiveSlotSequenceNumver = 0; // Smallest sequence number of the slot with a live entry private long localMachineId = 0; // Machine ID of this client device private long sequenceNumber = 0; // Largest sequence number a client has received + private long localSequenceNumber = 0; + // private int smallestTableStatusSeen = -1; // Smallest Table Status that was seen in the latest slots sent from the server // private int largestTableStatusSeen = -1; // Largest Table Status that was seen in the latest slots sent from the server private long localTransactionSequenceNumber = 0; // Local sequence number counter for transactions @@ -242,7 +244,8 @@ final public class Table { cloud.initSecurity(); // Create the first insertion into the block chain which is the table status - Slot s = new Slot(this, 1, localMachineId); + Slot s = new Slot(this, 1, localMachineId, localSequenceNumber); + localSequenceNumber++; TableStatus status = new TableStatus(s, numberOfSlots); s.addEntry(status); Slot[] array = cloud.putSlot(s, numberOfSlots); @@ -522,6 +525,10 @@ final public class Table { bufferResizeThreshold = resizeLower - 1 + random.nextInt(numberOfSlots - resizeLower); } + public long getLocalSequenceNumber() { + return localSequenceNumber; + } + boolean lastInsertedNewKey = false; @@ -720,7 +727,6 @@ final public class Table { // While we have stuff that needs inserting into the block chain while ((pendingTransactionQueue.size() > 0) || (pendingSendArbitrationRounds.size() > 0) || (newKey != null)) { - fromRetry = false; if (hadPartialSendToServer) { @@ -735,7 +741,8 @@ final public class Table { } // Create the slot - Slot slot = new Slot(this, sequenceNumber + 1, localMachineId, buffer.getSlot(sequenceNumber).getHMAC()); + Slot slot = new Slot(this, sequenceNumber + 1, localMachineId, buffer.getSlot(sequenceNumber).getHMAC(), localSequenceNumber); + localSequenceNumber++; // Try to fill the slot with data ThreeTuple fillSlotsReturn = fillSlot(slot, false, newKey); @@ -782,7 +789,7 @@ final public class Table { // New Key was successfully inserted into the block chain so dont want to insert it again newKey = null; - } + } // Remove the aborts and commit parts that were sent from the pending to send queue for (Iterator iter = pendingSendArbitrationRounds.iterator(); iter.hasNext(); ) { @@ -929,7 +936,8 @@ final public class Table { bbEncode.putInt(0); // Send by local - byte[] returnData = cloud.sendLocalData(sendData, localCommunicationInformation.getFirst(), localCommunicationInformation.getSecond()); + byte[] returnData = cloud.sendLocalData(sendData, localSequenceNumber, localCommunicationInformation.getFirst(), localCommunicationInformation.getSecond()); + localSequenceNumber++; if (returnData == null) { // Could not contact server @@ -990,7 +998,8 @@ final public class Table { // Send by local - byte[] returnData = cloud.sendLocalData(sendData, localCommunicationInformation.getFirst(), localCommunicationInformation.getSecond()); + byte[] returnData = cloud.sendLocalData(sendData, localSequenceNumber, localCommunicationInformation.getFirst(), localCommunicationInformation.getSecond()); + localSequenceNumber++; if (returnData == null) { // Could not contact server @@ -1143,6 +1152,8 @@ final public class Table { entry.encode(bbEncode); } + + localSequenceNumber++; return returnData; } @@ -1250,7 +1261,7 @@ final public class Table { slot.addEntry(newKeyEntry); inserted = true; - } + } } // Clear the transactions, aborts and commits that were sent previously