com.mytalentfolio.h_daforum.CconnectToServer.java Source code

Java tutorial

Introduction

Here is the source code for com.mytalentfolio.h_daforum.CconnectToServer.java

Source

package com.mytalentfolio.h_daforum;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Vector;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.util.Base64;

import com.mytalentfolio.h_daforum.R;

/**
 * <p>Copyright (c) Hochschule Darmstadt. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.</p>
 *
 * <p>You can redistribute and/or modify the code
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.</p> 
 *
 * <p>Please contact Hochschule Darmstadt if you need additional information or have any
 * questions.</p>
 * 
 * <p><strong>The Class CconnectToServer.</strong></br>
 * This class is used to form a secure connection between server and client</p>
 * 
 * @author Deepak Patel
 * @version 1.1
 */
public class CconnectToServer {

    /**
     * Static variable for storing the Context. This context variable is
     * used for reading the certificate file.
     */
    static public Context mContext;

    /**
     * {@code connect} is for forming the secure connection between server and
     * android, sending and receiving of the data.
     * 
     * @param arg0
     *            data which is to be sent to server.
     * 
     * @return data in string format, received from the server.
     */
    public String connect(String... arg0) {

        int nrOfDataToSendToServer = arg0.length;
        nrOfDataToSendToServer = nrOfDataToSendToServer - 1;
        boolean valid = false;
        String dataFromServer = "unverified", serverPublicKeySigStr, serverDataSig;

        try {
            //Creating the server certificate
            Certificate serverCertificate = getServerCertificate();

            KeyStore keyStore = getKeyStore(serverCertificate);

            TrustManagerFactory tmf = getTrustManager(keyStore);

            SSLContext sslContext = getSSLContext(tmf);

            HostnameVerifier hostnameVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };

            HttpsURLConnection urlConnection = getURLConnection(sslContext, hostnameVerifier);

            // Converting the data into JSONObject
            JSONObject obj = new JSONObject();
            for (int i = 0; i <= nrOfDataToSendToServer; i++) {
                obj.put("param" + i, arg0[i]);
            }

            // Converting the JSONObject into string
            String dataToSend = obj.toString();

            KeyPairGenerator keyGen = getKeyPairGenerator();

            KeyPair keyPair = keyGen.generateKeyPair();
            //Public key for verifying the digital signature
            PublicKey clientPublicKeySig = keyPair.getPublic();
            //Private key for signing the data
            PrivateKey clientPrivateKeySig = keyPair.getPrivate();

            // Get signed data
            String sigData = getDataSig(clientPrivateKeySig, dataToSend);

            // Creating URL Format
            String urlData = URLEncoder.encode("clientPublicKeySig", "UTF-8") + "=" + URLEncoder
                    .encode(Base64.encodeToString(clientPublicKeySig.getEncoded(), Base64.DEFAULT), "UTF-8");
            urlData += "&" + URLEncoder.encode("clientData", "UTF-8") + "="
                    + URLEncoder.encode(dataToSend, "UTF-8");
            urlData += "&" + URLEncoder.encode("clientDataSig", "UTF-8") + "="
                    + URLEncoder.encode(sigData, "UTF-8");

            // Sending the data to the server
            OutputStreamWriter wr = new OutputStreamWriter(urlConnection.getOutputStream());
            wr.write(urlData);
            wr.flush();
            wr.close();

            // Receiving the data from server
            BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line = null;

            // Read Server Response
            while ((line = reader.readLine()) != null) {
                // Append server response in string
                sb.append(line + "\n");
                // sb.append(line);
            }
            String text = sb.toString();
            reader.close();

            // Extracting the data, public key and signature received from
            // server
            Vector<String> storeExtractedValues = new Vector<String>();

            storeExtractedValues = extractDataFromJson(text, "data");
            dataFromServer = storeExtractedValues.get(0);

            storeExtractedValues = extractDataFromJson(text, "serverPublicKeySig");
            serverPublicKeySigStr = storeExtractedValues.get(0);

            storeExtractedValues = extractDataFromJson(text, "serverDataSig");
            serverDataSig = storeExtractedValues.get(0);

            // Converting the Server Public key format to Java compatible from
            PublicKey serverPublicKeySig = getServerPublicKey(serverPublicKeySigStr);

            // Verify the received data
            valid = getDataValidity(serverPublicKeySig, dataFromServer, serverDataSig);

            // Disconnect the url connection
            urlConnection.disconnect();

            if (dataFromServer.equalsIgnoreCase("unverified")) {
                CExceptionHandling.ExceptionState = ExceptionSet.SENT_DATA_UNVERIFIED;
                return "-1";
            } else if (valid == false) {
                CExceptionHandling.ExceptionState = ExceptionSet.RECEIVED_DATA_UNVERIFIED;
                return "-1";
            } else {
                return dataFromServer;
            }

        } catch (Exception e) {
            CExceptionHandling.ExceptionMsg = e.getMessage();

            if (e.toString().equals("java.net.SocketException: Network unreachable")) {
                CExceptionHandling.ExceptionState = ExceptionSet.NO_DATA_CONNECTION;
            } else if (e.toString().equals(
                    "java.net.SocketTimeoutException: failed to connect to /10.0.2.2 (port 443) after 10000ms")) {
                CExceptionHandling.ExceptionState = ExceptionSet.CONNECTION_TIMEOUT;
            } else {
                CExceptionHandling.ExceptionState = ExceptionSet.OTHER_EXCEPTIONS;
            }
            return "-1";
        }

    }

    /**
     * Creates a new instance of {@code Certificate}
     * 
     * @return the new {@code Certificate} instance.
     * @throws CertificateException
     *             if the specified certificate type is not available at any
     *             installed provider.
     * @throws IOException
     *             if an error occurs while closing this stream
     */
    private Certificate getServerCertificate() throws CertificateException, IOException {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        // deepak
        InputStream caInput = mContext.getResources().openRawResource(R.raw.server);
        // ankit
        // InputStream caInput =
        // mContext.getResources().openRawResource(R.raw.localhost);

        Certificate ca;
        try {
            ca = cf.generateCertificate(caInput);
        } finally {
            caInput.close();
        }

        return ca;
    }

    /**
     * Creates a new instance of KeyStore from provided certificate.
     * 
     * @param ca
     *            the certificate to get KeyStore
     * @return the new {@code KeyStore} instance.
     * @throws KeyStoreException
     *             if an error occurred during the creation of the new KeyStore.
     * @throws NoSuchAlgorithmException
     *             if the required algorithm is not available.
     * @throws CertificateException
     *             if the specified certificate type is not available at any
     *             installed provider.
     * @throws IOException
     *             if an error occurs while closing this stream
     */
    private KeyStore getKeyStore(Certificate ca)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
        return keyStore;

    }

    /**
     * Creates a new instance of {@code TrustManagerFactory} from provided
     * {@code KeyStore}.
     * 
     * @param keyStore
     *            the KeyStore to get the TrustManagerFactory
     * @return the new {@code TrustManagerFactory} instance.
     * @throws KeyStoreException
     *             if an error occurred during the creation of the new KeyStore.
     * @throws NoSuchAlgorithmException
     *             if the required algorithm is not available.
     * 
     */
    private TrustManagerFactory getTrustManager(KeyStore keyStore)
            throws NoSuchAlgorithmException, KeyStoreException {
        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);
        return tmf;
    }

    /**
     * Creates a new instance of {@code SSLContext} from the given
     * {@code TrustManagerFactory} {@code tmf}.
     * 
     * @param tmf
     *            the TrustManagerFactory to create a SSLContext
     * @return the new {@code SSLContext} instance.
     * @throws NoSuchAlgorithmException
     *             if the required algorithm is not available.
     * @throws KeyManagementException
     *             if initializing this instance fails.
     */
    private SSLContext getSSLContext(TrustManagerFactory tmf)
            throws NoSuchAlgorithmException, KeyManagementException {

        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);
        return context;
    }

    /**
     * Creates a new instance of {@code HttpsURLConnection} from the given
     * {@code context} and {@code hostnameVerifier}.
     * 
     * @param context
     *            the TrustManagerFactory to get the SSLContext
     * @return the new {@code HttpsURLConnection} instance.
     * @throws IOException
     *             if an error occurs while opening the connection.
     */
    private HttpsURLConnection getURLConnection(SSLContext context, HostnameVerifier hostnameVerifier)
            throws IOException {

        URL url = new URL("https://10.0.2.2/mycode/digitalSig.php");

        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.setConnectTimeout(3000);
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        urlConnection.setHostnameVerifier(hostnameVerifier);

        return urlConnection;
    }

    /**
     * Creates a new instance of (@code KeyPairGenerator}.
     * 
     * @return the new {@code KeyPairGenerator} instance.
     * @throws NoSuchAlgorithmException
     *             if the specified algorithm is not available
     */
    private KeyPairGenerator getKeyPairGenerator() throws NoSuchAlgorithmException {
        // Generate Key Pair
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(1024);
        return keyGen;
    }

    /**
     * Returns the string formatted digital signature for the data.
     * 
     * @param key
     *            Private key for signing the data.
     * @param data
     *            Data for which the signature is to be generated.
     * @return signed data with the provide private key.
     * @throws NoSuchAlgorithmException
     *             if the specified algorithm is not available.
     * @throws InvalidKeyException
     *             if privateKey is not valid.
     * @throws SignatureException
     *             if this Signature instance is not initialized properly.
     */
    private String getDataSig(PrivateKey key, String data)
            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {

        // Generate Signature For the data
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(key);
        signature.update(data.getBytes());
        byte[] sigBytes = signature.sign();
        return Base64.encodeToString(sigBytes, Base64.DEFAULT);
    }

    /**
     * Creates a new instance of {@code PublicKey}. Convert the string formatted
     * public key into {@code PublicKey} type.
     * 
     * @param key
     *            the string formated public key.
     * @return the new {@code PublicKey} instance.
     * @throws NoSuchAlgorithmException
     *             if no provider provides the requested algorithm.
     * @throws InvalidKeyException
     *             if the specified keySpec is invalid.
     * 
     */
    // Converting the Server Public key format to Java compatible from
    private PublicKey getServerPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {

        // Converting the Server Public key format to Java compatible from
        key = key.replace("-----BEGIN PUBLIC KEY-----\n", "");
        key = key.replace("\n-----END PUBLIC KEY-----", "");

        // Creating the public key from the string format received from server
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey serverPublicKeySig = keyFactory
                .generatePublic(new X509EncodedKeySpec(Base64.decode(key.toString(), Base64.DEFAULT)));
        return serverPublicKeySig;
    }

    /**
     * {@code getDataValidity} is used to verify the digital signature of the
     * received data. If the verification is true then {@code true} is returned
     * otherwise {@code false}.
     * 
     * @param key
     *            the PublicKey received from server.
     * @param data
     *            the data received from server.
     * @param serverDataSig
     *            the Signature corresponding to the received data.
     * @return Boolean value.
     * @throws NoSuchAlgorithmException
     *             if the specified algorithm is not available.
     * @throws InvalidKeyException
     *             if publicKey is not valid.
     * @throws SignatureException
     *             if this Signature instance is not initialized properly.
     */
    private Boolean getDataValidity(PublicKey key, String data, String serverDataSig)
            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        Signature s = Signature.getInstance("SHA256withRSA");
        s.initVerify(key);
        byte[] byte_dataFromServer = data.getBytes();
        s.update(byte_dataFromServer);
        byte[] byte_serverDataSig = Base64.decode(serverDataSig, Base64.DEFAULT);
        Boolean valid = s.verify(byte_serverDataSig);
        return valid;
    }

    /**
     * This method {@code extractDataFromJson} is used to extract the data from
     * JSONArray
     * 
     * @param arg0
     *            [0]-JSONArray formated data, arg[1]-contains the tag name
     *            corresponding to which the data is to be extracted.
     * @return Vector<String>, array of values extracted.
     */
    public Vector<String> extractDataFromJson(String... arg0) {
        Vector<String> valuesExtractedFromData = new Vector<String>();
        try {
            JSONArray json = new JSONArray(arg0[0]);
            for (int i = 0; i < json.length(); i++) {
                JSONObject obj = json.getJSONObject(i);
                valuesExtractedFromData.add(obj.getString(arg0[1]));
            }
            return valuesExtractedFromData;
        } catch (JSONException e) {

            e.printStackTrace();
            valuesExtractedFromData.add("error");
            return valuesExtractedFromData;
        }
    }

}