Android RSA encrypt decrypt message Tutorial

RSA (Rivest-Shamir-Adleman) is one of the best secure encryption algorithms that is currently used by many developers. This algorithm involves four steps which are the key generation, key distribution, encryption, and decryption. It is asymmetric encryption by using public key and private key for encrypting and decryption confidential data. The public key is open to all people and its mostly used to encrypt data.

There have two methods in RSA which are encrypted and signed. What is the difference between encrypting and signing data in RSA?

By encrypting, you use the public key to write a message and use the private key to read a message.

By signing, you use the private key to write message’s signature and use the public key to verify the message.

In this tutorial, I will teach you how to use RSA encrypt and decrypt a message in your android project.

Creating a New Project

1. Open Android Studio IDE in your computer.
2. Create a new project and Edit the Application name to “RSAExample”.
(Optional) You can edit the company domain or select the suitable location for current project tutorial. Then click next button to proceed.
3. Select Minimum SDK (API 15:Android 4.0.3 (IceCreamSandwich). I choose the API 15 because many android devices currently are support more than API 15. Click Next button.
4. Choose “Empty Activity” and Click Next button
5. Lastly, press finish button.

Create a new class

Right-click your package name and create a class “RSA”, after that paste the source code from the bottom sample to this class. This class provides all the encrypt, decrypt, sign and verify function. So you can just use this class in your activity.

import android.util.Base64;

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

public class RSA {
    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    private static final String PUBLIC_KEY = "RSAPublicKey";
    private static final String PRIVATE_KEY = "RSAPrivateKey";

    public static byte[] decryptBASE64(String key) throws Exception {
        return Base64.decode(key, Base64.DEFAULT);
    }

    public static String encryptBASE64(byte[] key) throws Exception {
        return Base64.encodeToString(key, Base64.DEFAULT);
    }


    public static String sign(byte[] data, String privateKey) throws Exception {

        byte[] keyBytes = decryptBASE64(privateKey);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);

        return encryptBASE64(signature.sign());
    }


    public static boolean verify(byte[] data, String publicKey, String sign)
            throws Exception {

        byte[] keyBytes = decryptBASE64(publicKey);

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        PublicKey pubKey = keyFactory.generatePublic(keySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);

        return signature.verify(decryptBASE64(sign));
    }


    public static byte[] decryptByPrivateKey(byte[] data, String key)
            throws Exception {

        byte[] keyBytes = decryptBASE64(key);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }


    public static byte[] decryptByPublicKey(byte[] data, String key)
            throws Exception {

        byte[] keyBytes = decryptBASE64(key);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }


    public static byte[] encryptByPublicKey(byte[] data, String key)
            throws Exception {

        byte[] keyBytes = decryptBASE64(key);

        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }


    public static byte[] encryptByPrivateKey(byte[] data, String key)
            throws Exception {

        byte[] keyBytes = decryptBASE64(key);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

    public static String getPrivateKey(Map<String, Object> keyMap)
            throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());
    }

    public static String getPublicKey(Map<String, Object> keyMap)
            throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());
    }


    public static Map<String, Object> initKey() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator
                .getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);

        KeyPair keyPair = keyPairGen.generateKeyPair();

        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        Map<String, Object> keyMap = new HashMap<String, Object>(2);

        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    public static PublicKey getPublicKey(String MODULUS,String EXPONENT) throws Exception{
        byte[] modulusBytes = Base64.decode(MODULUS,0);
        byte[] exponentBytes = Base64.decode(EXPONENT,0);

        BigInteger modulus = new BigInteger(1, (modulusBytes) );
        BigInteger exponent = new BigInteger(1, (exponentBytes));

        RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
        KeyFactory kf = KeyFactory.getInstance(RSA.KEY_ALGORITHM);
        return kf.generatePublic(spec);
    }

    public static byte[] encrypt(Key publicKey, String s) throws Exception{
        byte[] byteData = s.getBytes();
        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(byteData);


        return encryptedData;
    }

}

Create two new activity

By create an activity, right click package name > new > Activity > Empty Activity. (Repeat 2 times cause we need extra 2 activity) First Activity “EncryptionActivity” and another Activity “SignatureActivity”.

