From c48ec1604744ab330d18af1f55256c35dc5c34c6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Magdalena=20Grodzi=C5=84ska?= <mag.grodzinska@gmail.com>
Date: Sun, 12 Jan 2020 22:58:08 +0100
Subject: Improve query signer and its api

---
 .../mimuw/cloudatlas/client/ClientController.java  | 10 ++-
 .../mimuw/cloudatlas/querysigner/QuerySigner.java  | 12 +++-
 .../querysigner/QuerySignerApiImplementation.java  | 84 +++++++++++++++-------
 .../cloudatlas/querysignerapi/QuerySignerApi.java  | 10 ++-
 4 files changed, 78 insertions(+), 38 deletions(-)

(limited to 'src')

diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java b/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java
index 14f531e..56b478c 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java
@@ -35,7 +35,6 @@ import java.util.*;
 public class ClientController {
     private Api agentApi;
     private QuerySignerApi querySignerApi;
-    private Map<String, byte[]> querySignatures;
     private Map<ValueTime, AttributesMap> attributes;
     private String currentZoneName;
     private static final int MAX_ENTRIES = 10;
@@ -60,7 +59,6 @@ public class ClientController {
             }
         };
         this.currentZoneName = System.getProperty("zone_path");
-        this.querySignatures = new HashMap<>();
         fetchAttributeData(); // fetch attribute data as early as possible
     }
 
