2

Here's a string :

String msg="dpbqNszFN2cpmtlzPi3myV9M1ctlkSIQD95ue+T+9rz13T+Pe/aLZ8Pd5geI+PhEM/b0UeRS1cAzKybQsKICTBhh3ke5Jjw6BHWGESJWBnUT54lAlTvzkgOxpQ5stBh2cPPSn3KLyKmXifr8ClbV5s1k3Gy5C7HitA5KLw7hRxAmIGSWQG7PaiLNEVRbgicNfJ7Ic7VIdGA/UA51vK8mpywIR2YQUDPv30ThGq4DuclaJ3X4aVWVj8VYChcfM+82sViVU8HO3DF9CCU4EIADNET503olxiDZBp7WMYmJvWq0KhhZXkLSY3QFmcSMX6IThtdKKCcZp6hu3TtC+7aP7Q==";

So the byte array is

[1] => 100     [2] => 112     [3] => 98     [4] => 113     [5] => 78     [6] => 115     [7] => 122 ..

Which should be decoded to

[ I used PHP base64_encode() for encoding into the above form & base64_decode() for getting this output ]

[1] => 118     [2] => 150     [3] => 234     [4] => 54     [5] => 204     [6] => 197      7] => 55     ...

But the problem I'm facing is that ( In android , Using Base64.decode(String) ) it's getting decoded to :

[118, -106, -22, 54, -52, -59, 55, 103, 41, -102, -39, 115, 62, 45, -26, -55, 95, 76, -43, -53, 101, -111, 34, 16, 15, -34, 110, 123, -28, -2, -10, -68, -11, -35, 63, -113, 123, -10, -117, 103, -61, -35, -26, 7, -120, -8, -8, 68, 51, -10, -12, 81, -28, 82, -43, -64, 51, 43, 38, -48, -80, -94, 2, 76, 24, 97, -34, 71, -71, 38, 60, 58, 4, 117, -122, 17, 34, 86, 6, 117, 19, -25, -119, 64, -107, 59, -13, -110, 3, -79, -91, 14, 108, -76, 24, 118, 112, -13, -46, -97, 114, -117, -56, -87, -105, -119, -6, -4, 10, 86, -43, -26, -51, 100, -36, 108, -71, 11, -79, -30, -76, 14, 74, 47, 14, -31, 71, 16, 38, 32, 100, -106, 64, 110, -49, 106, 34, -51, 17, 84, 91, -126, 39, 13, 124, -98, -56, 115, -75, 72, 116, 96, 63, 80, 14, 117, -68, -81, 38, -89, 44, 8, 71, 102, 16, 80, 51, -17, -33, 68, -31, 26, -82, 3, -71, -55, 90, 39, 117, -8, 105, 85, -107, -113, -59, 88, 10, 23, 31, 51, -17, 54, -79, 88, -107, 83, -63, -50, -36, 49, 125, 8, 37, 56, 16, -128, 3, 52, 68, -7, -45, 122, 37, -58, 32, -39, 6, -98, -42, 49, -119, -119, -67, 106, -76, 42, 24, 89, 94, 66, -46, 99, 116, 5, -103, -60, -116, 95, -94, 19, -122, -41, 74, 40, 39, 25, -89, -88, 110, -35, 59, 66, -5, -74, -113, -19]

As you can see , some characters ( which are not readable though) , are not getting decoded correctly. Edit(2) : bytes are signed in java and unsigned in PHP . Thanks @Jon and @Tony for clearing that idea. But the bug remains in my code.

Edit(1):

Code Segment:

