简体   繁体   中英

When I use DES algorithm I convert byte[] to String and convert this String to byte[], and these two byte[] become different

When I use DES algorithm I convert byte[] to String and convert this String to byte[], and these two byte[] become different:

String str = "lszzz";
String password = "12343213";
byte[] result = Des.encrypt(str.getBytes("utf-8"), password);
String res=new String(result,"utf-8");
System.out.println(result+" dividing line "+res.getBytes());

The running answer is

[B@182decdb dividing line [B@26f0a63f;

Why are these two byte[] different, and how can I can get the same byte[] ?

There are two issues here.

When you concatenate a String with a byte array (which you do twice in result + " dividing line " + res.getBytes() ) you are calling toString() on a byte[] . When you call toString() on any array, you get a value of the form

  [<internal-type-name>@<identity-hashcode>

This does not represent the contents of the array. It represents the identity of the array.

So, in this case, [B@182decdb dividing line [B@26f0a63f only tells you that these are byte arrays and that they are not the same object. It does not explain anything.

The second issue is that you can't treat an arbitrary byte sequence as a UTF-8 encoding. Not every sequence of arbitrary bytes is a valid UTF-8 encoding.

The Des.encrypt call is producing a byte array containing arbitrary binary bytes. When you treat an array containing arbitrary bytes as UTF-8 encoded... and decode it into a String , the process is lossy. When you then take the String value in res and then attempt to encode it as UTF-8, it is unlikely that the bytes you will get will be the same as the bytes that you started with.

The solution depends on what you are trying to do here:

  • If you want to store or transmit binary data as binary:

    • use a BLOB database type
    • use InputStream / OutputStream
    • possibly use DataInputStream / DataOutput or ObjectInputStream / ObjectOutputStream
  • If you are trying to turn the encrypted data into a robust form that can be transmitted through a "text only" channel, use Base64 encoding.

  • If want to pretend that your bytes are text, you could encode them as ISO-8859-1 aka LATIN-1. There is a 1-to-1 correspondence between the 256 codes of ISO-8859-1 and the first 256 Unicode codepoints. So if you pretend that that your binary is ISO-8859-1, you can decode them to a string, encode them back to ISO-8859-1, and get the bytes that you started with. (This is conceptually broken... but it works.)


Now a strict reading of the ISO-8859-1 spec says that the "conceptually broken" approach should not work . However, the following test code demonstrates that it does.

public class Test {
    public static void main (String[] args) throws Exception {
        byte[] data = new byte[256];
        for (int i = 0; i < 256; i++) {
            data[i] = (byte) i;
        }
        String s = new String(data, "ISO-8859-1");
        data = s.getBytes("ISO-8859-1");
        for (int i = 0; i < 256; i++) {
            if (data[i] != ((byte) i)) {
                System.out.println("mismatch: " +  data[i] + " != " +
                   ((byte) i));
            }
        }
    }
}

We can put this down to the way that the ISO-8859-1 encoder / decoder classes are implemented in Java.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM