Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue in Java Character reverseBytes

I'm facing this weird issue. I use the "Character.reverseBytes(char ch)" method for the purpose of encrypting. It works fine, when running inside NetBeans. But Whenever I try to run it outside, it gives weird outputs.

I think the issue is that in two occasions, it use two different encoding methods (or something like that). The following code demonstrate the issue.

import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;

public class Encryptor {

    public static String encode(String in) {
        ArrayList<Character> list = new ArrayList<Character>();
        for (int i = 0; i < in.length(); i++) {
            list.add(Character.reverseBytes(in.charAt(i)));
        }
        return arrayToString(list);
    }

    public static String decode(String in) {
        ArrayList<Character> list = new ArrayList<Character>();
        for (int i = 0; i < in.length(); i++) {
            list.add(Character.reverseBytes(in.charAt(i)));
        }
        return arrayToString(list);
    }

    private static String arrayToString(ArrayList<Character> list) {
        char[] ch = new char[list.size()];
        for (int i = 0; i < list.size(); i++) {
            ch[i] = list.get(i);
        }
        return String.copyValueOf(ch);
    }

    public static void main(String[] args) throws java.io.FileNotFoundException, java.io.IOException {
        String pass = "Password";
        String passEn = encode(pass);
        File file = new File(System.getProperty("user.dir") + "/pass.txt");
        file.createNewFile();
        PrintWriter pr = new PrintWriter(file);
        pr.write(passEn);
        pr.flush();
        passEn = new java.util.Scanner(file).next();
        String passDe = decode(passEn);
        String msg;
        msg = "Initial : " + pass
                + "\nEncrypted : " + passEn
                + "\nDecrypted : " + passDe;
        javax.swing.JOptionPane.showMessageDialog(null, msg);
    }
}

First I save the encrypted word to a file, then try to decode the saved word. This gives two different outputs in the above mentioned two occasions.

Is there any way to fix this?

like image 554
Anubis Avatar asked Mar 15 '26 01:03

Anubis


1 Answers

Fundamentally, Character.reverseBytes is giving you a somewhat arbitrary UTF-16 code unit. There's no guarantee whatsoever that the characters you get afterwards will form a valid string - there could be "half" surrogate pairs, for example, or characters which don't have any specific meaning in Unicode.

More importantly, there's every chance that when you write the "text" to a file and read it back, you'll get different values - particularly as you're not specifying an encoding. There's a very good chance that the default encoding you're using can't support the characters you've ended up with.

Fundamentally, you don't want to do any of this. Encryption of strings should basically take the form of:

  • Encode the string to bytes in a fixed encoding (e.g. UTF-8)
  • Encrypt the binary data (please don't roll your own; Java includes plenty of crypto facilities)
  • Pass the encrypted binary data wherever you need it to. If you must represent the binary data as a string, use something like base64 to make sure you can recover the exact binary data later.

Then to decrypt, you reverse each operation:

  • Retrieve the encrypted binary data, which may involve converting back from base64
  • Perform the appropriate decryption step (binary to binary) based on whatever encryption algorithm you used earlier
  • Convert the result (still bytes) back to a string, using the same encoding you used at the very start

Treating arbitrary binary data as text - which is effectively what Character.reverseBytes is doing, in a very crude way - is a really bad idea.

like image 86
Jon Skeet Avatar answered Mar 17 '26 15:03

Jon Skeet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!