2009-10-22 68 views
46

我在寻找Java相当于这个PHP呼叫:的Java相当于PHP的HMAC-SHA1

hash_hmac('sha1', "test", "secret") 

我想这一点,使用java.crypto.Mac,但两人不同意:

String mykey = "secret"; 
String test = "test"; 
try { 
    Mac mac = Mac.getInstance("HmacSHA1"); 
    SecretKeySpec secret = new SecretKeySpec(mykey.getBytes(),"HmacSHA1"); 
    mac.init(secret); 
    byte[] digest = mac.doFinal(test.getBytes()); 
    String enc = new String(digest); 
    System.out.println(enc); 
} catch (Exception e) { 
    System.out.println(e.getMessage()); 
} 

key =“secret”和test =“test”的输出似乎不匹配。

+2

那么,他们有什么不同呢?哪一个匹配sha1的测试模式?粗略浏览PHP文档将显示“raw_output”选项。 – 2009-10-22 21:01:39

+0

发布一些测试输入和输出(使用十六进制编码或base-64作为二进制参数)。 – erickson 2009-10-22 21:03:44

回答

37

事实上他们同意。
由于Hans Doggen已经使用十六进制表示法记录了PHP输出消息摘要,除非您将原始输出参数设置为true。
如果你想使用Java中相同的符号,你可以使用类似

for (byte b : digest) { 
    System.out.format("%02x", b); 
} 
System.out.println(); 

据此格式化输出。

3

对我来说似乎是PHP对Java产生的字节(1a = 26)使用HEX表示法 - 但我没有检查整个表达式。

如果通过this页面上的方法运行字节数组,会发生什么情况?

1

没有测试过,但试试这个:

 BigInteger hash = new BigInteger(1, digest); 
     String enc = hash.toString(16); 
     if ((enc.length() % 2) != 0) { 
      enc = "0" + enc; 
     } 

这是我的方法,使Java的MD5和SHA1匹配PHP的快照。

+0

当然,使用新的StringBuilder(digest.length * 2),for/next循环和append(String.format(“%02X”),digest [i]&0xFF)的内存密集程度更低,并且可读性更强。 – 2011-11-21 22:10:44

+0

if语句需要是while循环。它不适用于多个前导零的情况。 – slushi 2013-06-06 14:37:18

4

这是我实现:

 String hmac = ""; 

    Mac mac = Mac.getInstance("HmacSHA1"); 
    SecretKeySpec secret = new SecretKeySpec(llave.getBytes(), "HmacSHA1"); 
    mac.init(secret); 
    byte[] digest = mac.doFinal(cadena.getBytes()); 
    BigInteger hash = new BigInteger(1, digest); 
    hmac = hash.toString(16); 

    if (hmac.length() % 2 != 0) { 
     hmac = "0" + hmac; 
    } 

    return hmac; 
+0

这是唯一适用于我的解决方案。非常感谢! – 2016-08-04 07:22:37

11

你可以在Java中试试这个:

private static String computeSignature(String baseString, String keyString) throws GeneralSecurityException, UnsupportedEncodingException { 

    SecretKey secretKey = null; 

    byte[] keyBytes = keyString.getBytes(); 
    secretKey = new SecretKeySpec(keyBytes, "HmacSHA1"); 

    Mac mac = Mac.getInstance("HmacSHA1"); 

    mac.init(secretKey); 

    byte[] text = baseString.getBytes(); 

    return new String(Base64.encodeBase64(mac.doFinal(text))).trim(); 
} 
1

我实施HMACMD5 - 只是改变算法HMACSHA1:

SecretKeySpec keySpec = new SecretKeySpec("secretkey".getBytes(), "HmacMD5"); 
Mac mac = Mac.getInstance("HmacMD5"); 
mac.init(keySpec); 
byte[] hashBytes = mac.doFinal("text2crypt".getBytes()); 
return Hex.encodeHexString(hashBytes); 
1

这样我可以得到完全相同的字符串,因为我在使用hash_hmac在php

String result; 

try { 
     String data = "mydata"; 
     String key = "myKey"; 
     // Get an hmac_sha1 key from the raw key bytes 
     byte[] keyBytes = key.getBytes(); 
     SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1"); 

     // Get an hmac_sha1 Mac instance and initialize with the signing key 
     Mac mac = Mac.getInstance("HmacSHA1"); 
     mac.init(signingKey); 

     // Compute the hmac on input data bytes 
     byte[] rawHmac = mac.doFinal(data.getBytes()); 

     // Convert raw bytes to Hex 
     byte[] hexBytes = new Hex().encode(rawHmac); 

     // Covert array of Hex bytes to a String 
     result = new String(hexBytes, "ISO-8859-1"); 
     out.println("MAC : " + result); 
} 
catch (Exception e) { 

} 
+0

这应该是正确的答案,许多人错过了十六进制编码步骤。 – Krishnaraj 2016-08-20 06:08:22