5

I am working in a project where I have to encrypt password using RSA public key. I tried many samples and solutions from SO like as follows

  1. Android RSA encryption from public string

  2. RSA using SpongyCastle

But none of the solutions worked in my case unfortunately. I was getting following exceptions repeatedly if i try with any work around

Error Log:

04-21 07:50:57.876 18842-18842/com.takeoffandroid.passwordencryption W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
04-21 07:50:57.986 18842-18842/com.takeoffandroid.passwordencryption W/System.err: java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
04-21 07:50:57.986 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.android.org.conscrypt.OpenSSLKey.getPublicKey(OpenSSLKey.java:250)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.android.org.conscrypt.OpenSSLRSAKeyFactory.engineGeneratePublic(OpenSSLRSAKeyFactory.java:47)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at java.security.KeyFactory.generatePublic(KeyFactory.java:172)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.takeoffandroid.passwordencryption.MainActivity.RSAEncrypt(MainActivity.java:181)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.takeoffandroid.passwordencryption.MainActivity.onCreate(MainActivity.java:80)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.Activity.performCreate(Activity.java:6532)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2383)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2490)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.ActivityThread.access$900(ActivityThread.java:157)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1351)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.os.Looper.loop(Looper.java:148)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5437)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err: Caused by: java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.android.org.conscrypt.NativeCrypto.d2i_PUBKEY(Native Method)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:     at com.android.org.conscrypt.OpenSSLKey.getPublicKey(OpenSSLKey.java:248)
04-21 07:50:57.987 18842-18842/com.takeoffandroid.passwordencryption W/System.err:  ... 16 more

My Requirement:

I have a public key with me and I wanted to encrypt the text entered in the edittext with that public key. For Eg: Password@123 should be encrypted using public key.

Public Key:

public static String PUBLIC_KEY = "-----BEGIN RSA PUBLIC KEY-----\n" +
            "MMDDFDFK43545mmdf499Mdfdasl43ND/GGKLGKL4434safddEcBFfbTZUM517\n" +
            "VDSVFS45fwdGJGGLKGGL332XSA3=d/S/2ETegJPFQ4sjiY7/DsS2o9Gr\n" +
            "asBASF3465243FCDXSDCDxsSFC39NkDiNO2QKNXivAQVpuJeuoDeK\n" +
            "wNGmwDkIsvxBn8u55QpOwvdaRBeLqllJ6xoF6OuwnD0IB4tVDL2MbMVj1U9GtEGL\n" +
            "DJKHSJAH434jjhdds54KkhjbvGJGGGG/Vn4OYNooIWE9uuiyxm2M\n" +
            "AFSDAFXZB546FGHxcvv324FDGJIYTaa346/9xQIDAQAB\n" +
            "-----END RSA PUBLIC KEY-----";

Code Implementations I tried:

Sample I:

  public static String encryptDataRSA(final String data) throws IOException {
        final byte[] dataToEncrypt = data.getBytes();
        byte[] encryptedData = null;

        try {

            PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(RSAUtils.PUBLIC_KEY.getBytes()));

            final Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            encryptedData = cipher.doFinal(dataToEncrypt);

            try {
                final String encryptedText = new String(Base64.encode(encryptedData, Base64.DEFAULT), "UTF-8");
                return encryptedText.toString();
            }
            catch (final UnsupportedEncodingException e1) { return null; }
        } catch (Exception e) { e.printStackTrace(); }

        return "ERROR";
    }

Sample II:

    public byte[] RSAEncrypt(final String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException {
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        KeyPair kp = kpg.genKeyPair();
        PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(RSAUtils.PUBLIC_KEY.getBytes()));

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(plain.getBytes());
        System.out.println("EEncrypted?????" + org.apache.commons.codec.binary.Hex.encodeHexString(encryptedBytes));
        return encryptedBytes;
    }

