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.
Why doesn’t this work with key generated by JSEncrypt
Superb Post
Helped me a Lot
Thanks
This helps me a lot!
Thank you.