web-dev-qa-db-fra.com

Comment générer un HMAC dans Java équivalent à un Python?

Je cherche à implémenter une application obtenant autorisation Twitter via Oauth en Java. La première étape est obtenir un jeton de demande . Voici un exemple Python pour le moteur d'application.

Pour tester mon code, j'exécute Python et vérifie la sortie avec Java. Voici un exemple de Python générant un code d'authentification de message basé sur le hachage (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]

Production:

$ ./foo.py
+3h2gpjf4xcynjCGU5lbdMBwGOc=

Comment reproduit-on cet exemple en Java?

J'ai vu un exemple de HMAC en 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) {
}

Il utilise javax.crypto.Mac , tout va bien. Cependant, les constructeurs SecretKey prennent des octets et un algorithme.

Quel est l'algorithme dans l'exemple Python? Comment créer une clé secrète Java sans algorithme?)

49
dfrankow

HmacSHA1 semble être le nom d'algorithme dont vous avez besoin:

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));

produit:

+3h2gpjf4xcynjCGU5lbdMBwGOc=

Notez que j'ai utilisé Sun.misc.BASE64Encoder pour une implémentation rapide ici, mais vous devriez probablement utiliser quelque chose qui ne dépend pas du Sun JRE. L'encodeur base64 dans Commons Codec serait un meilleur choix, par exemple.

67
Bruno

Une chose mineure mais si vous recherchez un équivalent à hmac (clé, message), par défaut, la bibliothèque python utilisera l'algorithme MD5, vous devez donc utiliser l'algorithme HmacMD5 en Java.

Je mentionne cela parce que j'avais ce problème exact et j'ai trouvé cette réponse qui était utile, mais j'ai raté la partie où une méthode de résumé a été transmise à hmac () et j'ai donc descendu un terrier de lapin. Espérons que cette réponse empêchera d'autres de faire de même à l'avenir.

par exemple. dans Python REPL

>>> import hmac
>>> hmac.new("keyValueGoesHere", "secretMessageToHash").hexdigest()
'1a7bb3687962c9e26b2d4c2b833b2bf2'

Cela équivaut à la méthode 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);
    }
}

Notez que dans mon exemple, je fais l'équivalent de .hexdigest ()

21
markltbaker