2010-07-08 15 views
45

Je cherche à mettre en œuvre une application en obtenant Twitter authorization via Oauth en Java. La première étape est getting a request token. Voici un Python example pour le moteur de l'application. Pour tester mon code, j'exécute Python et je vérifie la sortie avec Java. Voici un exemple de Python générer un message basé Hash code d'authentification (HMAC):Comment générer un HMAC en Java équivalent à un exemple Python?

#!/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] 

Sortie:

$ ./foo.py 
+3h2gpjf4xcynjCGU5lbdMBwGOc= 

Comment peut-on reproduire ce exemple en Java?

j'ai vu un example of 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 bon. Cependant, les constructeurs SecretKey prennent des octets et un algorithme.

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

Répondre

64

HMACSHA1 semble être le nom de l'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 je l'ai utilisé sun.misc.BASE64Encoder pour une mise en œuvre rapide, mais vous devriez probablement utiliser quelque chose qui ne dépend pas du Sun JRE. The base64-encoder in Commons Codec serait un meilleur choix, par exemple.

+0

bon! Merci. – dfrankow

+0

@Bruno salut, pourriez-vous expliquer comment puis-je "zéro pad" la clé secrète ici si elle est plus petite que la taille de bloc recommandée, ce qui est 160 bits pour SHA1 tnx – Spring

+0

Merci beaucoup, bon exemple. Pour l'enregistrement cependant, je pense que vous changez définitivement votre exemple de code avec le codec Apache Commons ou l'encodeur Guava;) – Brice

20

Une chose mineure mais si vous cherchez un équivalent à hmac (clé, message) alors par défaut la bibliothèque python utilisera l'algorithme MD5, donc vous devez utiliser l'algorithme HmacMD5 en Java. Je mentionne cela parce que j'ai eu ce problème exact et trouvé cette réponse qui a été utile, mais j'ai raté la partie où une méthode de digestion a été transmise à hmac() et est donc descendue dans un trou de lapin. Espérons que cette réponse empêchera les autres de faire de même à l'avenir.

par exemple. en 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()

+3

encodeHexString ne fonctionnait pas sous Android, je devais donc utiliser ceci: return new String (Hex.encodeHex (rawHmac)); – JustinMorris

+0

Traduction excellente de Python à Java. Ça a marché ! –