Android: decrypt RSA text using a Public key stored in a file

androidencryptionrsa

I've been several days trying to do it without success.

There are plenty of similar questions here in StackOverflow and even two of them are exactly the same as mine but unanswered and unresolved:
1) Convert PHP RSA PublicKey into Android PublicKey
2) Android: how to decrypt an openssl encrypted file with RSA key?

My scenario:
I have some text encrypted using RSA (not encrypted by me). I have a "public.key" file in my res/raw folder with the public key needed to decrypt it (the public key related to the private key used to encrypt the message), with a format like the following example:
enter image description here

I see a lot of examples of how to decrypt a RSA text, like the following one:

public static byte[] decryptRSA( PublicKey key, byte[] text) throws Exception
      { 
          byte[] dectyptedText = null;

          Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
          cipher.init(Cipher.DECRYPT_MODE, key);
          dectyptedText = cipher.doFinal(text);
          return dectyptedText;
      }

But my question is, how to get the proper PublicKey instance from the file? No examples of this.

If I simply try:

    InputStream is = getResources().openRawResource(R.raw.public);
    DataInputStream dis = new DataInputStream(is);
    byte [] keyBytes = new byte [(int) is.available()];
    dis.readFully(keyBytes);
    dis.close();
    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    return keyFactory.generatePublic(spec);

I get an InvalidKeyException in the return sentence.
Would I need to decode Hex or Base64? Aren't the first and last lines of the public key file a problem (the ones with "—-BEGIN PUBLIC KEY—-" and so)?

Maybe we could get the answer of this properly for the first time in StackOverflow:-)

Best Answer

Finally solved!!! Drums, trumpets and a symphony of enchanting sounds!!!

public static byte[] decryptRSA(Context mContext, byte[] message) throws Exception { 

    // reads the public key stored in a file
    InputStream is = mContext.getResources().openRawResource(R.raw.sm_public);
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    List<String> lines = new ArrayList<String>();
    String line = null;
    while ((line = br.readLine()) != null)
        lines.add(line);

    // removes the first and last lines of the file (comments)
    if (lines.size() > 1 && lines.get(0).startsWith("-----") && lines.get(lines.size()-1).startsWith("-----")) {
        lines.remove(0);
        lines.remove(lines.size()-1);
    }

    // concats the remaining lines to a single String
    StringBuilder sb = new StringBuilder();
    for (String aLine: lines)
        sb.append(aLine);
    String keyString = sb.toString();
    Log.d("log", "keyString:"+keyString);

    // converts the String to a PublicKey instance
    byte[] keyBytes = Base64.decodeBase64(keyString.getBytes("utf-8"));
    X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey key = keyFactory.generatePublic(spec);

    // decrypts the message
    byte[] dectyptedText = null;
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, key);
    dectyptedText = cipher.doFinal(Base64.decodeBase64(message));
    return dectyptedText;
}

The solution was to Base64 decode not only the public key read from the file, but also the crypted message itself!

By the way, I read the public key from the file the way @Nikolay suggested (tnx again man).

Thank you all very much for your help. StackOverflow rocks!

Related Topic