public void run() throws IOException, ClassNotFoundException {
        readConfig();

        String asHostName = clientProperties.getProperty("as.hostname");
        int asPortNumber = Integer.parseInt(clientProperties.getProperty("as.port"));
        String clientName = clientProperties.getProperty("client.name");

        System.out.println("Connecting to AS with HostName: " + asHostName
                + ", PortNumber: " + asPortNumber);
        Socket asSocket = new Socket(asHostName, asPortNumber);

        KeyPair authClientKeyPair = getAuthClientKey();

        ClientRequest clientRequest = new ClientRequest();
        clientRequest.clientName = clientName;
        if (readDepartmentList(this.deptName)) {
            clientRequest.departServer = this.deptName;
        } else {
            asSocket.close();
            System.out.println("Department name - " + deptName + " is invalid.");
            return;
        }

        byte[] nonce = RandomUtils.getNonce();
        clientRequest.nonce = nonce;

        EncryptedPayload encryptedPayload = clientRequest
                .encrypt(authClientKeyPair);

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(asSocket.getOutputStream());
        objectOutputStream.writeObject(clientName);
        objectOutputStream.writeObject(encryptedPayload);
        objectOutputStream.flush();

        ObjectInputStream objectInputStream = new ObjectInputStream(asSocket.getInputStream());
        EncryptedPayload encryptedPayloadReceived = (EncryptedPayload) objectInputStream.readObject();

        AuthServerResponse authServerResponse = new AuthServerResponse();
        authServerResponse.decrypt(authClientKeyPair, encryptedPayloadReceived);

        System.out.println("Auth Server response decrypted");

        if (!MessageDigest.isEqual(authServerResponse.nonce, nonce) || !clientName.equals(authServerResponse.clientName)) {
            asSocket.close();
            throw new RuntimeException("Client name or nonce mismatch. Expected client name-" + clientName);
        }

        asSocket.close();
        sessionKeyClientMaster = KeyManager.generateKeyPair(authServerResponse.sessionKeyClientMaster);
        sessionKeyClientDepartment = KeyManager.generateKeyPair(authServerResponse.sessionKeyClientDepartment);

        EncryptedPayload masterTicket = new EncryptedPayload();
        masterTicket.decode(authServerResponse.masterServerToken);

        String masterHostName = clientProperties.getProperty("master.hostname");
        int masterPortNumber = Integer.parseInt(clientProperties.getProperty("master.port"));

        System.out.println("Connecting to Master File Server with HostName: "
                + masterHostName + ", PortNumber: " + masterPortNumber);
        Socket masterSocket = new Socket(masterHostName, masterPortNumber);

        ObjectOutputStream outputStream = new ObjectOutputStream(masterSocket.getOutputStream());
        outputStream.writeObject(masterTicket);

        System.out.println("Ticket sent to Master File Server...");
        System.out.println("Generating the File transfer Request...");

        ClientDeptRequest deptRequest = new ClientDeptRequest();
        deptRequest.clientName = clientName;
        deptRequest.nonce = RandomUtils.getNonce();
        deptRequest.reqFileName = this.fileName;

        EncryptedPayload encryptedDeptRequest = deptRequest.encrypt(sessionKeyClientDepartment);

        ClientMasterRequest masterRequest = new ClientMasterRequest();
        masterRequest.clientName = clientName;
        masterRequest.nonce = RandomUtils.getNonce();
        masterRequest.clientDeptToken = encryptedDeptRequest.encode();

        EncryptedPayload encryptedMasterRequest = masterRequest.encrypt(sessionKeyClientMaster);

        outputStream.writeObject(encryptedMasterRequest);

        objectInputStream = new ObjectInputStream(masterSocket.getInputStream());
        System.out.println("File Transfer Request sent... ");

        encryptedPayloadReceived = (EncryptedPayload) objectInputStream.readObject();

        System.out.println("Recived response for the File Transfer Request");
        MasterClientResponse mClientResponse = new MasterClientResponse();
        mClientResponse.decrypt(sessionKeyClientMaster, encryptedPayloadReceived);

        if (!MessageDigest.isEqual(mClientResponse.nonce, masterRequest.nonce) ||
                !mClientResponse.clientName.equals(clientName)) {
            masterSocket.close();
            throw new RuntimeException("Client name or nonce mismatch in response. " +
                    "Expected client name-" + clientName + ". Received client name -" +
                    mClientResponse.clientName);
        }

        EncryptedPayload departmentResponse = new EncryptedPayload();
        departmentResponse.decode(mClientResponse.deptClientToken);

        DeptClientResponse dClientResponse = new DeptClientResponse();
        dClientResponse.decrypt(sessionKeyClientDepartment, departmentResponse);

        if (dClientResponse.respCode == 0 && MessageDigest.isEqual(dClientResponse.nonce, deptRequest.nonce)) {

            String basePath = clientProperties.getProperty("client.fileSaveLocation");

            if (!FileUtils.isFileInDirectory(basePath, this.fileName)) {
                throw new RuntimeException("Seems like provided filename is tricky. Exiting for safety");
            }

            String fileName = FileUtils.getNonExistingFilename(basePath + "/" + this.fileName);
            File newFile = new File(fileName);
            FileUtils.writeFileBinary(fileName, dClientResponse.fileContent);

            System.out.println("File transfer complete");
            System.out.println("File saved at: " + newFile.getAbsolutePath());
        }
        System.out.println("Client Exiting");
        masterSocket.close();
    }