SHA-256相同的字符串返回不同的byte[]?

问题描述 投票:0回答:3

我需要 SHA-256 作为 AES-256 的密钥。 但我的示例 SHA-256 是:

MessageDigest messageDigest;
messageDigest = MessageDigest.getInstance("SHA-256");

String input = new String("ALIBABA");
messageDigest.update(input.getBytes(Charset.forName("UTF-8")));
byte[] hash = messageDigest.digest();
String hash1s = new String(hash,StandardCharsets.UTF_8);
System.out.println("HASH 1 is "+hash1s);
System.out.println("HASH 1 is "+hash);

String input2 = new String("ALIBABA");
messageDigest.update(input2.getBytes(Charset.forName("UTF-8")));
byte[] hash2 = messageDigest.digest();
String hash2s = new String(hash2,StandardCharsets.UTF_8);
System.out.println("HASH 2 is "+hash2s);
System.out.println("HASH 2 is "+hash2);

返回不相同的值byte[]:

HASH 1 为 V%��%�P�9�P��v�/�/e\BF}�$]

哈希 1 是 [B@629f0666

HASH 2 为 V%��%�P�9�P��v�/�/e\BF}�$]

哈希 2 是 [B@1bc6a36e

如何获得相同的 byte[] 作为 AES-256 的密钥?

java hash
3个回答
6
投票

当您执行

"HASH 1 is " + hash
时,这是
"HASH 1 is " + (hash == null ? "null" : hash.toString())
的简写。您将获得的结果取决于您的
hash
对象如何实现
toString()
。在您的情况下,
hash
属于
byte[]
类型,并且
byte[]
类型不会 not 覆盖
ToString()
,因此会调用
Object.toString()
的默认实现。这个默认实现并不知道你的对象是一个字节数组;它只是发出对象的类型描述符,后跟一个 at 符号('@',),然后是对象的身份哈希代码。

byte[]
的类型描述符是“B[”(不要问我为什么会这样,问Java的创建者。)

身份哈希码是类似于内存地址的十六进制数字。 (它不完全是一个内存地址,但这样想是很有用的。)

由于您的两个字节数组是内存中不同的对象,因此它们位于内存中的不同位置,因此它们具有不同的身份哈希码。这就是为什么他们的

toString()
表示看起来不同。但这并不能告诉你它们的内容是否不同。

为了查看字节数组的内容是否相同,您不必打印它们,只需逐字节比较它们即可。但如果你坚持打印它们,你对

new String( hash2, StandardCharsets.UTF_8 );
的尝试就是错误的,因为它试图将随机字节重新解释为 unicode 字符,这当然会产生有趣的结果。看看这个答案:Java:将字节数组转换为十六进制字符串?

(无论如何,请注意,两个垃圾字符串是相同的,因此这应该告诉您字节数组的内容也是相同的。)


1
投票

您需要在同一对象的连续使用之间调用

messageDigest.reset()
来计算不同数据的哈希值。

这是因为

MessageDigest
旨在与您不是一次性提供的数据块一起使用(通过调用
update(...)
)。所以行为是不断更新内部哈希,直到您通过
reset()
重置状态。

基本上在您的代码中,第二个摘要是针对字符串

"ALIBABAALIBABA"


0
投票

有人可能需要更简单的解释。

String
不仅包含其中的字符信息,还包含一些其他信息。例如,可能是关于它在字符串池中的位置等。该信息也包含在
.toByteArray()
中,因此 2 个相同字符串的结果不同。一个建议是使用
char[]
代替。这是一些代码。

byte[] toBytes(char[] chars) {
  CharBuffer charBuffer = CharBuffer.wrap(chars);
  ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
  byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
          byteBuffer.position(), byteBuffer.limit());
  Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
  return bytes;
}

...

bytesToHex(MessageDigest
             .getInstance("SHA-256")
             .digest(toBytes(charArray)));

...

String bytesToHex(byte[] bytes){
  //any way you want to convert byte array to String
  //for example using apache.commons.codec:
  return Hex.encodeHexString(bytes);
}
© www.soinside.com 2019 - 2024. All rights reserved.