HMAC-SHA256签名计算算法

我正在尝试使用 HMAC-SHA256算法创建一个签名,这是我的代码。 我使用的是美国 ASCII 编码。

final Charset asciiCs = Charset.forName("US-ASCII");
final Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
final SecretKeySpec secret_key = new javax.crypto.spec.SecretKeySpec(asciiCs.encode("key").array(), "HmacSHA256");
sha256_HMAC.init(secret_key);
final byte[] mac_data = sha256_HMAC.doFinal(asciiCs.encode("The quick brown fox jumps over the lazy dog").array());
String result = "";
for (final byte element : mac_data)
{
result += Integer.toString((element & 0xff) + 0x100, 16).substring(1);
}
System.out.println("Result:[" + result + "]");

我从上面的代码得到的结果是:

f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

这和在维基中显示的是一样的

HMAC_SHA256("key", "The quick brown fox jumps over the lazy dog") = 0x f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

0x除外。

我正在寻找想法/注释,如果我做的一切正确或可能是我可以改进我的代码。

206585 次浏览

The 0x just denotes that the characters after it represent a hex string.

0x1A == 1Ah == 26 == 1A

So the 0x is just to clarify what format the output is in, no need to worry about it.

The answer that you got there is correct. One minor thing in the code above, you need to init(key) before you can call doFinal()

    final Charset charSet = Charset.forName("US-ASCII");
final Mac sha256_HMAC = Mac.getInstance("HmacSHA256");


final SecretKeySpec secret_key = new javax.crypto.spec.SecretKeySpec(charSet.encode("key").array(), "HmacSHA256");
try {
sha256_HMAC.init(secret_key);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...

Here is my solution:

public static String encode(String key, String data) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);


return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes("UTF-8")));
}


public static void main(String [] args) throws Exception {
System.out.println(encode("key", "The quick brown fox jumps over the lazy dog"));
}

Or you can return the hash encoded in Base64:

Base64.encodeBase64String(sha256_HMAC.doFinal(data.getBytes("UTF-8")));

The output in hex is as expected:

f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

Here is my solution:

public String HMAC_SHA256(String secret, String message)
{
String hash="";
try{
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);


hash = Base64.encodeToString(sha256_HMAC.doFinal(message.getBytes()), Base64.DEFAULT);
}catch (Exception e)
{


}
return hash.trim();
}

This is working fine for me

I have add dependency

compile 'commons-codec:commons-codec:1.9'

ref: http://mvnrepository.com/artifact/commons-codec/commons-codec/1.9

my function

public String encode(String key, String data) {
try {


Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);


return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)));


} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
    

return null;
}

If but any chance you found a solution how to calculate HMAC-SHA256 here, but you're getting an exception like this one:

java.lang.NoSuchMethodError: No static method encodeHexString([B)Ljava/lang/String; in class Lorg/apache/commons/codec/binary/Hex; or its super classes (declaration of 'org.apache.commons.codec.binary.Hex' appears in /system/framework/org.apache.http.legacy.boot.jar)

Then use:

public static String encode(String key, String data) {
try {
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
hmac.init(secret_key);
return new String(Hex.encodeHex(hmac.doFinal(data.getBytes("UTF-8"))));
} catch (Exception e) {
throw new RuntimeException(e);
}
}

If you're using Guava, its latest release now lets you use

 Hashing.hmacSha256()

One example of using this:

String hash = Hashing.hmacSha256("mykey".getBytes(StandardCharsets.UTF_8)).hashString("my_message", StandardCharsets.UTF_8).toString()

Further documentation here: https://guava.dev/releases/23.0/api/docs/com/google/common/hash/Hashing.html#hmacSha256-byte:A-

Java simple code to generate encoded(HMAC-x) signatures. (Tried using Java-8 and Eclipse)

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;


import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;


import com.sun.org.apache.xml.internal.security.utils.Base64;


/**
* Encryption class to show how to generate encoded(HMAC-x) signatures.
*
*/
public class Encryption {


public static void main(String args[]) {


String message = "This is my message.";
String key = "your_key";
String algorithm = "HmacMD5";  // OPTIONS= HmacSHA512, HmacSHA256, HmacSHA1, HmacMD5


try {


// 1. Get an algorithm instance.
Mac sha256_hmac = Mac.getInstance(algorithm);


// 2. Create secret key.
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), algorithm);


// 3. Assign secret key algorithm.
sha256_hmac.init(secret_key);


// 4. Generate Base64 encoded cipher string.
String hash = Base64.encode(sha256_hmac.doFinal(message.getBytes("UTF-8")));


// You can use any other encoding format to get hash text in that encoding.
System.out.println(hash);


/**
* Here are the outputs for given algorithms:-
*
* HmacMD5 = hpytHW6XebJ/hNyJeX/A2w==
* HmacSHA1 = CZbtauhnzKs+UkBmdC1ssoEqdOw=
* HmacSHA256 =gCZJBUrp45o+Z5REzMwyJrdbRj8Rvfoy33ULZ1bySXM=
* HmacSHA512 = OAqi5yEbt2lkwDuFlO6/4UU6XmU2JEDuZn6+1pY4xLAq/JJGSNfSy1if499coG1K2Nqz/yyAMKPIx9C91uLj+w==
*/


} catch (NoSuchAlgorithmException e) {


e.printStackTrace();


} catch (UnsupportedEncodingException e) {


e.printStackTrace();


} catch (InvalidKeyException e) {


e.printStackTrace();


}


}


}

NOTE: You can use any other Algorithms and can try generating HmacMD5, HmacSHA1, HmacSHA256, HmacSHA512 signatures.

Try this

Sorry for being late, I have tried all above answers but none of them is giving me correct value, After doing the lot of R&D I have found a simple way that gives me exact value.

  1. Declare this method in your class

    private String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
    try {
    SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
    Mac mac = Mac.getInstance(SHA_TYPE);
    mac.init(signingKey);
    byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));
    byte[] hexArray = {(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'};
    byte[] hexChars = new byte[rawHmac.length * 2];
    for ( int j = 0; j < rawHmac.length; j++ ) {
    int v = rawHmac[j] & 0xFF;
    hexChars[j * 2] = hexArray[v >>> 4];
    hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
    }
    catch (Exception ex) {
    throw new RuntimeException(ex);
    }
    

    }

  2. Use this like

    Log.e("TAG", "onCreate: "+hmacSha("key","text","HmacSHA256"));
    

Verification

1.Android studio output Android studio output 2. Online HMAC generator Output(Visit here for Online Genrator) enter image description here