Reputation: 191
I need SHA-256 to be my key for AES-256. But my example SHA-256 is:
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);
Return not a same value byte[]:
HASH 1 is V%��%�P�9�P��v�/�/e\BF}�$]
HASH 1 is [B@629f0666
HASH 2 is V%��%�P�9�P��v�/�/e\BF}�$]
HASH 2 is [B@1bc6a36e
How do I get same byte[] to be key for AES-256?
Upvotes: 1
Views: 2798
Reputation: 61984
When you do "HASH 1 is " + hash
this is shorthand for "HASH 1 is " + (hash == null ? "null" : hash.toString())
. The results that you will get depend on how your hash
object implements toString()
. In your case, hash
is of type byte[]
, and the byte[]
type does not override ToString()
, so the default implementation of Object.toString()
is invoked. This default implementation has no idea that your object is an array of bytes; it just emits the type descriptor of the object, followed by an at-sign, ('@',) followed by the identity hash code of the object.
The type descriptor of byte[]
is "B[" (don't ask me why it is so, ask the creators of Java.)
The identity hash code is a hex number akin to a memory address. (It is not exactly a memory address, but it is useful to think of it that way.)
Since your two byte arrays are distinct objects in memory, they live in different locations in memory, so they have different identity hash codes. That's why their toString()
representations look different. But this tells you nothing as to whether their contents are different.
In order to see that the contents of your byte arrays are identical, you don't have to print them, you can simply compare them byte by byte. But if you insist on printing them, your attempt with new String( hash2, StandardCharsets.UTF_8 );
is mistaken, because it is trying to reinterpret random bytes as unicode characters, which of course gives funny results. Take a look at this answer: Java: convert a byte array to a hex string?
(And in any case, note that the two strings of garbage are identical, so this should be telling you that the contents of your byte arrays are identical, too.)
Upvotes: 6
Reputation: 179
Someone may need a more simple explanation. String
contains info not only for chars in it, but also some other info. May be for example about it's position in String pool etc. That info also included in .toByteArray()
so results differ for 2 same strings. A piece of advice is to use char[]
instead. Here is some code.
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);
}
Upvotes: 0
Reputation: 133577
You need to call messageDigest.reset()
between successive utilizations of the same object to compute hash for different data.
This because MessageDigest
is meant to be used with chunks of data that you feed to it not all at once (by calling update(...)
). So the behavior is to keep updating the internal hash until you reset the state through reset()
.
Basically in your code the second digest is for the string "ALIBABAALIBABA"
Upvotes: 1