diff --git a/.github/workflows/build-gradle-project.yml b/.github/workflows/build-gradle-project.yml index 793d656..689a66f 100644 --- a/.github/workflows/build-gradle-project.yml +++ b/.github/workflows/build-gradle-project.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest env: ALIAS: andrew - KEYSTORE: andrew_keystore + KEYSTORE: keystore PASSWORD: ${{ secrets.PASSWORD }} steps: diff --git a/.github/workflows/build-push-action.yml b/.github/workflows/build-push-action.yml index 5e10949..98d305f 100644 --- a/.github/workflows/build-push-action.yml +++ b/.github/workflows/build-push-action.yml @@ -18,6 +18,11 @@ on: jobs: build: runs-on: ubuntu-latest + env: + ALIAS: andrew + KEYSTORE: andrew_keystore + PASSWORD: ${{ secrets.PASSWORD }} + steps: - name: Checkout uses: actions/checkout@v3 @@ -27,7 +32,10 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - + + - name: Create Key Store + run: sh create_keystore.sh + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/.gitignore b/.gitignore index 37efd50..4f75a3a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ bin # No attaching Kubernetes secrets k8/level_sites/ppdt-secrets.yaml +k8/client/ppdt-secrets.yaml +k8/server/ppdt-secrets.yaml +k8/server-job/ppdt-secrets.yaml # Outputs from PPDT creation output diff --git a/README.md b/README.md index 216812f..83cf518 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,8 @@ bash setup.sh 1. Check the `config.properties` file is set to your needs. Currently: 1. It assumes level-site 0 would use port 9000, level-site 1 would use port 9001, etc. - 1. If you modify this, provide a comma separated string of all the ports for each level-site. - 2. Currently, it assumes ports 9000 - 9009 will be used. + 1. If you modify this, provide a comma-separated string of all the ports for each level-site. + 2. Currently, it assumes ports 9000–9009 will be used. 2. key_size corresponds to the key size of both DGK and Paillier keys. 3. precision controls how accurate to measure thresholds that are decimals. If a value was 100.1, then a precision of 1 would set this value to 1001. @@ -66,7 +66,7 @@ This would assume one execution rather than multiple executions. In the `server_site_training_job.yaml` file, you need to change the first argument to point to the right ARFF file. #### Creating a Kubernetes Secret -You should set up a Kubernetes secret file, called `ppdt-secrets.yaml` in the `k8/level-sites` folder. +You should set up a Kubernetes secret file, called `ppdt-secrets.yaml` in the `k8/level-sites`, `k8/client`, and `k8/server` folder. In the yaml file, you will need to replace with a random string encoded in Base64. This secret is used in the AES encryption between level sites. ```yaml @@ -76,7 +76,7 @@ metadata: name: ppdt-secrets type: Opaque data: - aes-key: > + keystore-pass: > ``` or you can use the command: @@ -144,7 +144,7 @@ To get the results, access the logs as described in the previous steps for both #### Re-running with different experiments - *Case 1: Re-run with different testing set* -As the job created the pod, you would connect to the pod and run the modified gradle command with the other VALUES file. +As the job created the pod, you would connect to the pod and run the modified Gradle command with the other VALUES file. ```bash kubectl exec -i -t $(kubectl get pod -l "pod=ppdt-client-deploy" -o name) -- bash -c "gradle run -PchooseRole=weka.finito.client --args " ``` diff --git a/k8/client/client_deployment.yaml b/k8/client/client_deployment.yaml index 2b23f37..9b3ca2f 100644 --- a/k8/client/client_deployment.yaml +++ b/k8/client/client_deployment.yaml @@ -41,3 +41,12 @@ spec: - name: GRADLE_USER_HOME value: "gradle_user_home" + + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD + valueFrom: + secretKeyRef: + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_01_deployment.yaml b/k8/level_sites/level_site_01_deployment.yaml index 4468e73..d72347c 100644 --- a/k8/level_sites/level_site_01_deployment.yaml +++ b/k8/level_sites/level_site_01_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key \ No newline at end of file + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_02_deployment.yaml b/k8/level_sites/level_site_02_deployment.yaml index e371512..72dd384 100644 --- a/k8/level_sites/level_site_02_deployment.yaml +++ b/k8/level_sites/level_site_02_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_03_deployment.yaml b/k8/level_sites/level_site_03_deployment.yaml index 8f6a243..c324c18 100644 --- a/k8/level_sites/level_site_03_deployment.yaml +++ b/k8/level_sites/level_site_03_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_04_deployment.yaml b/k8/level_sites/level_site_04_deployment.yaml index 4befe39..f33090b 100644 --- a/k8/level_sites/level_site_04_deployment.yaml +++ b/k8/level_sites/level_site_04_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_05_deployment.yaml b/k8/level_sites/level_site_05_deployment.yaml index 26d9051..48d9969 100644 --- a/k8/level_sites/level_site_05_deployment.yaml +++ b/k8/level_sites/level_site_05_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key + name: ppdt-secrets + key: keystore-pass \ No newline at end of file diff --git a/k8/level_sites/level_site_06_deployment.yaml b/k8/level_sites/level_site_06_deployment.yaml index cce66b0..50571dc 100644 --- a/k8/level_sites/level_site_06_deployment.yaml +++ b/k8/level_sites/level_site_06_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_07_deployment.yaml b/k8/level_sites/level_site_07_deployment.yaml index 44f16ec..90d9f84 100644 --- a/k8/level_sites/level_site_07_deployment.yaml +++ b/k8/level_sites/level_site_07_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key \ No newline at end of file + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_08_deployment.yaml b/k8/level_sites/level_site_08_deployment.yaml index 1aa4323..2c6fd9b 100644 --- a/k8/level_sites/level_site_08_deployment.yaml +++ b/k8/level_sites/level_site_08_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key \ No newline at end of file + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_09_deployment.yaml b/k8/level_sites/level_site_09_deployment.yaml index 6cbac3b..446e7b7 100644 --- a/k8/level_sites/level_site_09_deployment.yaml +++ b/k8/level_sites/level_site_09_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key \ No newline at end of file + name: ppdt-secrets + key: keystore-pass diff --git a/k8/level_sites/level_site_10_deployment.yaml b/k8/level_sites/level_site_10_deployment.yaml index 4b69272..c1a333e 100644 --- a/k8/level_sites/level_site_10_deployment.yaml +++ b/k8/level_sites/level_site_10_deployment.yaml @@ -27,8 +27,11 @@ spec: - name: PORT_NUM value: "9000" - - name: AES_PASS + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD valueFrom: secretKeyRef: - name: ppdt-secrets - key: aes-key \ No newline at end of file + name: ppdt-secrets + key: keystore-pass diff --git a/k8/server-job/server_training_job.yaml b/k8/server-job/server_training_job.yaml index 9b2f093..def5221 100644 --- a/k8/server-job/server_training_job.yaml +++ b/k8/server-job/server_training_job.yaml @@ -29,4 +29,13 @@ spec: - name: GRADLE_USER_HOME value: "gradle_user_home" + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD + valueFrom: + secretKeyRef: + name: ppdt-secrets + key: keystore-pass + backoffLimit: 4 \ No newline at end of file diff --git a/k8/server-deploy/server_deployment.yaml b/k8/server/server_deployment.yaml similarity index 83% rename from k8/server-deploy/server_deployment.yaml rename to k8/server/server_deployment.yaml index 15bb73a..40b308f 100644 --- a/k8/server-deploy/server_deployment.yaml +++ b/k8/server/server_deployment.yaml @@ -38,3 +38,12 @@ spec: - name: GRADLE_USER_HOME value: "gradle_user_home" + + - name: KEYSTORE + value: "keystore" + + - name: PASSWORD + valueFrom: + secretKeyRef: + name: ppdt-secrets + key: keystore-pass diff --git a/k8/server-deploy/server_service.yaml b/k8/server/server_service.yaml similarity index 100% rename from k8/server-deploy/server_service.yaml rename to k8/server/server_service.yaml diff --git a/src/main/java/weka/finito/AES.java b/src/main/java/weka/finito/AES.java deleted file mode 100644 index 37c5856..0000000 --- a/src/main/java/weka/finito/AES.java +++ /dev/null @@ -1,89 +0,0 @@ -package weka.finito; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; - -import java.nio.charset.StandardCharsets; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.KeySpec; -import java.util.Base64; - -public final class AES { - private SecretKey key; - private int iterations = 65536; - private int key_length = 256; - private final byte [] salt = "123456789".getBytes(); - private final SecureRandom random = new SecureRandom(); - - private byte [] iv_bytes = new byte[16]; - private IvParameterSpec ivspec = null; - private String iv_string = null; - private final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - - public AES(String password) throws NoSuchPaddingException, NoSuchAlgorithmException { - try { - getKeyFromPassword(password); - } - catch (NoSuchAlgorithmException | InvalidKeySpecException e) { - e.printStackTrace(); - } - } - - public AES(String password, int iterations, int key_length) throws NoSuchPaddingException, NoSuchAlgorithmException { - this(password); - this.iterations = iterations; - this.key_length = key_length; - } - - public String getIV() { - return this.iv_string; - } - - public void getKeyFromPassword(String password) - throws NoSuchAlgorithmException, InvalidKeySpecException { - SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); - KeySpec spec = new PBEKeySpec(password.toCharArray(), this.salt, this.iterations, this.key_length); - this.key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); - } - - public String encrypt(String strToEncrypt) - throws NoSuchAlgorithmException, NoSuchPaddingException, - IllegalBlockSizeException, BadPaddingException, InvalidKeyException, - InvalidAlgorithmParameterException { - - // Generate new IV - random.nextBytes(iv_bytes); - ivspec = new IvParameterSpec(iv_bytes); - iv_string = Base64.getEncoder().encodeToString(iv_bytes); - - // Run Encryption - cipher.init(Cipher.ENCRYPT_MODE, this.key, ivspec); - byte [] output = cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)); - return Base64.getEncoder().encodeToString(output); - } - - public String decrypt(String strToDecrypt, String iv) - throws NoSuchAlgorithmException, NoSuchPaddingException, - IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { - // Get IV - iv_string = iv; - iv_bytes = Base64.getDecoder().decode(iv); - ivspec = new IvParameterSpec(iv_bytes); - - // Decrypt the value - cipher.init(Cipher.DECRYPT_MODE, this.key, ivspec); - byte [] output = cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)); - return new String(output); - } -} \ No newline at end of file diff --git a/src/main/java/weka/finito/client.java b/src/main/java/weka/finito/client.java index 490e779..8a84a08 100644 --- a/src/main/java/weka/finito/client.java +++ b/src/main/java/weka/finito/client.java @@ -44,8 +44,7 @@ public final class client implements Runnable { private KeyPair dgk; private KeyPair paillier; private Hashtable feature = null; - private String next_index = null; - private String iv = null; + private boolean classification_complete = false; private String [] classes; @@ -56,6 +55,7 @@ public final class client implements Runnable { private final HashMap hashed_classification = new HashMap<>(); private final String server_ip; private final int server_port; + private Integer next_index = 0; //For k8s deployment. public static void main(String[] args) { @@ -342,14 +342,7 @@ private void communicate_with_level_site(Socket level_site) // Send bool: // 1- true, there is an encrypted index coming // 2- false, there is NO encrypted index coming - if (next_index == null) { - to_level_site.writeBoolean(false); - } - else { - to_level_site.writeBoolean(true); - to_level_site.writeObject(next_index); - to_level_site.writeObject(iv); - } + to_level_site.writeInt(next_index); to_level_site.flush(); // Work with the comparison @@ -377,21 +370,15 @@ else if (comparison_type == 1) { // true - get leaf value // false - get encrypted AES index for next round classification_complete = from_level_site.readBoolean(); - o = from_level_site.readObject(); if (classification_complete) { + o = from_level_site.readObject(); if (o instanceof String) { classification = (String) o; classification = hashed_classification.get(classification); } } else { - if (o instanceof String) { - next_index = (String) o; - } - o = from_level_site.readObject(); - if (o instanceof String) { - iv = (String) o; - } + next_index = from_level_site.readInt(); } } diff --git a/src/main/java/weka/finito/level_site_server.java b/src/main/java/weka/finito/level_site_server.java index dab61ff..0bac079 100644 --- a/src/main/java/weka/finito/level_site_server.java +++ b/src/main/java/weka/finito/level_site_server.java @@ -1,15 +1,12 @@ package weka.finito; import weka.finito.structs.level_order_site; - -import javax.crypto.NoSuchPaddingException; import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import java.io.IOException; import java.lang.System; -import java.security.NoSuchAlgorithmException; import static weka.finito.utils.shared.cipher_suites; import static weka.finito.utils.shared.protocols; @@ -21,15 +18,11 @@ public class level_site_server implements Runnable { protected boolean isStopped = false; protected Thread runningThread= null; protected level_order_site level_site_parameters = null; - protected int precision; - protected AES crypto; protected SSLServerSocketFactory factory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); - public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException { + public static void main(String[] args) { int our_port = 0; - int our_precision = 0; - String AES_Pass = System.getenv("AES_PASS"); try { our_port = Integer.parseInt(System.getenv("PORT_NUM")); @@ -37,11 +30,7 @@ public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgo System.out.println("Port is not defined."); System.exit(1); } - if(AES_Pass == null || AES_Pass.isEmpty()) { - System.out.println("AES_PASS is empty."); - System.exit(1); - } - level_site_server server = new level_site_server(our_port, our_precision, new AES(AES_Pass)); + level_site_server server = new level_site_server(our_port); new Thread(server).start(); System.out.println("LEVEL SITE SERVER STARTED!"); while (true) { @@ -54,10 +43,8 @@ public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgo server.stop(); } - public level_site_server (int port, int precision, AES crypto) { + public level_site_server (int port) { this.serverPort = port; - this.precision = precision; - this.crypto = crypto; } public void run() { @@ -81,7 +68,7 @@ public void run() { throw new RuntimeException("Error accepting client connection", e); } level_site_thread current_level_site_class = new level_site_thread(clientSocket, - this.level_site_parameters, this.crypto); + this.level_site_parameters); level_order_site new_data = current_level_site_class.getLevelSiteParameters(); if (this.level_site_parameters == null) { diff --git a/src/main/java/weka/finito/level_site_thread.java b/src/main/java/weka/finito/level_site_thread.java index 3d297c0..68426ca 100644 --- a/src/main/java/weka/finito/level_site_thread.java +++ b/src/main/java/weka/finito/level_site_thread.java @@ -25,11 +25,8 @@ public class level_site_thread implements Runnable { private level_order_site level_site_data = null; private final Hashtable encrypted_features = new Hashtable<>(); - private final AES crypto; - - public level_site_thread(Socket client_socket, level_order_site level_site_data, AES crypto) { + public level_site_thread(Socket client_socket, level_order_site level_site_data) { this.client_socket = client_socket; - this.crypto = crypto; Object x; try { @@ -74,10 +71,7 @@ private void closeClientConnection() throws IOException { // This will run the communication with client and next level site public final void run() { - Object o; - String previous_index = null; - String iv = null; - boolean get_previous_index; + long start_time = System.nanoTime(); try { @@ -90,32 +84,12 @@ public final void run() { niu.setDGKPublicKey(this.level_site_data.dgk_public_key); niu.setPaillierPublicKey(this.level_site_data.paillier_public_key); + level_site_data.set_current_index(fromClient.readInt()); - get_previous_index = fromClient.readBoolean(); - if (get_previous_index) { - o = fromClient.readObject(); - if (o instanceof String) { - previous_index = (String) o; - } - o = fromClient.readObject(); - if (o instanceof String) { - iv = (String) o; - } - previous_index = crypto.decrypt(previous_index, iv); - } - - // Level Data is the Node Data... - // it is set to 0 by default... - if (previous_index != null) { - this.level_site_data.set_current_index(Integer.parseInt(previous_index)); - } - - // Null, keep going down the tree, + // Null, keep going down the tree, // Not null, you got the correct leaf node of your DT! NodeInfo reply = traverse_level(level_site_data, encrypted_features, toClient, niu); - String encrypted_next_index; - // Place -1 to break Protocol4 loop toClient.writeInt(-1); toClient.flush(); @@ -126,13 +100,8 @@ public final void run() { toClient.writeObject(reply.getVariableName()); } else { - toClient.writeBoolean(false); - // encrypt with AES, send to the client which will send to next level-site - encrypted_next_index = crypto.encrypt(String.valueOf(this.level_site_data.get_next_index())); - iv = crypto.getIV(); - toClient.writeObject(encrypted_next_index); - toClient.writeObject(iv); + toClient.writeInt(level_site_data.get_next_index()); } long stop_time = System.nanoTime(); double run_time = (double) (stop_time - start_time); diff --git a/src/test/java/PrivacyTest.java b/src/test/java/PrivacyTest.java index e068570..28d3793 100644 --- a/src/test/java/PrivacyTest.java +++ b/src/test/java/PrivacyTest.java @@ -1,16 +1,13 @@ import org.junit.Before; import org.junit.Test; -import weka.finito.AES; import weka.finito.client; import weka.finito.level_site_server; import weka.finito.server; -import javax.crypto.NoSuchPaddingException; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.security.NoSuchAlgorithmException; import java.util.Properties; import static org.junit.Assert.assertEquals; @@ -127,7 +124,7 @@ public void test_all_level_sites() throws Exception { public static String test_level_site(String training_data, String features_file, int levels, int key_size, int precision, String [] level_site_ips, String [] level_site_ports_string, String server_ip, int server_port) - throws InterruptedException, NoSuchPaddingException, NoSuchAlgorithmException { + throws InterruptedException { int [] level_site_ports = new int[levels]; @@ -136,8 +133,7 @@ public static String test_level_site(String training_data, String features_file, for (int i = 0; i < level_sites.length; i++) { String port_string = level_site_ports_string[i].replaceAll("[^0-9]", ""); level_site_ports[i] = Integer.parseInt(port_string); - level_sites[i] = new level_site_server(level_site_ports[i], precision, - new AES("AppSecSpring2023")); + level_sites[i] = new level_site_server(level_site_ports[i]); new Thread(level_sites[i]).start(); }