package com.ruoyi.jianguan.util;
|
|
import java.io.UnsupportedEncodingException;
|
import java.security.MessageDigest;
|
import java.security.NoSuchAlgorithmException;
|
import java.util.Arrays;
|
|
/**
|
* 签名工具
|
* @author zhibing.pu
|
* @Date 2025/1/23 11:30
|
*/
|
public class SignUtil {
|
|
|
/*************************************快电******************************************/
|
|
/**
|
* 签名算法
|
*
|
* @param aValue 加密的原文,即源数据
|
* @param aKey 密钥 这是针对一条字符串进行加密的方法
|
*/
|
public static String hmacSign (String aValue, String aKey) {
|
byte k_ipad[] = new byte[64];
|
byte k_opad[] = new byte[64];
|
byte keyb[];
|
byte value[];
|
try {
|
keyb = aKey.getBytes("UTF-8");
|
value = aValue.getBytes("UTF-8");
|
} catch (UnsupportedEncodingException e) {
|
keyb = aKey.getBytes();
|
value = aValue.getBytes();
|
}
|
|
Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
|
Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
|
for (int i = 0; i < keyb.length; i++) {
|
k_ipad[i] = (byte) (keyb[i] ^ 0x36);
|
k_opad[i] = (byte) (keyb[i] ^ 0x5c);
|
}
|
|
MessageDigest md = null;
|
try {
|
md = MessageDigest.getInstance("MD5");
|
} catch (NoSuchAlgorithmException e) {
|
return null;
|
}
|
md.update(k_ipad);
|
md.update(value);
|
byte dg[] = md.digest();
|
md.reset();
|
md.update(k_opad);
|
md.update(dg, 0, 16);
|
dg = md.digest();
|
return toHex(dg);
|
}
|
|
public static String toHex (byte input[]) {
|
if (input == null) {
|
return null;
|
}
|
StringBuffer output = new StringBuffer(input.length * 2);
|
for (int i = 0; i < input.length; i++) {
|
int current = input[i] & 0xff;
|
if (current < 16) {
|
output.append("0");
|
}
|
output.append(Integer.toString(current, 16));
|
}
|
return output.toString().toUpperCase();
|
}
|
|
|
|
/*************************************新电途******************************************/
|
|
/**
|
* 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组成的字符串;
|
* ⊕表示异或运算;
|
* ∣表示连接操作。
|
**/
|
public 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 < length; 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转化为字符串
|
**/
|
public 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();
|
}
|
|
|
|
|
public static void main(String[] args) {
|
// String encrypt = AESUtil.encrypt("{\"total\":1,\"stationStatusInfo\":{\"operationID\":\"123456789\",\"stationID\":\"111111111111111\",\"connectorStatusInfos\":{\"connectorID\":1,\"equipmentID\":\"10000000000000000000001\",\"status\":4,\"currentA\":0,\"currentB\":0,\"currentC\":0,\"voltageA\":0,\"voltageB\":0,\"voltageC\":0,\"soc\":10,}}}");
|
// String s = hmacSign(encrypt, "123456789abcdef");
|
// System.err.println(s);
|
|
|
//签名秘钥SigSecret
|
String key = "1234567890abcdef";
|
//运营商标识OperatorId
|
String operatorId = "123456789";
|
//参数信息Data
|
String data = "il7B0BSEjFdzpyKzfOFpvg/Se1CP802RItKYFPfSLRxJ3jf0bVl9hvYOEktPAYW2nd7S8MBcyHYyacHKbISq5iTmDzG+ivnR+SZJv3USNTYVMz9rCQVSxd0cLlqsJauko79NnwQJbzDTyLooYoIwz75qBOH2/xOMirpeEqRJrF/EQjWekJmGk9RtboXePu2rka+Xm51syBPhiXJAq0GfbfaFu9tNqs/e2Vjja/ltE1M0lqvxfXQ6da6HrThsm5id4ClZFIi0acRfrsPLRixS/IQYtksxghvJwbqOsbIsITail9Ayy4tKcogeEZiOO+4Ed264NSKmk7l3wKwJLAFjCFogBx8GE3OBz4pqcAn/ydA=";
|
//时间戳TimeStamp(格式:年月日时分秒)
|
String timeStamp = "20160729142400";
|
//自增序列Seq
|
String seq = "0001";
|
//进行字符串拼接、计算
|
String m = new StringBuilder(operatorId).append(data).append(timeStamp).append(seq).toString();
|
byte[] hmacMd5 = getHMacMD5Bytes(key.getBytes(), m.getBytes());
|
// 打印计算得到的签名Sig
|
System.out.println(bytesToHexString(hmacMd5));
|
}
|
}
|