Skip to content

Instantly share code, notes, and snippets.

@awesometic
Last active January 11, 2024 07:15
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save awesometic/f1f52acf5904189f687724e42c461413 to your computer and use it in GitHub Desktop.
Save awesometic/f1f52acf5904189f687724e42c461413 to your computer and use it in GitHub Desktop.
RSA encryption example for android
/**
* Created by Awesometic
* It's encrypt returns Base64 encoded, and also decrypt for Base64 encoded cipher
* references: http://stackoverflow.com/questions/12471999/rsa-encryption-decryption-in-android
*/
import android.util.Base64;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class RSACipher {
KeyPairGenerator kpg;
KeyPair kp;
PublicKey publicKey;
PrivateKey privateKey;
byte[] encryptedBytes, decryptedBytes;
Cipher cipher, cipher1;
String encrypted, decrypted;
private final static String CRYPTO_METHOD = "RSA";
private final static int CRYPTO_BITS = 2048;
public RSACipher()
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
generateKeyPair();
}
private void generateKeyPair()
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
kpg = KeyPairGenerator.getInstance(CRYPTO_METHOD);
kpg.initialize(CRYPTO_BITS);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
}
/**
* Encrypt plain text to RSA encrypted and Base64 encoded string
*
* @param args
* args[0] should be plain text that will be encrypted
* If args[1] is be, it should be RSA public key to be used as encrypt public key
* @return a encrypted string that Base64 encoded
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws IllegalBlockSizeException
* @throws BadPaddingException
*/
public String encrypt(Object... args)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
String plain = (String) args[0];
PublicKey rsaPublicKey;
if (args.length == 1) {
rsaPublicKey = this.publicKey;
} else {
rsaPublicKey = (PublicKey) args[1];
}
cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
encryptedBytes = cipher.doFinal(plain.getBytes(StandardCharsets.UTF_8));
return Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
}
public String decrypt(String result)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
cipher1 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher1.init(Cipher.DECRYPT_MODE, privateKey);
decryptedBytes = cipher1.doFinal(Base64.decode(result, Base64.DEFAULT));
decrypted = new String(decryptedBytes);
return decrypted;
}
public String getPublicKey(String option)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
switch (option) {
case "pkcs1-pem":
String pkcs1pem = "-----BEGIN RSA PUBLIC KEY-----\n";
pkcs1pem += Base64.encodeToString(publicKey.getEncoded(), Base64.DEFAULT);
pkcs1pem += "-----END RSA PUBLIC KEY-----";
return pkcs1pem;
case "pkcs8-pem":
String pkcs8pem = "-----BEGIN PUBLIC KEY-----\n";
pkcs8pem += Base64.encodeToString(publicKey.getEncoded(), Base64.DEFAULT);
pkcs8pem += "-----END PUBLIC KEY-----";
return pkcs8pem;
case "base64":
return Base64.encodeToString(publicKey.getEncoded(), Base64.DEFAULT);
default:
return null;
}
}
public static PublicKey stringToPublicKey(String publicKeyString)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
IllegalBlockSizeException,
BadPaddingException {
try {
if (publicKeyString.contains("-----BEGIN PUBLIC KEY-----") || publicKeyString.contains("-----END PUBLIC KEY-----"))
publicKeyString = publicKeyString.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");
byte[] keyBytes = Base64.decode(publicKeyString, Base64.DEFAULT);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
return null;
}
}
}
@BehradJafari
Copy link

Excellent coding .
you can use below code for creating PRIVATE KEY from a string:

