4

I've got some decryption problems in my Android project.

I'm getting a string signed with a private key and I have to verify(decrypt) it with a public key. I'd like to get exactly the same result as if I were using a PHP function - openssl_public_decrypt ( http://php.net/manual/pl/function.openssl-public-decrypt.php )

I have to do this in my Java project, so I can use Java libs (e.g BouncyCastle, or something else, any recommendations? )

Any ideas how to solve this?

Ok, here's my code. I'm getting the public key like this

PEMReader reader = new PEMReader(new InputStreamReader(ctx
                .getAssets().open("pubkey.pem")));
        Object obj;
        while ((obj = reader.readObject()) != null) {
             if (obj instanceof RSAPublicKey) {
                pubKey = (RSAPublicKey) obj;
                return pubKey;
            }
        }

And I always get the public key without any problems.

Cipher c = Cipher.getInstance("RSA/NONE/NoPadding", "SC");
c.init(Cipher.DECRYPT_MODE, pubKey);
byte[] result = c.doFinal(data_to_decrypt.getBytes());

And as a result(after converting bytes to string) I get 022c06571c6a263b389fcd93159cb311abb880bddf51b7c916dd1ae...

where php functions returns sd8dsa348acvcx87|00454|OK|15000|CDE and this is a correct output.

Community
  • 1
  • 1
Mike
  • 819
  • 1
  • 8
  • 14
  • 2
    In public key cryptography: you sign and decrypt/decipher using a private key; you verify (a signature) and encrypt/encipher using a public key. Which one are you trying to do? – Bruno Apr 26 '12 at 11:09
  • Like I said I'm trying to decrypt data with public key – Mike Apr 26 '12 at 11:12
  • 4
    You *cannot* decrypt data with a public key, it doesn't make sense (despite the poor naming choice from PHP). "*I'm getting a string encrypted with a private key*": that really doesn't make sense. It's signed at best. Granted, with RSA it will be more or less the same operations (but that wouldn't be the case for DSA). The problem is that the signing of the message will almost certainly have involved a hash, so getting the original message is impossible. – Bruno Apr 26 '12 at 11:15
  • Ok, so let assume that string is signed, how can I verify this ? – Mike Apr 26 '12 at 11:19
  • Do you know more about the signature? Which hash algorithm was used, for example `RSAwithSHA1`? – Bruno Apr 26 '12 at 11:46
  • You need to check how bytes are converted to a string. What is the format of the string you get from PHP? How do you convert it to a byte array to feed to Java? To get the 'correct' output you need to convert the result of `doFinal()` to a string as well. How are you doing it? It seems you are just dumping bytes as hex, that won't give you a readable string. – Nikolay Elenkov Apr 27 '12 at 02:53
  • I think that there is a problem with deryption, because I'm converting hex into readable string, and the result is completely different than php result. – Mike May 02 '12 at 09:16
  • I wouldn't know :) Make sure you are encrypting/decrypting the same byte sequence in Android and PHP. Strings can be tricky, because they depend on encoding. Assuming you get it decrypted correctly, something like this should convert to a Java string, _if_ the output is valid UTF-8/ASCII: `String s = new String(plainText, "UTF-8");` – Nikolay Elenkov May 02 '12 at 09:47

1 Answers1

7

Java has got the Java Cryptography Extension Framework, which is just designed for these things.

BouncyCastle is a Cryptography Provider for this framework. This means, it provides your Java Cryptography Extension with implementations of cryptography algorithms.

You'll find the basic classes for this in the packages java.security and javax.crypto

To decrypt your message with a public key you could try the following:

// Use RSA/NONE/NoPadding as algorithm and BouncyCastle as crypto provider
Cipher asymmetricCipher = Cipher.getInstance("RSA/NONE/NoPadding", "BC");

// asume, that publicKeyBytes contains a byte array representing
// your public key
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);

KeyFactory keyFactory;
keyFactory = KeyFactory.getInstance(publicKeySpec.getFormat());
Key key = keyFactory.generatePublic(publicKeySpec);

// initialize your cipher
asymmetricCipher.init(Cipher.DECRYPT_MODE, key);
// asuming, cipherText is a byte array containing your encrypted message
byte[] plainText = asymmetricCipher.doFinal(cipherText);

Please note, that this example is very basic and lacks several try catch blocks. Also, you should not use an asymmetric cipher without padding as this makes you vulnerable to replay attacks. You may also encounter issues with the key length. In some Java packages, the maximum allowed key length is restricted. This may be solved by using the unlimited strength policy files.

I hope, this helps you in getting started with the Java cryptography.

Francis
  • 198
  • 1
  • 10
  • Thanks for your answer. I had a similiar solution before, it works but I get as a result sth like this: 022c06571c6a263b389fcd93159cb311abb880bddf51b7c916dd1ae... where php function returns decrypted string, where is a problem with that ? – Mike Apr 26 '12 at 12:10
  • The method returns a byte array. Did you convert the result to a String? Also I just recognize, that i did not assign the result of the doFinal method to a variable... going to edit the answer... – Francis Apr 26 '12 at 12:24
  • I convert the result to String, and the output from my previous comment is a String converted from array of bytes – Mike Apr 26 '12 at 12:59
  • I edit my first post, and add some code, maybe it will be helpful in finding the solution. – Mike Apr 26 '12 at 13:43
  • Hi. what gets translated in byte array for the public key? is it the following example below: ---- BEGIN SSH2 PUBLIC KEY ---- Comment: "rsa-key-20130520" AAAAB3NzaC1yc2EAAAABJQAAAIEAsE8aR2CIWuQgkeOsPhHDuGo+Rokr2cT+KS5L sJFbEkB0R3XYXnOT3DU0CFrmHUX1PpcfTOSdxCIfeSXFHCGGWEXm4qx7ptNpm4vP Scuzmlr/fjuQdb7lBQ0+OEP2LKuRHxt5oEVZvq/EvwENS5T2BiVUSvTwXUS6SKCh ERydjXE= ---- END SSH2 PUBLIC KEY ---- – Jono May 20 '13 at 21:29
  • @Francis I have a similar use case, where I would decrypt using a public key on an android device. Can you please help me out, how should I proceed? I do not have any prior experience in cryptography. – arvind.mohan Sep 08 '16 at 16:18
  • 1
    KeyFactory X.509 implemention not found – Ege Kuzubasioglu Jan 16 '18 at 13:28