将 HMAC-SHA1 从 node.js 转换为 Java
Converting HMAC-SHA1 from node.js to Java
我的任务是将一些现有的 node.js 代码片段转换为 Java。我想我的路很好,但我现在有点卡住了。这些方法的输出似乎不匹配。
我正在做的是基于查询字符串创建 SHA-1 签名。此查询字符串包含一些与查询相关的数据(与此问题无关)和一个 API 键。
重要
- node.js中的
api_secret
字符串等同于Java中的Config.API_SECRET
。
- 示例查询字符串(这些在 node.js 和 Java 程序中是相等的):
/events?festival=imaginate&pretty=1&size=100&from=0&key=SOME_KEY
实际代码
SHA-1 hmac在nodejs中初始化如下:
const hmac = crypto.createHmac('sha1', api_secret);
SHA-1 mac 在 Java 中初始化如下:
final SecretKeySpec secretKeySpec = new SecretKeySpec(Config.API_SECRET.getBytes("UTF-8"), "HmacSHA1");
final Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(secretKeySpec);
接下来,node.js程序更新hmac(query
参数如上所列):
hmac.update(query, 'ascii');
我在Java中这样复制(query
参数等于node.js query
参数):
hmac.update(query.getBytes("US-ASCII"));
最后,字节串在 node.js 程序中被转换为 SHA-1 散列:
const signature = hmac.digest('hex');
我找不到 Java 的准确翻译,但这是我的尝试,我认为它做的是同样的事情:
字节数组转十六进制函数
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
实际使用
byte[] result = hmac.doFinal();
MessageDigest md = MessageDigest.getInstance("SHA-1");
String sha1Hash = byteArrayToHex(md.digest(result));
然而,这是我感到困惑的地方。 node.js 程序 returns 这个散列:
18cf4fce7bd6163c64d3b2ea8d935b0f16720fe3
但是我的 Java 程序给出了这个散列作为输出:
f65f8738cce89134dc73709e3353d94c83ccf1fb
我不知道哪里出了问题,我真的希望有人能对此有所启发。
我想通了!
原来我做了一个不必要的步骤。
这一行:
byte[] result = mac.doFinal();
已包含签名哈希。我需要将该字节数组转换为十六进制字符串,而不是该字节数组的摘要。
所以工作代码很简单:
byte[] result = mac.doFinal();
return byteArrayToHex(result);
我的任务是将一些现有的 node.js 代码片段转换为 Java。我想我的路很好,但我现在有点卡住了。这些方法的输出似乎不匹配。
我正在做的是基于查询字符串创建 SHA-1 签名。此查询字符串包含一些与查询相关的数据(与此问题无关)和一个 API 键。
重要
- node.js中的
api_secret
字符串等同于Java中的Config.API_SECRET
。 - 示例查询字符串(这些在 node.js 和 Java 程序中是相等的):
/events?festival=imaginate&pretty=1&size=100&from=0&key=SOME_KEY
实际代码
SHA-1 hmac在nodejs中初始化如下:
const hmac = crypto.createHmac('sha1', api_secret);
SHA-1 mac 在 Java 中初始化如下:
final SecretKeySpec secretKeySpec = new SecretKeySpec(Config.API_SECRET.getBytes("UTF-8"), "HmacSHA1");
final Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(secretKeySpec);
接下来,node.js程序更新hmac(query
参数如上所列):
hmac.update(query, 'ascii');
我在Java中这样复制(query
参数等于node.js query
参数):
hmac.update(query.getBytes("US-ASCII"));
最后,字节串在 node.js 程序中被转换为 SHA-1 散列:
const signature = hmac.digest('hex');
我找不到 Java 的准确翻译,但这是我的尝试,我认为它做的是同样的事情:
字节数组转十六进制函数
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
实际使用
byte[] result = hmac.doFinal();
MessageDigest md = MessageDigest.getInstance("SHA-1");
String sha1Hash = byteArrayToHex(md.digest(result));
然而,这是我感到困惑的地方。 node.js 程序 returns 这个散列:
18cf4fce7bd6163c64d3b2ea8d935b0f16720fe3
但是我的 Java 程序给出了这个散列作为输出:
f65f8738cce89134dc73709e3353d94c83ccf1fb
我不知道哪里出了问题,我真的希望有人能对此有所启发。
我想通了!
原来我做了一个不必要的步骤。
这一行:
byte[] result = mac.doFinal();
已包含签名哈希。我需要将该字节数组转换为十六进制字符串,而不是该字节数组的摘要。
所以工作代码很简单:
byte[] result = mac.doFinal();
return byteArrayToHex(result);