如何在Java中生成与Python示例等效的HMAC?

如何在Java中生成与Python示例等效的HMAC?,java,oauth,sha1,hmac,cryptoapi,Java,Oauth,Sha1,Hmac,Cryptoapi,我正在考虑用Java实现一个应用程序。第一步是。这里是一个应用程序引擎 为了测试我的代码,我运行Python并用Java检查输出。下面是Python生成基于哈希的消息身份验证代码(HMAC)的示例: 输出: $ ./foo.py +3h2gpjf4xcynjCGU5lbdMBwGOc= 如何在Java中复制此示例 我在Java中看到了一个: 它使用,一切都好。但是,构造函数采用字节和算法 Python示例中的算法是什么?没有算法,如何创建Java密钥?HmacSHA1似乎是您需要的算法名称:

我正在考虑用Java实现一个应用程序。第一步是。这里是一个应用程序引擎

为了测试我的代码,我运行Python并用Java检查输出。下面是Python生成基于哈希的消息身份验证代码(HMAC)的示例:

输出:

$ ./foo.py
+3h2gpjf4xcynjCGU5lbdMBwGOc=
如何在Java中复制此示例

我在Java中看到了一个:

它使用,一切都好。但是,构造函数采用字节和算法


Python示例中的算法是什么?没有算法,如何创建Java密钥?

HmacSHA1似乎是您需要的算法名称:

SecretKeySpec keySpec = new SecretKeySpec(
        "qnscAdgRlkIhAUPY44oiexBKtQbGY0orf7OV1I50".getBytes(),
        "HmacSHA1");

Mac mac = Mac.getInstance("HmacSHA1");
mac.init(keySpec);
byte[] result = mac.doFinal("foo".getBytes());

BASE64Encoder encoder = new BASE64Encoder();
System.out.println(encoder.encode(result));
产生:

+3h2gpjf4xcynjCGU5lbdMBwGOc=

注意,我在这里使用了
sun.misc.BASE64Encoder
来快速实现,但是您可能应该使用不依赖于sun JRE的东西。例如,这将是一个更好的选择。

这是一件小事,但如果您正在寻找与hmac(键、消息)等效的,那么默认情况下python库将使用MD5算法,因此您需要在Java中使用HmacMD5算法

我之所以提到这一点,是因为我遇到了一个确切的问题,并且找到了这个答案,这个答案很有帮助,但我错过了将摘要方法传递给hmac()的部分,因此陷入了困境。希望这个答案能阻止其他人将来也这样做

e、 g.在Python REPL中

>>> import hmac
>>> hmac.new("keyValueGoesHere", "secretMessageToHash").hexdigest()
'1a7bb3687962c9e26b2d4c2b833b2bf2'
这相当于Java方法:

import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class HashingUtility {
    public static String HMAC_MD5_encode(String key, String message) throws Exception {

        SecretKeySpec keySpec = new SecretKeySpec(
                key.getBytes(),
                "HmacMD5");

        Mac mac = Mac.getInstance("HmacMD5");
        mac.init(keySpec);
        byte[] rawHmac = mac.doFinal(message.getBytes());

        return Hex.encodeHexString(rawHmac);
    }
}

请注意,在我的示例中,我正在执行与.hexdigest()等效的操作。

@Bruno嗨,请您解释一下,如果密钥小于推荐的块大小(SHA1 TNX为160位),我如何在此处“置零”密钥非常感谢您,非常好的示例。不过,作为记录,我认为您肯定会使用ApacheCommons编解码器或Guava编码器更改代码示例;)<代码>“字符串”。getBytes()看起来很奇怪。它将返回与平台相关的字节(指定编码!),并且不会覆盖整个字节值范围。我希望使用编码(如bae64、base32或hexdigest)来表示密钥的字符串,或者使用密码增强(PBKDF)来返回纯均匀分布的字节。(当然,这也是spec/python示例的问题)。@eckes非常好的一点,我几乎总是自己使用
getBytes(“UTF-8”)
。正如您所说,Python示例中的字符串不是以
u“…”
开头的,我们不知道它是否是Python 3。关于base64编码,在2016年,我们通过
string java.xml.bind.DatatypeConverter.printBase64Binary(byte[]val)来实现
encodeHexString在Android上不起作用,所以我不得不使用它:返回新字符串(Hex.encodeHex(rawHmac));
>>> import hmac
>>> hmac.new("keyValueGoesHere", "secretMessageToHash").hexdigest()
'1a7bb3687962c9e26b2d4c2b833b2bf2'
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class HashingUtility {
    public static String HMAC_MD5_encode(String key, String message) throws Exception {

        SecretKeySpec keySpec = new SecretKeySpec(
                key.getBytes(),
                "HmacMD5");

        Mac mac = Mac.getInstance("HmacMD5");
        mac.init(keySpec);
        byte[] rawHmac = mac.doFinal(message.getBytes());

        return Hex.encodeHexString(rawHmac);
    }
}