我需要 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 的密钥?
当您执行
"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:将字节数组转换为十六进制字符串?
(无论如何,请注意,两个垃圾字符串是相同的,因此这应该告诉您字节数组的内容也是相同的。)
messageDigest.reset()
来计算不同数据的哈希值。
这是因为
MessageDigest
旨在与您不是一次性提供的数据块一起使用(通过调用 update(...)
)。所以行为是不断更新内部哈希,直到您通过reset()
重置状态。
基本上在您的代码中,第二个摘要是针对字符串
"ALIBABAALIBABA"
有人可能需要更简单的解释。
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);
}