KeyFactory fact = KeyFactory.getInstance("RSA");
BigInteger e=new BigInteger("65537");
BigInteger n=new BigInteger("B7AC0C8F738305F8BDDF93EE25655A70FBDF9F074640C159E36914C227BE1E50A615A25E6706EBA08FB79216F02279420ED4C9DA310778601F6A3233EDADE2FF3775D29E5302C4FCB9E7879D9F3C814AE8F42759148D91CDB23E528241AE2E44F6DE9D4334494C103886B2333D5833EFEABD76205B8F4897BB908E71697A10F6494EBFB0392A831575F64672E0F915A88F46F7FC03E7F94EB56A8A3296840095CB53787EE6E71D4C297108EA5CDD31BD37B1C0A55A8B5FA78F88FC82AEF3C2C80C0FC2CC97A1AEC74ACE44F4AC1B111B727311DA4D1447899A15BA292BCA4E7E864DF55CCB903CD4109874AD475393E7F24FC60E2D7B88E9B4FB57FA54A9B817",16);
RSAPublicKeySpec keySpec=new RSAPublicKeySpec(n,e);
PublicKey pubKey = (PublicKey) fact.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey );
String msg="dpbqNszFN2cpmtlzPi3myV9M1ctlkSIQD95ue+T+9rz13T+Pe/aLZ8Pd5geI+PhEM/b0UeRS1cAzKybQsKICTBhh3ke5Jjw6BHWGESJWBnUT54lAlTvzkgOxpQ5stBh2cPPSn3KLyKmXifr8ClbV5s1k3Gy5C7HitA5KLw7hRxAmIGSWQG7PaiLNEVRbgicNfJ7Ic7VIdGA/UA51vK8mpywIR2YQUDPv30ThGq4DuclaJ3X4aVWVj8VYChcfM+82sViVU8HO3DF9CCU4EIADNET503olxiDZBp7WMYmJvWq0KhhZXkLSY3QFmcSMX6IThtdKKCcZp6hu3TtC+7aP7Q==";
byte[] bytes=msg.getBytes("UTF-8");
byte[] enc_bytes= Base64.decode(bytes,Base64.DEFAULT);
byte[]  dt = cipher.doFinal(enc_bytes);   
String code=new String(dt,"UTF-8");
System.out.println(code);

Cipher decrypted String comes out as ( At the second system.out )

