0

Good evening!

In my android app the smartphones load a AES encrypted String from my server and store it in a variable. After that process the variable and a key are pass to a method which decrypt the string. My mistake is that german umlauts (ä, ü, ö) aren't correct decoded. All umlauts displayed as question marks with black background...

My Code:

public static String decrypt(String input, String key) {

    byte[] output = null;
    String newString = "";

    try {

        SecretKeySpec skey = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, skey);
        output = cipher.doFinal(Base64.decode(input, Base64.DEFAULT));
        newString = new String(output);

    } catch(Exception e) {}

    return newString;
}

The code works perfectly - only umlauts displayed not correctly, an example is that (should be "ö-ä-ü"):

umlauts bug

How can I set the encoding of the decrypted String? In my iOS app I use ASCII to encoding the decoded downloaded String. That works perfectly! Android and iOS get the String from the same Server on the same way - so I think the problem is the local Code above.

I hope you can help me with my problem... Thanks!

  • 2
    Specify the charset when you call `String.getBytes()` and `new String(byte[])`. Might not be the immediate problem here, but it will avoid problems down the road. – Andy Turner Sep 24 '16 at 18:48
  • (As well as not swallowing the exception; and not catching `Exception` in the first place, but rather catching the specific exceptions thrown) – Andy Turner Sep 24 '16 at 18:49
  • Thank you! Do you mean `String.getBytes("UTF-8")` and `new String(byte[], "UTF-8")`? I've added both to test - no changes... Thanks for your hint in your second comment! –  Sep 24 '16 at 18:55
  • 1
    @AndyTurner You are right of course wrt the exception handling, but character encoding / decoding is silent by default (which, in my opinion, is the wrong default of course, but yeah, we'll be stuck on it). Anyway, to handle crypto exceptions, take a look [here](http://stackoverflow.com/questions/15709421/handling-crypto-exceptions). I don't mind upvotes at all :) – Maarten Bodewes Sep 24 '16 at 18:55
  • @Waldi Then the *encoded* text is not UTF-8. This is not an encryption problem. Try e.g. [`StandardCharsets.ISO_8859_1`](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/StandardCharsets.html#ISO_8859_1) for the Latin character set. – Maarten Bodewes Sep 24 '16 at 18:57
  • Thank you! I will test it. Do you mean I should test all encoding Charsets in `new String(...)` until the bug doesn't exist anymore? –  Sep 24 '16 at 19:00
  • @Waldi Yep, well, the 8 bit character sets anyway. UTF-16 doesn't make sense as your other text would be garbled as well. Java contains more character sets, by the way, [here](https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html) are "a few" more :P. Try at least windows-1252 and code page 437. Oh and **Mac Roman** may somehow make sense. – Maarten Bodewes Sep 24 '16 at 19:02
  • Oh, uh, Android... I guess you need to look [here](https://developer.android.com/reference/java/nio/charset/Charset.html#availableCharsets()) – Maarten Bodewes Sep 24 '16 at 19:09
  • Nice - `newString = new String(output, "ISO8859-1");` do the job! Thank you for your help :-) –  Sep 24 '16 at 20:54

1 Answers1

0

There is no text but encoded text.

It seems like you are guessing at the character set and encoding—That's no way to communicate.

To recover the text, you need to reverse the original process applied to it with the parameters associated with each step.

For explanation, assume that the server is taking text from a Java String and sending it to you securely.

  1. String uses the Unicode character set (specifically, Unicode's UTF-16 encoding).
  2. Get the bytes for the String, using some specific encoding, say ISO8859-1. (UTF-8 could be better because it is also an encoding for the Unicode character set, whereas ISO8859-1 has a lot fewer characters.) As @Andy points out, exceptions are your friends here.
  3. Encrypt the bytes with a specific key. The key is a sequence of bytes, so, if you are generating this from a string, you have to use a specific encoding.
  4. Encode the encrypted bytes with Base64, producing a Java String (again, UTF-16) with a subset of characters so reduced that it can be re-encoded in just about any character encoding and placed in just about any context such as SMTP, XML, or HTML without being misinterpreted or making it invalid.
  5. Transmit the string using a specific encoding. An HTTP header and/or HTML charset value is usually used to communicate which encoding.

To receive the text, you have to get:

  • the bytes,
  • the encoding from step 5,
  • the key from step 3,
  • the encoding from step 3 and
  • the encoding from step 2.

Then you can reverse all of the steps. Per your comments, you discovered you weren't using the encoding from step 2. You also need to use the encoding from step 3.

Tom Blodget
  • 20,260
  • 3
  • 39
  • 72