2010-07-08 19 views
45

Tôi đang xem xét việc triển khai ứng dụng nhận được Twitter authorization via Oauth trong Java. Bước đầu tiên là getting a request token. Đây là Python example cho công cụ ứng dụng.Làm thế nào để tạo ra một HMAC trong Java tương đương với một ví dụ Python?

Để kiểm tra mã của tôi, tôi đang chạy Python và kiểm tra đầu ra bằng Java. Dưới đây là một ví dụ về Python tạo ra một tin nhắn Hash-Based Authentication Code (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] 

Output:

$ ./foo.py 
+3h2gpjf4xcynjCGU5lbdMBwGOc= 

Làm thế nào để một lặp lại ví dụ này trong Java?

Tôi đã nhìn thấy một example of HMAC trong 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) { 
} 

Nó sử dụng javax.crypto.Mac, tất cả đều tốt. Tuy nhiên, các nhà xây dựng SecretKey mất byte và một thuật toán.

Thuật toán trong ví dụ Python là gì? Làm cách nào để tạo khóa bí mật Java mà không có thuật toán?

Trả lời

64

HMACSHA1 có vẻ là tên thuật toán bạn cần:

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

sản xuất:

+3h2gpjf4xcynjCGU5lbdMBwGOc= 

Lưu ý rằng tôi đã sử dụng sun.misc.BASE64Encoder cho một thực hiện nhanh chóng ở đây, nhưng có lẽ bạn nên sử dụng một cái gì đó không phụ thuộc vào Sun JRE. Ví dụ: The base64-encoder in Commons Codec sẽ là một lựa chọn tốt hơn.

+0

một tốt! cảm ơn. – dfrankow

+0

@Bruno hi, bạn có thể giải thích làm thế nào tôi có thể "zero pad" khóa bí mật ở đây nếu nó nhỏ hơn kích thước khối được đề xuất, là 160 bit cho SHA1 tnx – Spring

+0

Cảm ơn bạn rất nhiều, ví dụ tuyệt vời. Mặc dù vậy, đối với bản ghi, tôi nghĩ bạn chắc chắn thay đổi mẫu mã của bạn bằng Apache Commons Codec hoặc bộ mã hóa Guava;) – Brice

20

Một điều nhỏ nhưng nếu bạn đang tìm kiếm một tương đương với hmac (khóa, tin nhắn) thì theo mặc định thư viện python sẽ sử dụng thuật toán MD5, vì vậy bạn cần sử dụng thuật toán HmacMD5 trong Java.

Tôi đề cập đến điều này bởi vì tôi đã có vấn đề chính xác này và tìm thấy câu trả lời này hữu ích, nhưng tôi đã bỏ lỡ một phần mà phương pháp thông báo đã được chuyển vào hmac() và do đó đi xuống một lỗ thỏ. Hy vọng câu trả lời này sẽ ngăn người khác làm tương tự trong tương lai.

ví dụ: bằng Python REPL

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

này tương đương với phương pháp 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); 
    } 
} 

Lưu ý rằng trong ví dụ của tôi, tôi đang làm tương đương với .hexdigest()

+3

encodeHexString không hoạt động trên Android vì vậy tôi đã phải sử dụng nó thay vì: trả về String mới (Hex.encodeHex (rawHmac)); – JustinMorris

+0

Xuất sắc Python sang bản dịch Java. Nó đã làm việc ! –

Các vấn đề liên quan