05-10 21:05:27.501: I/System.out(11809): �ќ2`��H&��'Va�x�m��0G�����V�T�����)^����/|���BG,f_r    fK�B7?�a��n������Jl�y�yL���}��΂Ճ������JZj�+�|�-#ș%u�1�z�c�G��nl�5����HELLO HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 H

The Base64_encoded & signed data is "HELLO HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 HI1 H"


[Solved]

Huge thanks to @JonSkeet .

cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); removed all the junk data prefixed to it.

NT_
  • 2,216
  • 1
  • 18
  • 23

3 Answers3

6

All looks fine to me - you just need to remember that bytes are signed in Java. So a value of -106 in Java corresponds to an unsigned value of 150. Once you bear that in mind, I think you'll see that all the values in PHP correspond to the values in Java.

Note that you ought to distinguish between bytes and characters. So when you say:

As you can see , some characters ( which are not readable though) , are not getting decoded correctly.

You actually mean some bytes... and there's no such concept as a "readable" byte.

EDIT: I see no sign that you've actually decrypted the data at all.

You're converting the still encrypted result of the base64 decoding into text using the platform default encoding:

String tmpr=new String(baser);

You shouldn't be doing that - you should be using baser as the cipher-text to decrypt.

It's not at all clear where the tmp value you're passing to doFinal comes from at all...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • What i meant was, the Base64 encoded data is not a readable string. It is an encrypted data. – NT_ May 10 '12 at 15:32
  • @ngen: If the problem is decryption (as you've added in a comment later) then that suggests the problem is with the encryption or decryption code, which you haven't shown us. The base64 part seems to be fine here. But it's important to understand that the decoded base64 isn't a *string* at all, readable or unreadable - it's just bytes. – Jon Skeet May 10 '12 at 15:34
  • Perhaps he means it was encrypted, then BASE-64'd? – Tony Ennis May 10 '12 at 15:35
  • @TonyEnnis: Yes, having seen another comment that makes sense. But it's still a mistake to talk about the decoded data as a "string" at all. – Jon Skeet May 10 '12 at 15:36
  • @Jon , I've edited the question again. I've been at this for some hours in and out. I have a string which is encrypted ( RSA ) and Base64'd the encrypted string ( Which is not readable by humans :-) ) .And then i passed it into the Android . But the bug occurs there. – NT_ May 10 '12 at 15:38
  • @ngen: You're printing out something totally meaningless at the moment, and your code doesn't appear to be using the decoded base64 value for anything else. See my edit. – Jon Skeet May 10 '12 at 15:54
  • @JonSkeet , I'm Sorry for being an idiot. By hurrying up to add the code , I tried to make it readable by editing it out of IDE. The original code has been added . Sorry again. – NT_ May 10 '12 at 15:58
  • @ngen: Okay, so what encoding did you use in PHP before encryption? And how are you doing the encryption in the PHP code? And how are you setting up the decryption in the Java code? Just about the only bit of the pipeline we know *is* working is the base64 part... – Jon Skeet May 10 '12 at 16:04
  • @JonSkeet Thanks for being patient in listening to this. I'm using RSA-SHA1 . The data is in UTF-8 . It is working as you can see from that `println()` . The problem is that, the output data after the decryption its having garbage data. I had two assumptions regarding that. 1) Cipher is having garbage data in its buffer. 2) The byte[] arrays signed nature . And the Android ( Encrypt) => PHP ( Decrypt) is working perfectly. Data is same on both sides. But when it's done in the opposite direction, data is mangled with random characters in the beginning. – NT_ May 10 '12 at 16:09
  • @ngen: Hang on - I thought you said you were *encrypting*. RSA-SHA1 is just a *signature*, not encryption. You can't decrypt a signature - it doesn't work that way. Please show *all* the code you're using, because at the moment it's not making much sense. – Jon Skeet May 10 '12 at 16:10
  • @JonSkeet I'm not signing actually, I'm encryting the data at one end and decrypting it out of the encrypted code. There is no signature and signature verification. – NT_ May 10 '12 at 16:13
  • @JonSkeet I'm very new (24 hours) to encrypting hence the confused terminologies used by me. And i hit this bug some hours back. I can clean the output string somehow but i would like to know what's making it unclean in the first place. Hence spending time on it. – NT_ May 10 '12 at 16:15
  • @ngen: Okay, I may have been confused by the SHA-1 part. What does your similar code for encryption (that works) do? – Jon Skeet May 10 '12 at 16:18
  • @ngen: No, that doesn't work for my way of working. But I would take base64 and PHP out of the equation completely: if you encrypt *and directly decrypt* in Java, does *that* work? I suspect you should actually try that and ask a separate question, as the basis of this question is base64, which I believe to be irrelevant here. – Jon Skeet May 10 '12 at 16:20
  • @JonSkeet Okay. Thank you. I was worried whether it will be okay to make it a separate question. Thanks. – NT_ May 10 '12 at 16:22
  • @ngen: Oh absolutely - take base64 out of the equation, and produce as complete a question as you can :) I'll try to take a look when I get a chance. – Jon Skeet May 10 '12 at 16:25
  • @JonSkeet Unfortunately, The bug i believe is due to the Base64 itself, But that of PHP , I think. But i am not sure where to start debugging from. It **is** working : 1) Android (Encrypt) - Android(Decrypt) [I tried both with and without Base64 ] . 2)Android(Encrypt)-PHP(Decrypt) 3) PHP ( Encrypt) - PHP (Decrypt) . However on doing PHP(Encrypt)-Android(Decrypt) => It's producing unwanted characters prefixed to the decrypted string – NT_ May 10 '12 at 16:58
  • @ngen: Can you do PHP encrypt/base64-encode/base64-decode/decrypt? – Jon Skeet May 10 '12 at 17:12
  • @JonSkeet Yes, all using Base Encoding. All combination works , Except Android(Decrypt) !. Right now, I was trying out this: (1) Base64'd the data (2) Encrypted it (3) Base64'd encrypted string (4) Passed it to android (5) Base_Decoded ( Works Fine) (6) Decrypted using Cipher. ( Mangled!!! Again! ). I can't Base_decode this data again since it's mangled. Is it due to the buggy bouncy castle?. Since i was just decrypting a Base64'd data it wasn't due to the original string's encoding. In short, Cipher.doFinal() is prefixing unwanted chars. But it's not doing it on Android-Encrypted data. – NT_ May 10 '12 at 17:20
  • @ngen: That indicates that it isn't base64. You've got the same encrypted data on both sides (output of 2 and output of 5), but decryption fails. – Jon Skeet May 10 '12 at 17:24
  • @JonSkeet Exactly. That's what i wanted to convey. I understood that already. So the decrypting is failing but **only** on the data i'm encrypting from PHP. [Android->Android works] . I'm using PHPSecLib BTW. But if that library was buggy, PHP->PHP and Android->PHP wouldn't work. Right?. Any ideas? – NT_ May 10 '12 at 17:27
  • @ngen: It may well just be the way that you're configuring the keys. – Jon Skeet May 10 '12 at 17:45
  • @JonSkeet I am not sure of that. If it was that case , then it wouldn't decrypt the encrypted string at all. Right?. It is decrypting in my case. Full string is there!. Just that it's prefixed with a meaningless list of characters. :-( . – NT_ May 10 '12 at 17:55
  • 1
    @ngen: Ah - in that case it may well just be the CBC/padding modes (or initialization vector etc) involved. You should investigate that. – Jon Skeet May 10 '12 at 18:00
  • !!!! @JonSkeet , You saved me. I did think about Padding , But i guess i became overly conscious about the encoding and how it was working the other way around. So i was playing around that alone. `cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");` . And I'm done. :D . Sorry for all the trouble. But still i do not understand how all the other permutations were working except this one without forcing the PKCS1 . – NT_ May 10 '12 at 18:06
