Как создать HMAC в Java, эквивалентном примеру Python?

Я смотрю на реализацию приложения получения авторизация Twitter через Oauth в Java. Первый шаг -получение токена запроса. Вот это пример Python для App engine.

чтобы проверить мой код, я запускаю Python и проверяю вывод с помощью Java. Вот пример Python, генерирующего код аутентификации сообщения на основе хэша (HMAC):

#!/usr/bin/python

from hashlib import sha1
from hmac import new as hmac

key = "qnscAdgRlkIhAUPY44oiexBKtQbGY0orf7OV1I50"
message = "foo"

print "%s" % hmac(key, message, sha1).digest().encode('base64')[:-1]

выход:

$ ./foo.py
+3h2gpjf4xcynjCGU5lbdMBwGOc=

как это повторить пример в Java?

Я видел пример HMAC в Java:

try {
    // Generate a key for the HMAC-MD5 keyed-hashing algorithm; see RFC 2104
    // In practice, you would save this key.
    KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
    SecretKey key = keyGen.generateKey();

    // Create a MAC object using HMAC-MD5 and initialize with key
    Mac mac = Mac.getInstance(key.getAlgorithm());
    mac.init(key);

    String str = "This message will be digested";

    // Encode the string into bytes using utf-8 and digest it
    byte[] utf8 = str.getBytes("UTF8");
    byte[] digest = mac.doFinal(utf8);

    // If desired, convert the digest into a string
    String digestB64 = new sun.misc.BASE64Encoder().encode(digest);
} catch (InvalidKeyException e) {
} catch (NoSuchAlgorithmException e) {
} catch (UnsupportedEncodingException e) {
}

Он использует javax.криптографический.Мак!--5-->, все хорошо. Однако SecretKey конструкторы берут байты и алгоритм.

каков алгоритм в примере Python? Как можно создать секретный ключ Java без алгоритма?

2 ответов


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. кодер base64 в кодеке Commons было бы лучшим выбором, например.


незначительная вещь, но если вы ищете эквивалент hmac (ключ,сообщение), то по умолчанию библиотека python будет использовать алгоритм MD5, поэтому вам нужно использовать алгоритм HmacMD5 в Java.

я упоминаю об этом, потому что у меня была эта точная проблема и нашел этот ответ, который был полезен, но я пропустил часть, где метод дайджеста был передан в hmac() и, таким образом, спустился в кроличью нору. Надеюсь, этот ответ помешает другим сделать то же самое в будущее.

например, в 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()