我用不同的JRE版本(jre7和jre8)运行转换字节到字符串函数的相同代码得到了不同的结果

时间:2014-07-22 13:57:31

标签: java encoding

我想在我们的产品中将jre7升级到jre8,我收到了一些错误。根本原因是标题说,结果不稳定。

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;


public class Digest {
    /**
     * 
     * @param args
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     */
    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException
    {

        String userName = "superuser";
        String password = "superuser";

        byte[] userNameBytes = userName.getBytes(Charset.forName("GBK"));
        byte[] passwordBytes = password.getBytes(Charset.forName("GBK"));

        byte[] hashedBytes = digest(userNameBytes,passwordBytes);

        System.out.println(Arrays.toString(hashedBytes));

        String tmp = new String(hashedBytes,Charset.forName("GBK"));
        byte[] newHashedBytes = tmp.getBytes(Charset.forName("GBK"));

        System.out.println(Arrays.toString(newHashedBytes));
    }

    public static byte[] digest(byte[] username, byte[] password) throws NoSuchAlgorithmException
    {
        MessageDigest md = MessageDigest.getInstance("SHA");
        md.reset();
        md.update(password);
        md.update(username);
        return md.digest();
    }
}

示例代码是遗留逻辑。我的问题是如何使用解决方法来解决这个问题。

这是我的测试用例:

userNmae密码编码结果

超级用户超级用户UTF-8已通过

超级用户超级用户GBK失败

test62 test62 GBK失败

test62 test62 UTF-8失败

非常感谢。

1 个答案:

答案 0 :(得分:1)

从随机字节到String的转换可能是有损操作(取决于使用的Charset):

String tmp = new String(hashedBytes,Charset.forName("GBK"));

不能用所选CharSet编码的字节值被替换(通常使用'?'),因此当转换回byte []时,您将获得不同的字节数组。

一般来说,从不二进制数据转换为String并使用任何CharSet返回(虽然它可能适用于某些字符集,但是当你想要它时它会带来很大的麻烦传输数据或将其存储在数据库等中。有编码(例如Base64)专门设计为可以使用最小的通用字符集(ASCII)进行反转。

编辑: 这个小测试程序显示并非每个字符都转换为转换中的相同字节(看-128变为63)

import java.nio.charset.Charset;
import java.util.Arrays;

public class CSTest {
    public static void main(String[] argv) {
        Charset cs = Charset.forName("GBK");
        byte[] bytes = new byte[256];
        for (int i=0; i<bytes.length; ++i)
            bytes[i] = (byte) i;
        System.out.println(Arrays.toString(bytes));
        String s = new String(bytes, cs);
        byte[] b2 = s.getBytes(cs);
        System.out.println(Arrays.toString(b2));
    }
}