Edit activity_encryption layout

Go to this layout and edit to the sample below. I add 3 edit text and two buttons in this layout.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/userdataEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="Enter Message to be encypt"/>
    <EditText
        android:id="@+id/encryptedEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:editable="false"
        android:hint="(Public Key)Encrypted Message"/>
    <EditText
        android:id="@+id/decryptedEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="(Private Key)Decrypted Message"/>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_horizontal">
        <Button
            android:id="@+id/encryptButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Encrypt"/>
        <Button
            android:id="@+id/decryptButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Decrypt"/>
    </LinearLayout>

</LinearLayout>

Edit activity_signature layout

Modify the signature activity layout to the sample source code below.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="//schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <EditText
        android:id="@+id/userdataEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="Enter Message to be sign"/>

    <EditText
        android:id="@+id/signedEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="(Private Key)Signed Message"/>

    <EditText
        android:id="@+id/provedEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="(Public Key)Verify Signed Message"/>
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_horizontal">
        <Button
            android:id="@+id/signButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Sign"/>
        <Button
            android:id="@+id/proveButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Verify"/>
    </LinearLayout>
</LinearLayout>

Edit EncryptionActivity.java class

Go to EncryptionActivity.class and this class will perform encrypt using public key and decrypt the message using the private key.

public class EncryptionActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText userdataEdit;
    private EditText encryptedEdit;
    private EditText decryptedEdit;
    private Button encryptButton;
    private Button decryptButton;
    byte[] encodeData = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_encryption);

        userdataEdit = (EditText)findViewById(R.id.userdataEdit);
        encryptedEdit = (EditText)findViewById(R.id.encryptedEdit);
        decryptedEdit = (EditText)findViewById(R.id.decryptedEdit);
        encryptButton = (Button)findViewById(R.id.encryptButton);
        decryptButton = (Button)findViewById(R.id.decryptButton);
        encryptButton.setOnClickListener(this);
        decryptButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {

        Intent intent = getIntent();
        String publicKey = intent.getStringExtra("pubkey");
        String privateKey = intent.getStringExtra("prikey");
        if (view == encryptButton){


            String userStr = userdataEdit.getText().toString();
            if(userStr.equals("")){
                Toast.makeText(getApplicationContext(),"Please enter message",Toast.LENGTH_SHORT).show();
                return;
            }
            byte[] userData = userStr.getBytes();
            try {
                encodeData = RSA.encryptByPublicKey(userData, publicKey);
                String encodeStr = new BigInteger(1, encodeData).toString(16);
                encryptedEdit.setText(encodeStr);
            }catch (Exception e){
                e.printStackTrace();
            }

        }else if (view == decryptButton){

            if(encodeData == null){
                Toast.makeText(getApplicationContext(),"Please use public key to encrypt",Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                byte[] decodeData = RSA.decryptByPrivateKey(encodeData,privateKey);
                String decodeStr = new String(decodeData);
                decryptedEdit.setText(decodeStr);
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }
}

Edit SignatureActivity.java class

Modify this class to below sample so you can sign and verify message in this activity.

public class SignatureActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText userdataEdit;
    private EditText signedEdit;
    private EditText provedEdit;
    private Button signButton;
    private Button proveButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_signature);

        userdataEdit = (EditText)findViewById(R.id.userdataEdit);
        signedEdit = (EditText)findViewById(R.id.signedEdit);
        provedEdit = (EditText)findViewById(R.id.provedEdit);
        signButton = (Button)findViewById(R.id.signButton);
        proveButton = (Button)findViewById(R.id.proveButton);
        signButton.setOnClickListener(this);
        proveButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent = getIntent();
        String publicKey = intent.getStringExtra("pubkey");
        String privateKey = intent.getStringExtra("prikey");
        if (view == signButton){

            String userStr = userdataEdit.getText().toString();
            if (userStr.equals("")){
                Toast.makeText(getApplicationContext(),"Please enter message",Toast.LENGTH_SHORT).show();
                return;
            }
            byte[] usrData = userStr.getBytes();
            try {
                String sign = RSA.sign(usrData, privateKey);
                signedEdit.setText(sign);
            }catch (Exception e){
                e.printStackTrace();
            }

        }else if (view == proveButton){


            String sign = signedEdit.getText().toString();
            if (sign.equals("")){
                Toast.makeText(getApplicationContext(),"Please sign your message",Toast.LENGTH_SHORT).show();
                return;
            }
            String usrStr = userdataEdit.getText().toString();
            if(usrStr.equals("")){
                Toast.makeText(getApplicationContext(),"Please enter message",Toast.LENGTH_SHORT).show();
                return;
            }
            try {
                boolean status = RSA.verify(usrStr.getBytes(),publicKey,sign);
                if (status){
                    provedEdit.setText("Verify Sign Success");
                }else {
                    provedEdit.setText("Verify Sign Fail! Message Modified or Not Correct");
                }
            }catch (Exception e){
                e.printStackTrace();
            }


        }
    }
}