1

Your issue is one of sign. The first sample 'the should' is treating the output bytes as 8-bit unsigned. The Android version is treating them as signed bytes.

Is your code actually failing?

Edit

cipher.final() seems to be designed to finish decryption. Did you call cipher.update() first? See the example here, and look for update(...) stackoverflow.com/questions/3150830/android-encryption

Here's the Android Cipher documentation, for your convenience.

Tony Ennis
  • 12,000
  • 7
  • 52
  • 73
  • Yes, It is failing when the 'signed' byte array goes to cipher decryption. – NT_ May 10 '12 at 15:32
  • What input type does the decryption expect? If it expects an array of unsigned, you may have to convert the byte array to an unsigned. – Tony Ennis May 10 '12 at 15:37
  • It's the Android's `Cipher.doFinal(byte[])` . It is expecting bytes . But it's failing to decrypt the data and is adding a lot of junk in front of the actual data. – NT_ May 10 '12 at 15:40
  • I think it is Cipher.doFinal(byte[]) – Tony Ennis May 10 '12 at 15:43
  • I'm totally confused about the bug , I'm sorry . I'll be more clear & specific. Cipher.doFinal() accepts byte array and i'm trying it correctly, it's even decrypting. But the issue like i have mentioned in the edit is that, its producing Illegible string . Which I'm assuming now , is due to signed/unsigned bytes ?. Java supports only signed bytes?. – NT_ May 10 '12 at 15:46
  • Wait, how did you encrypt the data to begin with? – Tony Ennis May 10 '12 at 15:47
  • RSA-SHA1 format . In PHP. It's working from Android(Encrypt) => PHP(Decrypt). But on the other direction , This is happening. Lots of irrelevant characters are coming in the decrypted string. – NT_ May 10 '12 at 15:50
  • `cipher.final()` seems to be designed to _finish_ decryption. Did you call `cipher.update()` first? See the example here, and look for `update(...)` http://stackoverflow.com/questions/3150830/android-encryption – Tony Ennis May 10 '12 at 16:31
  • The way i understood about Cipher's working is that it's multipart . Update() for adding more bytes so that you can effectively continue decrypting part by part. doFinal() does the same job , except that it finalizes Cipher's work. Thanks for suggestion. But unfortunately it's not the part that's causing the issue. :(. `cipher.update(enc_bytes); byte[] dt = cipher.doFinal(); String code=new String(dt,"UTF-8"); System.out.println(code);` I've tried this code. And no, it doesn't work. Still gives junk characters. – NT_ May 10 '12 at 16:38
  • `doFinal(byte[] input) ` Encrypts or decrypts data **in a single-part operation**, *or* **finishes** a multiple-part operation. – NT_ May 10 '12 at 16:46
-2

Try this on your byte array

byte[] bytes = Base64.decode(data, Base64.DEFAULT);
String string = new String(bytes, "UTF-8");
allthenutsandbolts
  • 1,513
  • 1
  • 13
  • 34
  • 1
    Absolutely not. Unless you have any evidence that this is *actually* meant to be UTF-8-encoded text (I see no such evidence in the question), you shouldn't be trying to create text out of it. – Jon Skeet May 10 '12 at 15:28
  • The answer is totally irrelevant. – NT_ May 10 '12 at 15:29
  • My suggestion was based on the previous question at that particular time there was no code added which said that the data was being encrypted. There have been 2 edits to the question since I gave answers. I don't try creating text for the sake of creating it. People ought to read their code segments carefully before hitting the send button. – allthenutsandbolts May 10 '12 at 19:41