Sample III:

 public static String encryptRSAToString(String text, String strPublicKey) {
        byte[] cipherText = null;
        String strEncryInfoData="";
        try {

            KeyFactory keyFac = KeyFactory.getInstance("RSA");
            KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(strPublicKey.trim().getBytes(), Base64.DEFAULT));
            Key publicKey = keyFac.generatePublic(keySpec);

            // get an RSA cipher object and print the provider
            final Cipher cipher = Cipher.getInstance("RSA");
            // encrypt the plain text using the public key
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            cipherText = cipher.doFinal(text.getBytes());
            strEncryInfoData = new String(Base64.encode(cipherText,Base64.DEFAULT));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return strEncryInfoData.replaceAll("(\\r|\\n)", "");
    }

Any help or suggestions would be really helpful to me. Thanks in advance.

Community
  • 1
  • 1
Chandru
  • 5,954
  • 11
  • 45
  • 85

2 Answers2

19

try this.

public static String PUBLIC_KEY = "YOUR PUBLIC KEY";

static String enccriptData(String txt)
{
  String encoded = "";
  byte[] encrypted = null;
    try {
        byte[] publicBytes = Base64.decode(PUBLIC_KEY, Base64.DEFAULT);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); //or try with "RSA"
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        encrypted = cipher.doFinal(txt.getBytes());
        encoded = Base64.encodeToString(encrypted, Base64.DEFAULT);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    return encoded;
}

EDIT:

You can use my code but read the comment of James K Polk, he's right

Israel
  • 436
  • 3
  • 12
  • Thanks for replying. Again I got the following exception – Chandru Apr 21 '17 at 05:29
  • You put the key as in the example? X509EncodedKeySpec expects DER encoded data not PEM The code works correctly for me. . – Israel Apr 21 '17 at 08:38
  • 2
    please, don't publish your private key. In your code, you have a key: public static String PUBLIC_KEY = "-----BEGIN RSA PUBLIC KEY-----\n" + "MMDDFDFK43545mmdf499Mdfdasl43ND/GGKLGKL4434safddEcBFfbTZUM517\n" +..... Place it on a single line without -----BEGIN RSA PUBLIC KEY----, -----END RSA PUBLIC KEY----- and \n Like that of my example: public static String PUBLIC_KEY = "MMDDFDFK43545mmdf499Mdfdasl43ND......."; – Israel Apr 21 '17 at 10:55
  • I ran your code and it doesn't work. Your key has an embedded "=" character which is invalid. Did you run your own code? – President James K. Polk Apr 21 '17 at 11:50
  • yes, i use it in one application and work fine obviously with my key – Israel Apr 21 '17 at 12:02
  • @Israel It's public key, not private. No matter distributing it there is no secret in it as it's RSA algorithm. – Gweltaz Niquel Jun 21 '18 at 15:30
  • @Gweltaz Niquel He posted the private key in the pastebin of his comment, that is what i meant – Israel Jun 21 '18 at 17:27
  • @Israel, Dude! you are awesome. – Akshay Sahai Sep 05 '19 at 08:46
4

The Kotlin Code for RSA encryption:

first of all you need to remove "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" and ... to have a clean text.

Just use this:

 publicKy = publicKy  .replace("\\r".toRegex(), "")
        .replace("\\n".toRegex(), "")
        .replace(System.lineSeparator().toRegex(), "")
        .replace("-----BEGIN PUBLIC KEY-----", "")
        .replace("-----END PUBLIC KEY-----", "")


    val encryptedString = enccriptData(input,publicKy)

' input ' is the text which you want to encrypt with your public key,
then you need to use this method:

fun enccriptData(txt: String, pk: String): String? {
    var encoded = ""
    var encrypted: ByteArray? = null
    try {
        val publicBytes: ByteArray = Base64.decode(pk, Base64.DEFAULT)
        val keySpec = X509EncodedKeySpec(publicBytes)
        val keyFactory: KeyFactory = KeyFactory.getInstance("RSA")
        val pubKey: PublicKey = keyFactory.generatePublic(keySpec)
        val cipher: Cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING")
        cipher.init(Cipher.ENCRYPT_MODE, pubKey)
        encrypted = cipher.doFinal(txt.toByteArray())
        encoded = Base64.encodeToString(encrypted, Base64.DEFAULT)
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return encoded
}