@@ -81,9 +79,8 @@ public class ClientController {
         boolean success = true;
 
         try {
-            byte[] querySignature = this.querySignerApi.signQuery(queryObject.getName(), queryObject.getValue());
-            querySignatures.put(queryObject.getName(), querySignature);
-            this.agentApi.installQuery(queryObject.getName(), queryObject.getValue(), querySignature);
+            ValueQuery query = this.querySignerApi.signInstallQuery(queryObject.getName(), queryObject.getValue());
+            this.agentApi.installQuery(queryObject.getName(), query);
         } catch (Exception e) {
             success = false;
             System.err.println("Client exception:");
@@ -108,7 +105,8 @@ public class ClientController {
         boolean success = true;
 
         try {
-            this.agentApi.uninstallQuery(queryObject.getName(), querySignatures.get(queryObject.getName()));
+            ValueQuery query = querySignerApi.signUninstallQuery(queryObject.getName());
+            this.agentApi.uninstallQuery(queryObject.getName(), query);
         } catch (Exception e) {
             success = false;
             System.err.println("Client exception:");
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySigner.java b/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySigner.java
index 69a25d7..90a86b7 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySigner.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySigner.java
@@ -1,7 +1,5 @@
 package pl.edu.mimuw.cloudatlas.querysigner;
 
-import pl.edu.mimuw.cloudatlas.agent.EventBus;
-import pl.edu.mimuw.cloudatlas.api.Api;
 import pl.edu.mimuw.cloudatlas.querysignerapi.QuerySignerApi;
 
 import java.rmi.registry.LocateRegistry;
@@ -9,10 +7,18 @@ import java.rmi.registry.Registry;
 import java.rmi.server.UnicastRemoteObject;
 
 public class QuerySigner {
+    public static class InvalidQueryException extends Exception {
+        InvalidQueryException() {
+            super("Query invalid");
+        }
+    }
 
     public static void runRegistry() {
         try {
-            QuerySignerApiImplementation api = new QuerySignerApiImplementation();
+            // TODO reading from files
+            String publicKey = System.getProperty("public_key");
+            String privateKey = System.getProperty("private_key");
+            QuerySignerApiImplementation api = new QuerySignerApiImplementation(publicKey.getBytes(), privateKey.getBytes());
             QuerySignerApi apiStub =
                     (QuerySignerApi) UnicastRemoteObject.exportObject(api, 0);
             Registry registry = LocateRegistry.getRegistry();
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySignerApiImplementation.java b/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySignerApiImplementation.java
index 38a86c6..d1c0e7c 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySignerApiImplementation.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/querysigner/QuerySignerApiImplementation.java
@@ -1,5 +1,6 @@
 package pl.edu.mimuw.cloudatlas.querysigner;
 
+import pl.edu.mimuw.cloudatlas.ByteSerializer;
 import pl.edu.mimuw.cloudatlas.model.ValueQuery;
 import pl.edu.mimuw.cloudatlas.querysignerapi.QuerySignerApi;
 
@@ -9,27 +10,27 @@ import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.NoSuchPaddingException;
 import java.rmi.RemoteException;
 import java.security.*;
+import java.security.interfaces.RSAPrivateCrtKey;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 public class QuerySignerApiImplementation implements QuerySignerApi {
+    private final static String ENCRYPTION_ALGORITHM = "RSA";
+    private final static String DIGEST_ALGORITHM = "SHA-256";
     private PublicKey publicKey;
     private PrivateKey privateKey;
-    private final static String ENCRYPTION_ALGORITHM = "RSA";
-    private final static int NUM_KEY_BITS = 1024;
     private Map<String, ValueQuery> queries;
     private Set<String> attribsSetByQueries;
+    private ByteSerializer byteSerializer;
 
-    QuerySignerApiImplementation() {
+    QuerySignerApiImplementation(byte[] serializedPublicKey, byte[] serializedPrivateKey) {
+        this.byteSerializer = new ByteSerializer();
+        this.publicKey = (PublicKey) byteSerializer.deserialize(serializedPublicKey, PublicKey.class);
+        this.privateKey = (PrivateKey) byteSerializer.deserialize(serializedPrivateKey, PrivateKey.class);
         this.queries = new HashMap<>();
         this.attribsSetByQueries = new HashSet<>();
-        try {
-            generateKeys();
-        } catch (NoSuchAlgorithmException e) {
-            e.printStackTrace();
-        }
     }
 
     private String byteArrayToString(byte[] arr, int offset, int len) {
@@ -44,19 +45,10 @@ public class QuerySignerApiImplementation implements QuerySignerApi {
         return sb.toString();
     }
 
-    private void generateKeys() throws NoSuchAlgorithmException {
-        KeyPairGenerator keyGenerator =
-                KeyPairGenerator.getInstance(ENCRYPTION_ALGORITHM);
-        keyGenerator.initialize(NUM_KEY_BITS);
-        KeyPair keyPair = keyGenerator.generateKeyPair();
-        this.privateKey = keyPair.getPrivate();
-        this.publicKey = keyPair.getPublic();
-    }
-
-    private byte[] encryptQuery(String query) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+    private byte[] encryptQuery(byte[] query) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
         Cipher signCipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
         signCipher.init(Cipher.ENCRYPT_MODE, privateKey);
-        byte[] encryptedBytes = signCipher.doFinal(query.getBytes());
+        byte[] encryptedBytes = signCipher.doFinal(query);
         System.out.println(
                 "Bytes encrypted with " + ENCRYPTION_ALGORITHM +
                         ": " + byteArrayToString(
@@ -64,7 +56,7 @@ public class QuerySignerApiImplementation implements QuerySignerApi {
         return encryptedBytes;
     }
 
-    private String decryptQuery(byte[] encryptedQuery) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
+    private byte[] decryptQuery(byte[] encryptedQuery) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
         Cipher verifyCipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
         verifyCipher.init(Cipher.DECRYPT_MODE, publicKey);
         byte[] decryptedBytes = verifyCipher.doFinal(encryptedQuery);
@@ -72,29 +64,67 @@ public class QuerySignerApiImplementation implements QuerySignerApi {
                 "Bytes decrypted with " + ENCRYPTION_ALGORITHM +
                         ": " + byteArrayToString(
                         decryptedBytes, 0, decryptedBytes.length));
-        return new String(decryptedBytes);
+        return decryptedBytes;
+    }
+
+    private byte[] cryptographicHash(byte[] serializedQuery) throws NoSuchAlgorithmException {
+        MessageDigest digestGenerator =
+                MessageDigest.getInstance(DIGEST_ALGORITHM);
+        byte[] digest = digestGenerator.digest(serializedQuery);
+        System.out.println(
+                DIGEST_ALGORITHM + " digest: " +
+                        byteArrayToString(
+                                digest, 0, digest.length));
+        return digest;
+    }
+
+    // TODO
+    private byte[] serializeQuery(String queryName, String queryCode) {
+        return byteSerializer.serialize(queryName + queryCode);
     }
 
     @Override
-    public byte[] signQuery(String queryName, String queryCode) throws RemoteException {
+    public ValueQuery signInstallQuery(String queryName, String queryCode) throws RemoteException {
+        QueryUtils.validateQueryName(queryName);
         try {
-            return encryptQuery(queryName + queryCode);
-        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
+            byte[] serializedQuery = serializeQuery(queryName, queryCode);
+            byte[] hashedQuery = cryptographicHash(serializedQuery);
+            byte[] querySignature = encryptQuery(hashedQuery);
+            return new ValueQuery(queryCode, querySignature);
+        } catch (Exception e) {
             e.printStackTrace();
             throw new RemoteException(e.getLocalizedMessage());
         }
     }
 
     @Override
-    public String checkQuery(byte[] encryptedQuery, String queryName, String queryCode) throws RemoteException {
+    public void validateInstallQuery(String queryName, ValueQuery query) throws RemoteException {
+        QueryUtils.validateQueryName(queryName);
         try {
-            return decryptQuery(encryptedQuery);
-        } catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
+            byte[] decryptedQuery = decryptQuery(query.getSignature());
+            byte[] serializedQuery = serializeQuery(queryName, query.getCode());
+            byte[] hashedSerializedQuery = cryptographicHash(serializedQuery);
+            if (hashedSerializedQuery != decryptedQuery) {
+                throw new QuerySigner.InvalidQueryException();
+            }
+        } catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | QuerySigner.InvalidQueryException e) {
             e.printStackTrace();
             throw new RemoteException(e.getLocalizedMessage());
         }
     }
 
+    // TODO
+    @Override
+    public ValueQuery signUninstallQuery(String queryName) throws RemoteException {
+        return null;
+    }
+
+    // TODO
+    @Override
+    public void validateUninstallQuery(String queryName, ValueQuery query) throws RemoteException {
+
+    }
+
     @Override
     public PublicKey getPublicKey() throws RemoteException {
         return publicKey;
diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/querysignerapi/QuerySignerApi.java b/src/main/java/pl/edu/mimuw/cloudatlas/querysignerapi/QuerySignerApi.java
index 3c77c0a..fa46da3 100644
--- a/src/main/java/pl/edu/mimuw/cloudatlas/querysignerapi/QuerySignerApi.java
+++ b/src/main/java/pl/edu/mimuw/cloudatlas/querysignerapi/QuerySignerApi.java
@@ -1,13 +1,19 @@
 package pl.edu.mimuw.cloudatlas.querysignerapi;
 
+import pl.edu.mimuw.cloudatlas.model.ValueQuery;
+
 import java.rmi.Remote;
 import java.rmi.RemoteException;
 import java.security.PublicKey;
 
 public interface QuerySignerApi extends Remote {
-    public byte[] signQuery(String queryName, String queryCode) throws RemoteException;
+    public ValueQuery signInstallQuery(String queryName, String queryCode) throws RemoteException;
+
+    public ValueQuery signUninstallQuery(String queryName) throws RemoteException;
+
+    public void validateInstallQuery(String queryName, ValueQuery query) throws RemoteException;
 
-    public String checkQuery(byte[] encryptedQuery, String queryName, String queryCode) throws RemoteException;
+    public void validateUninstallQuery(String queryName, ValueQuery query) throws RemoteException;
 
     public PublicKey getPublicKey() throws RemoteException;
 
-- 
cgit v1.2.3