java equivalent to php's hmac-SHA1

42,724

Solution 1

In fact they do agree.
As Hans Doggen already noted PHP outputs the message digest using hexadecimal notation unless you set the raw output parameter to true.
If you want to use the same notation in Java you can use something like

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

to format the output accordingly.

Solution 2

You can try this in 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();
}

Solution 3

This is my implementation :

        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;

Solution 4

Seems to me that PHP uses HEX notation for the bytes that Java produces (1a = 26) - but I didn't check the whole expression.

What happens if you run the byte array through the method on this page?

Solution 5

This way I could get the exact same string as I was getting with hash_hmac in 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) {

}
Share:
42,724
Bee
Author by

Bee

Maker. Puzzle do-er. Word smith.

Updated on September 07, 2020

Comments

  • Bee
    Bee over 3 years

    I'm looking for a java equivalent to this php call:

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

    I tried this, using java.crypto.Mac, but the two do not agree:

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

    The outputs with key = "secret" and test = "test" do not seem to match.

  • Maarten Bodewes
    Maarten Bodewes over 12 years
    Of course, using new StringBuilder(digest.length * 2), a for/next loop and append(String.format("%02X"), digest[i] & 0xFF) is less memory intensive and possibly a bit more readable.
  • slushi
    slushi almost 11 years
    the if statement needs to be a while loop. it won't work for the multiple leading zeroes case.
  • Gerhard Hagerer
    Gerhard Hagerer almost 8 years
    That's the only solution that works for me. Thanks a lot!
  • Krishnaraj
    Krishnaraj over 7 years
    This should be the right answer, many have missed the Hex encoding step.
  • Pedro Joaquín
    Pedro Joaquín almost 5 years
    I'm sorry but I'm ignorant, where do I get the "Hex().encode(bytes[] rawHmac)" method?