Software Requirement
Android Studio
Android SDK
Tutorial: Generate and Save Keys
Use JAVA tool keytool.exe for Windows $keytool for Unix to generate Keystore on the server-side:
Open "Terminal" and run the following command
keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048
Enter Keystore password and other required information. Press "yes" to confirm
Now you can see the listed Keystore by this command
keytool -list -keystore keystore.jks
You have to store by running this command
keytool -export -alias mydomain -file mydomain.crt -keystore keystore.jks
Certificate stored in file <mydomain.crt>
Open the installed app from the Launchpad and will see this interface, close the Tip of the Day
From this interface, you can execute many tasks including open, create KeyStore
Find the saved certificate named "mydomain.crt" from your root folder and drag it into KeyStore App
Here is all the information about the Saved Key and now Click on "Import"
Choose "BKS" and click on "ok"
Enter the Name of the Certificate and click on "ok"
This interface means the key has imported and saved
4)Import the certificate exported from the server key a certificate that will be used on client-side.
Command: keytool -importcert -keystore /Users/jobairhossain/mydomain.crt
Note: Android need a Bouncy Castle certificate, which is not provided by JAVA, therefore, you need to add the external JAR (bcprov-jdk16-145.jar) into “your_java_jdk_path/jre/lib/ext” and then modify the “java.security” file, adding a new line: “security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider”.
All the preparation work done above is for one-way authentication. For a two-way authentication, the work we should do next is to generate a key for the client. Command $ keytool -genkey -alias kserverkey -keystore /Users/jobair/Desktop/bksclient.keystore in Linux or macOs
2. Create android projects for server and client
Server
Layout
In this lab, the main layout for the server contains a button to start the server to listen to the connection from clients; and the layout for the client contains a text box for users to input messages to send and buttons for sending messages and close a connection.
//main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="348dp"
android:text="Client Message"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.464"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Server"
tools:layout_editor_absoluteX="148dp"
tools:layout_editor_absoluteY="214dp"
tools:ignore="MissingConstraints"
android:onClick="connect"/>
</android.support.constraint.ConstraintLayout>
Server side
//MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements DataDisplay {
TextView serverMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serverMessage = findViewById(R.id.textview);
}
public void connect(View view){
MyServer server = new MyServer(getBaseContext());
server.setEventListerner(this);
server.startListening();
}
public void Display(String message){
serverMessage.setText(""+message);
}
}
//MyServer.Java
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
public class MyServer {
Thread m_objThread;
ServerSocket m_server;
DataDisplay m_dataDisplay;
private static final int SERVER_PORT = 5000;
private static final String SERVER_KEY_PASSWORD = "123456";
private static final String SERVER_AGREEMENT = "TLS";
private static final String SERVER_KEY_MANAGER = "X509";
private static final String SERVER_KEY_KEYSTORE = "BKS";
Context ctx;
SSLServerSocket serverSocket;
public MyServer(Context context){
this.ctx = context;
}
public void setEventListerner(DataDisplay dataDisplay){
m_dataDisplay = dataDisplay;
}
public void startListening(){
m_objThread = new Thread(new Runnable() {
@Override
public void run() {
try{
SSLContext sslContext = SSLContext.getInstance(SERVER_AGREEMENT);
KeyManagerFactory keyManager = KeyManagerFactory.getInstance(SERVER_KEY_MANAGER);
KeyStore kks = KeyStore.getInstance(SERVER_KEY_KEYSTORE);
kks.load(ctx.getResources().openRawResource(R.raw.bksserver), SERVER_KEY_PASSWORD.toCharArray());
keyManager.init(kks,SERVER_KEY_PASSWORD.toCharArray());
sslContext.init(keyManager.getKeyManagers(),null,null);
serverSocket = (SSLServerSocket)sslContext.getServerSocketFactory().createServerSocket(SERVER_PORT);
if (serverSocket != null) Log.i("ServerSocket", "Server Socket is ready to accept!!");
Socket connectedSocket = serverSocket.accept();
Message clientMessage = Message.obtain();
ObjectInputStream ois = new ObjectInputStream(connectedSocket.getInputStream());
String strMessage = (String)ois.readObject();
clientMessage.obj = strMessage;
mHandler.sendMessage(clientMessage);
ObjectOutputStream oos = new ObjectOutputStream(connectedSocket.getOutputStream());
oos.writeObject("Hello Client");
ois.close();
oos.close();
m_server.close();
}catch (Exception e){
Message msg = Message.obtain();
msg.obj = e.getMessage();
mHandler.sendMessage(msg);
}
}
});
m_objThread.start();
}
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
m_dataDisplay.Display(msg.obj.toString());
}
};
}
//DataDisplay.Java
public interface DataDisplay {
void Display(String message);
}
// AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.smsd.arabin.smsd_server">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
//Client
//main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/button"
android:layout_alignParentTop="true"
android:layout_marginStart="7dp"
android:layout_marginTop="164dp"
android:text="Server Message"
tools:ignore="RtlCompat" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Start Client"
android:onClick="Start"/>
</RelativeLayout>
//Client side
//MainActivity.java
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
public class MainActivity extends AppCompatActivity {
TextView serverMessage;
Thread m_objectThreadClient;
private static final String CLIENT_KEY_PASSWORD = "123456";
private static final String CLIENT_TRUST_PASSWORD = "123456";//
private static final String CLIENT_AGREEMENT = "TLS";// the protocol used
private static final String CLIENT_KEY_MANAGER = "X509";// key manager
private static final String CLIENT_TRUST_MANAGER = "X509";
private static final String CLIENT_KEY_KEYSTORE = "BKS";// key store,use
// BouncyCastle
private static final String CLIENT_TRUST_KEYSTORE = "BKS";//
private SSLSocket clientSocket;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serverMessage = findViewById(R.id.text);
}
public void Start(View view){
m_objectThreadClient = new Thread(new Runnable() {
@Override
public void run() {
try{
SSLContext sslContext = SSLContext.getInstance(CLIENT_AGREEMENT);
// get the X509 key manager instance of KeyManagerFactory and
// TrustManagerFactory
KeyManagerFactory keyManager = KeyManagerFactory.getInstance(CLIENT_KEY_MANAGER);
TrustManagerFactory trustManager = TrustManagerFactory.getInstance(CLIENT_TRUST_MANAGER);
// get BKS
KeyStore kks = KeyStore.getInstance(CLIENT_KEY_KEYSTORE);
KeyStore tks = KeyStore.getInstance(CLIENT_TRUST_KEYSTORE);
// load certificate and key of client by reading the key and
// trustful certificate in the resources file
kks.load(getBaseContext().getResources().openRawResource(R.raw.bksclient), CLIENT_KEY_PASSWORD.toCharArray());
tks.load(getBaseContext().getResources().openRawResource(R.raw.cacerts), CLIENT_TRUST_PASSWORD.toCharArray());
// initial key manager
keyManager.init(kks, CLIENT_KEY_PASSWORD.toCharArray());
trustManager.init(tks);
// initial SSLContext
sslContext.init(keyManager.getKeyManagers(), trustManager.getTrustManagers(), null);
Log.i("SslActivity", "start ssl connecting");
WifiManager wifi = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE);
String ip;
if (wifi.isWifiEnabled()){
wifi.setWifiEnabled(true);
WifiInfo wifiInfo = wifi.getConnectionInfo();
ip = Formatter.formatIpAddress(wifiInfo.getIpAddress());
}else {
ip = "127.0.0.1";
}
clientSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(ip,5000);
if(clientSocket!=null) Log.i("SslActivity", "ssl connected");
ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
oos.writeObject("Hello there");
Message serverMessage = Message.obtain();
ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
String strMessage = (String)ois.readObject();
serverMessage.obj = strMessage;
mHandler.sendMessage(serverMessage);
oos.close();
ois.close();
}catch (Exception e){
e.printStackTrace();
}
}
});
m_objectThreadClient.start();
}
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
messageDisplay(msg.obj.toString());
}
};
private void messageDisplay(String s) {
serverMessage.setText(""+s);
}
}
//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.smsd.arabin.smsd_client">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Note: We are all set to go. Our server and the client application are ready to built SSL communication validating the server certificate. Please note Build both applications in Android Emulator that has API level 22 or lower. In case of device please use API level 22 or lower devices, for example, Android version Lollypop. In upper API versions, you might face SSL handshake exception.
The codes here only show how to create SSL sockets and how to established secure communication between the server and client app.
The project here is the protection of data from being intercepted by attackers. By applying SSL to encrypt data, it will be fine even though attackers can make use of tcpdump or other tools to dump the data in the network. Because without the keys, there is a tiny probability that attackers are able to obtain original data.
Why we need SSL?
The primary reason why SSL is used is to keep sensitive information sent across the Internet encrypted so that only the intended recipient can understand it. This is important because the information you send on the Internet is passed from computer to computer to get to the destination server. Any computer in between you and the server can see your credit card numbers, usernames and passwords, and other sensitive information if it is not encrypted with an SSL certificate. When an SSL certificate is used, the information becomes unreadable to everyone except for the server you are sending the information to. This protects it from hackers and identity thieves.
In addition to encryption, a proper SSL certificate also provides authentication. This means you can be sure that you are sending information to the right server and not to a criminal’s server.
In this case, if we don’t have SSL, the message sent by the client app can be seen by the intruder as shown below
But If the SSL is enable, then the message is encrypted and secured