2012-10-22 29 views
5

HMAC-SHA1 Java kodunu http://tools.ietf.org/html/rfc6238'dan ödünç aldım ve bilinen çıkışlı bilinen bir anahtar/mesaj çiftini kullanmak için biraz kodlamaya adapte ettim.Python HMAC-SHA1 vs Java HMAC-SHA1 farklı sonuçlar

Daha sonra sonuçları doğrulamak için Python'da aynı kodu yazmaya çalıştım, ancak Python ve Java'da farklı değerler alıyorum.

Java değerlerinin iyi olduğu bilinir.

Java kodu:

import java.lang.reflect.UndeclaredThrowableException; 
import java.security.GeneralSecurityException; 
import java.text.DateFormat; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import javax.crypto.Mac; 
import javax.crypto.spec.SecretKeySpec; 
import java.math.BigInteger; 
import java.util.TimeZone; 
import java.util.Arrays; 


public class make_hmac { 

    private make_hmac() {} 


    private static byte[] hmac_sha(String crypto, byte[] keyBytes, 
      byte[] text){ 
     try { 
      System.out.println("Key is..." + bytesToHex(keyBytes) + "\n"); 
      Mac hmac; 
      hmac = Mac.getInstance(crypto); 
      SecretKeySpec macKey = 
       new SecretKeySpec(keyBytes, "RAW"); 
      hmac.init(macKey); 
      return hmac.doFinal(text); 
     } catch (GeneralSecurityException gse) { 
      throw new UndeclaredThrowableException(gse); 
     } 
    } 


    private static byte[] hexStr2Bytes(String hex){ 
     // Adding one byte to get the right conversion 
     // Values starting with "0" can be converted 
     byte[] bArray = new BigInteger("10" + hex,16).toByteArray(); 

     // Copy all the REAL bytes, not the "first" 
     byte[] ret = new byte[bArray.length - 1]; 
     for (int i = 0; i < ret.length; i++) 
      ret[i] = bArray[i+1]; 
     return ret; 
    } 

    private static final int[] DIGITS_POWER 
    // 0 1 2 3 4  5  6  7  8 
    = {1,10,100,1000,10000,100000,1000000,10000000,100000000 }; 


    public static String generateTOTP(String key, 
      String time, 
      String returnDigits, 
      String crypto){ 
     int codeDigits = Integer.decode(returnDigits).intValue(); 
     String result = null; 

     // Using the counter 
     // First 8 bytes are for the movingFactor 
     // Compliant with base RFC 4226 (HOTP) 
     while (time.length() < 16) 
      time = "0" + time; 

     // Get the HEX in a Byte[] 
     byte[] msg = hexStr2Bytes(time); 
     byte[] k = hexStr2Bytes(key); 
     byte[] hash = hmac_sha(crypto, k, msg); 
     System.out.println("I hashed key " + bytesToHex(k) + " against message " + bytesToHex(msg) + " and got...\n"); 
     System.out.println("HASHED: " + bytesToHex(hash) + "\n"); 

     // put selected bytes into result int 
     int offset = hash[hash.length - 1] & 0xf; 

     int binary = 
      ((hash[offset] & 0x7f) << 24) | 
      ((hash[offset + 1] & 0xff) << 16) | 
      ((hash[offset + 2] & 0xff) << 8) | 
      (hash[offset + 3] & 0xff); 

     int otp = binary % DIGITS_POWER[codeDigits]; 

     result = Integer.toString(otp); 
     while (result.length() < codeDigits) { 
      result = "0" + result; 
     } 
     return result; 
    } 

    public static String bytesToHex(byte[] bytes) { 
     final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 
     char[] hexChars = new char[bytes.length * 2]; 
     int v; 
     for (int j = 0; j < bytes.length; j++) { 
      v = bytes[j] & 0xFF; 
      hexChars[j * 2] = hexArray[v >>> 4]; 
      hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 
     } 
     return new String(hexChars); 
    } 

    public static void main(String[] args) { 
     // Seed for HMAC-SHA1 - 20 bytes 
     String seed = "3132333435363738393031323334353637383930"; 
     long T0 = 0; 
     long X = 30; 
      long testTime = 1111111109L; 

     String steps = "0"; 

     long T = (testTime - T0)/X; 
     steps = Long.toHexString(T).toUpperCase(); 
     while (steps.length() < 16) steps = "0" + steps; 
     System.out.println(generateTOTP(seed, steps, "8", 
     "HmacSHA1")); 
    } 
} 

Python kodu: çalışan Java

import hmac 
from hashlib import sha1 
k = "3132333435363738393031323334353637383930" 
msg = "00000000023523EC" 
print "I hashed key", k, "against msg", msg, "and got...\n" 
a = hmac.new(k, msg, sha1) 
print a.digest().encode('hex') 

Sonuçlar: Python çalışan

Key is...3132333435363738393031323334353637383930 

I hashed key 3132333435363738393031323334353637383930 against message 00000000023523EC and got... 

HASHED: 278C02E53610F84C40BD9135ACD4101012410A14 

07081804 

Sonuçlar:

I hashed key 3132333435363738393031323334353637383930 against msg 00000000023523EC and got... 

fa9362e87c80a1ac61f705b5f9d5095adaec9525 

"Anahtar" ve "ileti" aynıdır, ancak Java sürümü Python uygulamasının yaptığıdan farklı bir HMAC alır.

Python kodunun herhangi bir yerinde (Java sürümü RFC'den beklenen sonuçlarla eşleştiğinden) ince bir hata olduğundan şüpheleniyorum ancak emin değilim. Çok basit görünüyor.

System.out.println("Key is..." + bytesToHex(keyBytes) + "\n"); 
// ... 
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW"); 

Ama Python

, kullandığınız:

cevap

8

Sorun Java, anahtarın (sadece çıkış için bir onaltılık dize dönüştürerek) olarak ham bayt kullandığınız olduğunu düşünüyorum onaltılık dize:

k = "3132333435363738393031323334353637383930" 

görünüyor gibi yapabilirsiniz ile decode the hex string:

raw_key = k.decode('hex') 
+0

İyi catch. Düzeltme: a = hmac.new (k.decode ('hex'), msg.decode ('hex'), sha1) teşekkürler! – ashgromnies

+3

Ayrıca bunu RFC - "" "de ekledim. Ek B. Test Vektörleri ||| Test belirteci paylaşılan sırrı, ASCII dize değeri" 123456789"kullanır. Zaman Adımı X = 30 ile ve Unix çağında başlangıç ​​değeri olarak T0 = ​​0 olduğunda, TOTP algoritması belirtilen mod zaman damgaları için aşağıdaki değerleri gösterecektir. "" "Tablodaki" T (onaltılık) "değerinin" 00000000023523EC "olduğunu söylemeye devam eder. Bu yüzden farklı girişlerde biraz kafa karışıklığı olduğunu düşünüyorum. –