HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
package com.aesiny.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @Description
* @ClassName HMacMD5Util
* @Author Aesiny.L
* @Date 2020-1-10 14:23
**/
public class HMacMD5Util {
public static void main(String[] args){
String key = "1234567890abcdef";
String operatorId = "123456789";
String data = "il7B0BSEjFdzpyKzfOFpvg/Se1CP802RItKYFPfSLRxJ3jf0bVl9hvYOEktPAYW2nd7S8MBcyHYyacHKbISq5iTmDzG+ivnR+SZJv3USNTYVMz9rCQVSxd0cLlqsJauko79NnwQJbzDTyLooYoIwz75qBOH2/xOMirpeEqRJrF/EQjWekJmGk9RtboXePu2rka+Xm51syBPhiXJAq0GfbfaFu9tNqs/e2Vjja/ltE1M0lqvxfXQ6da6HrThsm5id4ClZFIi0acRfrsPLRixS/IQYtksxghvJwbqOsbIsITail9Ayy4tKcogeEZiOO+4Ed264NSKmk7l3wKwJLAFjCFogBx8GE3OBz4pqcAn/ydA=";
String timeStamp = "20160729142400";
String seq = "0001";
String m = new StringBuilder(operatorId).append(data).append(timeStamp).append(seq).toString();
byte[] macMD5 = HMacMD5Util.getHMacMD5Bytes(key.getBytes(), m.getBytes());
System.out.println(HMacMD5Util.bytesToHexString(macMD5));
}
/**
* HmacMd5的計算公式爲:HMAC(K,M) = H(K⊕opad∣H(K⊕ipad∣M))
* 其中:K是密鑰(byte[] key),長度可爲64字節(後面涉及描述都是以字節byte進行),若小於該長度,在密鑰後面用0(即0x00)補齊。
* M是消息內容(byte[] m);
* H是散列函數(此處採用MD5);
* opad和ipad分別是由若干個0x5c和0x36組成的字符串;
* ⊕表示異或運算;
* ∣表示連接操作。
**/
private static byte[] getHMacMD5Bytes(byte[] key, byte[] m) {
try {
//定義長度
int length = 64;
//定義opad和ipad
byte[] opad = new byte[length];
byte[] ipad = new byte[length];
for (int i = 0; i < 64; i++) {
opad[i] = 0x5C;
ipad[i] = 0x36;
}
byte[] actualKey = key;
byte[] keyArr = new byte[length];
//如果密鑰長度,大於64字節,就使用MD5算法計算其散列值,作爲密鑰
if (key.length > length) {
actualKey = md5(key);
}
for (int i = 0; i < actualKey.length; i++) {
keyArr[i] = actualKey[i];
}
//如果密鑰長度不足64字節,就使用0x00補齊到64字節
if (actualKey.length < length) {
for (int i = key.length; i < length; i++)
keyArr[i] = 0x00;
}
//使用密鑰和ipad進行異或運算【K⊕ipad】
byte[] kIpadXorResult = new byte[length];
for (int i = 0; i < length; i++) {
kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]);
}
//將待加密數據M追加到kIpadXorResult後面【K⊕ipad∣M】
byte[] firstAppendResult = new byte[kIpadXorResult.length + m.length];
for (int i = 0; i < kIpadXorResult.length; i++) {
firstAppendResult[i] = kIpadXorResult[i];
}
for (int i = 0; i < m.length; i++) {
firstAppendResult[i + keyArr.length] = m[i];
}
//做MD5運算【H(K⊕ipad∣M)】
byte[] firstHashResult = md5(firstAppendResult);
//使用密鑰和opad進行異或運算【K⊕opad】
byte[] kOpadXorResult = new byte[length];
for (int i = 0; i < length; i++) {
kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]);
}
//將firstHashResult追加到kOpadXorResult後面【K⊕opad∣H(K⊕ipad∣M)】
byte[] secondAppendResult = new byte[kOpadXorResult.length + firstHashResult.length];
for (int i = 0; i < kOpadXorResult.length; i++) {
secondAppendResult[i] = kOpadXorResult[i];
}
for (int i = 0; i < firstHashResult.length; i++) {
secondAppendResult[kOpadXorResult.length + i] = firstHashResult[i];
}
//做MD5運算【H(K⊕opad∣H(K⊕ipad∣M))】
return md5(secondAppendResult);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* MD5(產生出一個128位(16字節)的散列值)
**/
private static byte[] md5(byte[] str) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str);
return md.digest();
}
/**
* HEX轉化爲字符串
**/
private static String bytesToHexString(byte[] m) {
StringBuilder stringBuilder = new StringBuilder();
if (m == null || m.length <= 0) {
return null;
}
for (int i = 0; i < m.length; i++) {
int v = m[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString().toUpperCase();
}
}