Friday 11 September 2015

Send Encrypted SMS using Android

You may need to send a secure SMS to your friend over the GSM network. Following is a Tutorial of how you can build Secure SMS messenger using Android.

You can find the How we can receive these secure SMS from this link.

First and foremost, we need to configure the Manifest file with correct permissions.
   
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.priya.sendsms_mis023" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="23"/>
    <uses-permission
        android:name="android.permission.SEND_SMS" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


The most important part is acquire correct permission using
android:name="android.permission.SEND_SMS"

Next, we will take a look at the UI(View) part of the application. It is very simple and all you need to do is add couple of Edit text views and a button to send the encrypted SMS.
 
<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" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView android:text="Enter Message" android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_below="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView android:text="Enter Phone Number" android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/editText"
        android:id="@+id/textView2" />


    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editTextNumber"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView2"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send"
        android:id="@+id/button"
        android:layout_below="@+id/editTextNumber"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />


</RelativeLayout>




Next , we will take a look at how we can do the Encryption part. So I came up with a separate class for this using AES.
public class AESEncrypt {
    private static Key key=null;
    private static Cipher cipher = null;

    private static String algorithm = "AES";
    private static byte[] keyValue=new byte[] {'0','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7'};//

    public AESEncrypt(int size) throws NoSuchAlgorithmException, NoSuchPaddingException {
        //Generate a key
        try {
            if (key == null) {

                key = generateKey();
            }
            if (cipher == null) cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        }
        catch(Exception e)
        {}
    }

    public byte[] encrypt(String msg) throws InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException{
        // encryption pass
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(msg.getBytes());
    }

    public byte[] decrypt(byte[] cipherText) throws InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException{
        // decryption pass
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(cipherText);
    }

    private static Key generateKey() throws Exception
    {
        Key key = new SecretKeySpec(keyValue, algorithm);
        return key;
    }
}


Note that Im using a static AES Key which is hard coded here. This is not a very good security practice. Instead, We need to store the key securely in the device if we are going to use the Symmetric encryption. I would discuss this in a separate post and this is enough for the time being and for learning purposes.
encrypt and decrypt methods in this class itself in order perform all cryptography operations.
The generateKey() function would generate the reuired key based on the initial keyValue and the encryption algorithm which AES in this instance.

Finally, lets examine the main Activity class.
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button button = (Button) findViewById(R.id.button);
        final EditText tvMessage=(EditText)findViewById(R.id.editText);
        final EditText tvNumber=(EditText)findViewById(R.id.editTextNumber);
        final String SENT = "SMS_SENT";
        final String DELIVERED = "SMS_DELIVERED";

        final PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,
                new Intent(SENT), 0);

        final PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
                new Intent(DELIVERED), 0);


        registerReceiver(new BroadcastReceiver(){
            @Override
            public void onReceive(Context arg0, Intent arg1) {
                switch (getResultCode())
                {
                    case Activity.RESULT_OK:
                        Toast.makeText(getBaseContext(), "SMS sent",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                        Toast.makeText(getBaseContext(), "Generic failure",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_NO_SERVICE:
                        Toast.makeText(getBaseContext(), "No service",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_NULL_PDU:
                        Toast.makeText(getBaseContext(), "Null PDU",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case SmsManager.RESULT_ERROR_RADIO_OFF:
                        Toast.makeText(getBaseContext(), "Radio off",
                                Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        }, new IntentFilter(SENT));


        registerReceiver(new BroadcastReceiver(){
            @Override
            public void onReceive(Context arg0, Intent arg1) {
                switch (getResultCode())
                {
                    case Activity.RESULT_OK:
                        Toast.makeText(getBaseContext(), "SMS delivered",
                                Toast.LENGTH_SHORT).show();
                        break;
                    case Activity.RESULT_CANCELED:
                        Toast.makeText(getBaseContext(), "SMS not delivered",
                                Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        }, new IntentFilter(DELIVERED));

        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                try {
                    String msg = tvMessage.getText().toString();
                    String phoneNumber = tvNumber.getText().toString();
                    AESEncrypt aes = new AESEncrypt(256);
                    String base64 = Base64.encodeToString(aes.encrypt(msg), Base64.DEFAULT);
                    SmsManager smsManager = SmsManager.getDefault();
                    smsManager.sendTextMessage(phoneNumber, null, base64, sentPI, deliveredPI);

                }
                catch(Exception ex)
                {}
            }
        });


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}


I used the smsManager class to send the Message across the network. This is the simplest SMS sender in Android. There are two BroadcastReceivers where it can track what is actually happens to the SMS ending process once user clicks the send button.

Following is the Final Screenshot of the application.



Note : If you are sending the SMS to another emulator running on your desktop, you need to specify the port number of that emulator as the phone number. To get a specific port number for the emulator use Android Device Monitor tool.

You can Download the source code from this location.

No comments:

Post a Comment