Python HMAC-SHA1 vs Java HMAC-SHA1 resultados diferentes

Tomé prestado el código Java HMAC-SHA1 dehttp://tools.ietf.org/html/rfc6238 y se adaptó ligeramente al código para usar un par de mensaje / clave conocido con salida conocida.

Luego intenté escribir el mismo código en Python para verificar los resultados, sin embargo, estoy obteniendo diferentes valores en Python y Java.

Los valores de Java son conocidos por ser buenos.

Código de Java:

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

Código Python:

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

Resultados de la ejecución de Java:

Key is...3132333435363738393031323334353637383930

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

HASHED: 278C02E53610F84C40BD9135ACD4101012410A14

07081804

Resultados de correr Python:

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

fa9362e87c80a1ac61f705b5f9d5095adaec9525

La "clave" y el "mensaje" son los mismos, pero la versión de Java obtiene un HMAC diferente al de la implementación de Python.

Sospecho que hay un error sutil en alguna parte del código de Python (porque la versión de Java coincide con los resultados esperados del RFC) pero no estoy seguro de dónde. Se ve tan sencillo.

Respuestas a la pregunta(1)

Su respuesta a la pregunta