将散列转换为 Base64 编码:我应该在编码之前将散列存储为字符串还是字节?
Converting a hash to Base64 encoding: Should I be storing the hash as a String or Byte before encoding?
生成 HMAC-SHA1 哈希时出现问题。我将其转换为 Base64 并将其发送到外部系统,由其验证结果。但是,他们正在生成不同的 Base64 编码哈希。据我所知,他们使用 Java Mac (javax.crypto.mac) 来生成哈希,而我使用的是 Google 番石榴编解码器 API .
我检查了几个在线哈希生成器(即 https://www.freeformatter.com/hmac-generator.html),它们生成的哈希与我相同。我尝试了 Apache Commons Codec API,它也产生了相同的结果。然而,这个外部系统正在生成一个不同的 Base64 编码哈希。 Secret/key和message完全一样
事实证明,首先将哈希值转换为字符串,而不是字节,才是问题所在。我首先将散列转换为字符串,然后使用 Base64 进行编码。外部系统首先将哈希值转换为字节,然后使用 Base64 进行编码。我发现的在线生成器似乎首先将哈希转换为字符串,就像我自己一样,这就是为什么我的哈希与在线哈希生成器匹配的原因。
是否有正确的方法来转换哈希值?为了良好的实践,我应该使用 asBytes()、toString() 还是其他东西?
这是使用 Guava 编解码器的代码 API:
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import java.util.Base64;
public class HmacSha1TokenAuth {
public static void main(String[] args) {
String secret = "12345";
String valueToDigest = "TestUser";
byte[] key = secret.getBytes();
Hasher hasher = Hashing.hmacSha1(key).newHasher();
Hasher hasher2 = Hashing.hmacSha1(key).newHasher();
hasher.putBytes(valueToDigest.getBytes());
hasher2.putBytes(valueToDigest.getBytes());
// This is what I used and also found a few online hash generators using the same approach
String hashAsString = hasher.hash().toString();
// This is what the external system used
byte[] hashAsByte = hasher2.hash().asBytes();
String base64AsString = Base64.getEncoder().encodeToString(hashAsString.getBytes());
String base64AsByte = Base64.getEncoder().encodeToString(hashAsByte);
System.out.println("Hash As String: " + hashAsString);
System.out.println("Hash As String(Converted to Bytes): " + hashAsString.getBytes());
System.out.println("Base64 Value of Hash As String: " + base64AsString);
System.out.println("Hash As Byte: " + hashAsByte);
System.out.println("Base64 Value of Hash As Byte: " + base64AsByte);
/*** My Results ***/
// Hash As String: c8094bb1e0896a3f813036bdaeb37b753d9f4f5b
// Hash As String(Converted to Bytes): [B@61443d8f
// Base64 Value of Hash As String: YzgwOTRiYjFlMDg5NmEzZjgxMzAzNmJkYWViMzdiNzUzZDlmNGY1Yg==
/*** External System Results ***/
// Hash As Byte: [B@445b84c0
// Base64 Value of Hash As Byte: yAlLseCJaj+BMDa9rrN7dT2fT1s=
}
}
Base64 编码字节,hasher 产生字节,所以没有理由转换成 String。
我想你看到的例子是关于从字符串变量开始转换 base64。
不同的结果是由于 toString() 或 getBytes() 转换的不同编码。
从 guava 文档中您可以看到 hashcode.toString() 转换为十进制,而 bytes.toString() 依赖于平台(据说是 UTF8)?
https://guava.dev/releases/16.0/api/docs/com/google/common/hash/HashCode.html#toString()
https://guava.dev/releases/16.0/api/docs/com/google/common/hash/HashCode.html#fromString(java.lang.String)
生成 HMAC-SHA1 哈希时出现问题。我将其转换为 Base64 并将其发送到外部系统,由其验证结果。但是,他们正在生成不同的 Base64 编码哈希。据我所知,他们使用 Java Mac (javax.crypto.mac) 来生成哈希,而我使用的是 Google 番石榴编解码器 API .
我检查了几个在线哈希生成器(即 https://www.freeformatter.com/hmac-generator.html),它们生成的哈希与我相同。我尝试了 Apache Commons Codec API,它也产生了相同的结果。然而,这个外部系统正在生成一个不同的 Base64 编码哈希。 Secret/key和message完全一样
事实证明,首先将哈希值转换为字符串,而不是字节,才是问题所在。我首先将散列转换为字符串,然后使用 Base64 进行编码。外部系统首先将哈希值转换为字节,然后使用 Base64 进行编码。我发现的在线生成器似乎首先将哈希转换为字符串,就像我自己一样,这就是为什么我的哈希与在线哈希生成器匹配的原因。
是否有正确的方法来转换哈希值?为了良好的实践,我应该使用 asBytes()、toString() 还是其他东西?
这是使用 Guava 编解码器的代码 API:
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import java.util.Base64;
public class HmacSha1TokenAuth {
public static void main(String[] args) {
String secret = "12345";
String valueToDigest = "TestUser";
byte[] key = secret.getBytes();
Hasher hasher = Hashing.hmacSha1(key).newHasher();
Hasher hasher2 = Hashing.hmacSha1(key).newHasher();
hasher.putBytes(valueToDigest.getBytes());
hasher2.putBytes(valueToDigest.getBytes());
// This is what I used and also found a few online hash generators using the same approach
String hashAsString = hasher.hash().toString();
// This is what the external system used
byte[] hashAsByte = hasher2.hash().asBytes();
String base64AsString = Base64.getEncoder().encodeToString(hashAsString.getBytes());
String base64AsByte = Base64.getEncoder().encodeToString(hashAsByte);
System.out.println("Hash As String: " + hashAsString);
System.out.println("Hash As String(Converted to Bytes): " + hashAsString.getBytes());
System.out.println("Base64 Value of Hash As String: " + base64AsString);
System.out.println("Hash As Byte: " + hashAsByte);
System.out.println("Base64 Value of Hash As Byte: " + base64AsByte);
/*** My Results ***/
// Hash As String: c8094bb1e0896a3f813036bdaeb37b753d9f4f5b
// Hash As String(Converted to Bytes): [B@61443d8f
// Base64 Value of Hash As String: YzgwOTRiYjFlMDg5NmEzZjgxMzAzNmJkYWViMzdiNzUzZDlmNGY1Yg==
/*** External System Results ***/
// Hash As Byte: [B@445b84c0
// Base64 Value of Hash As Byte: yAlLseCJaj+BMDa9rrN7dT2fT1s=
}
}
Base64 编码字节,hasher 产生字节,所以没有理由转换成 String。
我想你看到的例子是关于从字符串变量开始转换 base64。
不同的结果是由于 toString() 或 getBytes() 转换的不同编码。
从 guava 文档中您可以看到 hashcode.toString() 转换为十进制,而 bytes.toString() 依赖于平台(据说是 UTF8)?
https://guava.dev/releases/16.0/api/docs/com/google/common/hash/HashCode.html#toString() https://guava.dev/releases/16.0/api/docs/com/google/common/hash/HashCode.html#fromString(java.lang.String)