Edit activity_main layout

After that, modify this class by adding 3 buttons and 2 edit text.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="//schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/initkeyButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Generate Private and Public Key"/>

    <EditText
        android:id="@+id/privatekeyEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="Public Key"/>
    <EditText
        android:id="@+id/publickeyEdit"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:hint="Private Key"/>

    <Button
        android:id="@+id/btnEncrypt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Encryption"/>

    <Button
        android:id="@+id/btnSig"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Signature"/>
</LinearLayout>

Edit MainActivity.java class

Edit this class to the source code below so you can generate private and public key in this activity.

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText publickeyEdit;
    private EditText privatekeyEdit;
    private Button initkeyButton;
    private Button btnEncrypt;
    private Button btnSig;
    private static String publicKey = "";
    private static String privateKey = "";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        publickeyEdit = (EditText)findViewById(R.id.publickeyEdit);
        privatekeyEdit = (EditText)findViewById(R.id.privatekeyEdit);
        initkeyButton = (Button)findViewById(R.id.initkeyButton);
        btnEncrypt = (Button)findViewById(R.id.btnEncrypt);
        btnSig = (Button)findViewById(R.id.btnSig);

        btnEncrypt.setOnClickListener(this);
        btnSig.setOnClickListener(this);
        initkeyButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {

            if (view == initkeyButton){
                try {
                    Map<String, Object> keyMap = RSA.initKey();
                    publicKey = RSA.getPublicKey(keyMap);
                    privateKey = RSA.getPrivateKey(keyMap);
                    publickeyEdit.setText(publicKey);
                    privatekeyEdit.setText(privateKey);
                }catch (Exception e){
                    e.printStackTrace();
                }

            }else if(view == btnEncrypt){
                if(publicKey==null||privateKey==null){
                    Toast.makeText(getApplicationContext(),"Please generate public and private key",Toast.LENGTH_LONG);
                }
                else{
                    Intent intent = new Intent(this,EncryptionActivity.class);
                    intent.putExtra("pubkey",publicKey);
                    intent.putExtra("prikey",privateKey);
                    startActivity(intent);
                }


            }else if(view == btnSig){
                if(publicKey==null||privateKey==null){
                    Toast.makeText(getApplicationContext(),"Please generate public and private key",Toast.LENGTH_LONG);
                }
                else {
                    Intent intent = new Intent(this, SignatureActivity.class);
                    intent.putExtra("pubkey", publicKey);
                    intent.putExtra("prikey", privateKey);
                    startActivity(intent);
                }
            }

    }



}

Run Your Project

Finally, you are complete this project, now you can check it how the RSA encrypt and signature work in android.

(Android RSA encrypt decrypt message)

Source Code

(Visited 10,181 times, 1 visits today)
Advertisements

Yong Loon Ng

Ng Yong Loon, better known as Kristofer is a software engineer and computer scientist who doubles up as an entrepreneur.

You may also like...

3 Responses

  1. issacnitin says:

    Why doesn’t this work with key generated by JSEncrypt

  2. Vishal Bhayani says:

    Superb Post
    Helped me a Lot
    Thanks

  3. Sitanan says:

    This helps me a lot!
    Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *