2010-07-08 4 views
45

Я ищу реализацию приложения, получающего Twitter authorization via Oauth в Java. Первым шагом является getting a request token. Ниже приведен пример Python example для приложения.Как создать HMAC в Java, эквивалентном примеру Python?

Чтобы проверить свой код, я запускаю 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?

Я видел example of 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.crypto.Mac, все хорошо. Однако конструкторы SecretKey принимают байты и алгоритм.

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

ответ

64

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. Например, The base64-encoder in Commons Codec был бы лучшим выбором.

+0

хороший! Благодарю. – dfrankow

+0

@Bruno привет, не могли бы вы объяснить, как я могу «нулевую прокладку» здесь секретного ключа, если он меньше рекомендуемого размера блока, то есть 160 бит для SHA1 tnx – Spring

+0

Большое вам спасибо, отличный пример. Для записи, однако, я думаю, что вы определенно измените свой пример кода с помощью кодека Apache Commons или кодека Guava;) – Brice

20

Небольшая вещь, но если вы ищете эквивалент hmac (key, message), то по умолчанию библиотека 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()

+3

encodeHexString не работает на Android, поэтому мне пришлось использовать это вместо: return new String (Hex.encodeHex (rawHmac)); – JustinMorris

+0

Отличный перевод Python в Java. Это сработало ! –