public static PrivateKey stringToPrivate(String private_key)
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            IllegalBlockSizeException,
            BadPaddingException {

        try {
            // Read in the key into a String
            StringBuilder pkcs8Lines = new StringBuilder();
            BufferedReader rdr = new BufferedReader(new StringReader(private_key));
            String line;
            while ((line = rdr.readLine()) != null) {
                pkcs8Lines.append(line);
            }

            // Remove the "BEGIN" and "END" lines, as well as any whitespace

            String pkcs8Pem = pkcs8Lines.toString();
            pkcs8Pem = pkcs8Pem.replace("-----BEGIN PRIVATE KEY-----", "");
            pkcs8Pem = pkcs8Pem.replace("-----END PRIVATE KEY-----", "");
            pkcs8Pem = pkcs8Pem.replaceAll("\\s+", "");

            // Base64 decode the result

            byte[] pkcs8EncodedBytes = Base64.decode(pkcs8Pem, Base64.DEFAULT);

            // extract the private key

            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8EncodedBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey privKey = kf.generatePrivate(keySpec);
            return privKey;

        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            e.printStackTrace();

            return null;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;


    }

@miladev95
Copy link

miladev95 commented Jun 11, 2019

when i run below :

                   String result = null;
                   String g = null;
                   try {
                       result = new Pgp().encrypt("slkdfjlks");
                   } catch (NoSuchAlgorithmException e) {
                       e.printStackTrace();
                   } catch (NoSuchPaddingException e) {
                       e.printStackTrace();
                   } catch (InvalidKeyException e) {
                       e.printStackTrace();
                   } catch (IllegalBlockSizeException e) {
                       e.printStackTrace();
                   } catch (BadPaddingException e) {
                       e.printStackTrace();
                   }
                   try {
                       g = new Pgp().decrypt(result);
                   } catch (NoSuchAlgorithmException e) {
                       e.printStackTrace();
                   } catch (NoSuchPaddingException e) {
                       e.printStackTrace();
                   } catch (InvalidKeyException e) {
                       e.printStackTrace();
                   } catch (IllegalBlockSizeException e) {
                       e.printStackTrace();
                   } catch (BadPaddingException e) {
                       e.printStackTrace();
                   }

i get this error :
javax.crypto.BadPaddingException: data hash wrong
and exception is because of this line in decrypt function
decryptedBytes = cipher1.doFinal(Base64.decode(result, Base64.DEFAULT));

public String decrypt(String result)
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            IllegalBlockSizeException,
            BadPaddingException {

        cipher1 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
        cipher1.init(Cipher.DECRYPT_MODE, privateKey);
        decryptedBytes = cipher1.doFinal(Base64.decode(result, Base64.DEFAULT));
        decrypted = new String(decryptedBytes);

        return decrypted;
}

@chax007
Copy link

chax007 commented Jul 8, 2021

when i run below :

                   String result = null;
                   String g = null;
                   try {
                       result = new Pgp().encrypt("slkdfjlks");
                   } catch (NoSuchAlgorithmException e) {
                       e.printStackTrace();
                   } catch (NoSuchPaddingException e) {
                       e.printStackTrace();
                   } catch (InvalidKeyException e) {
                       e.printStackTrace();
                   } catch (IllegalBlockSizeException e) {
                       e.printStackTrace();
                   } catch (BadPaddingException e) {
                       e.printStackTrace();
                   }
                   try {
                       g = new Pgp().decrypt(result);
                   } catch (NoSuchAlgorithmException e) {
                       e.printStackTrace();
                   } catch (NoSuchPaddingException e) {
                       e.printStackTrace();
                   } catch (InvalidKeyException e) {
                       e.printStackTrace();
                   } catch (IllegalBlockSizeException e) {
                       e.printStackTrace();
                   } catch (BadPaddingException e) {
                       e.printStackTrace();
                   }

i get this error :
javax.crypto.BadPaddingException: data hash wrong
and exception is because of this line in decrypt function
decryptedBytes = cipher1.doFinal(Base64.decode(result, Base64.DEFAULT));

public String decrypt(String result)
            throws NoSuchAlgorithmException,
            NoSuchPaddingException,
            InvalidKeyException,
            IllegalBlockSizeException,
            BadPaddingException {

        cipher1 = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
        cipher1.init(Cipher.DECRYPT_MODE, privateKey);
        decryptedBytes = cipher1.doFinal(Base64.decode(result, Base64.DEFAULT));
        decrypted = new String(decryptedBytes);

        return decrypted;
}

If you are using a hardcoded private string then you must check that
start/begin is same as pkcs8Pem = pkcs8Pem.replace("-----BEGIN PRIVATE KEY-----", "");
and end/completes with the pkcs8Pem = pkcs8Pem.replace("-----END PRIVATE KEY-----", "");

@SaadTariqpak
Copy link

i get this error on decryption :

com.android.org.bouncycastle.jcajce.provider.util.BadBlockException: unable to decrypt block
at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.getOutput(CipherSpi.java:553)
at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(CipherSpi.java:498)
at javax.crypto.Cipher.doFinal(Cipher.java:2056)
at com.example.magicchatapp.utils.security.RSACipher.decrypt(RSACipher.java:106)
at com.example.magicchatapp.presentation.fragment.SingleChatThreadFragment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment