HmacSHA1签名

在提供第三方接口的时候,我们需要确认:

1.消息未被其他人篡改(签名和验证签名)

2.从消息中确认第三方的身份(appid)

因为hash是不可逆的,所以签名的过程是不可逆的;

HMACSHA1 是从 SHA1 哈希函数构造的一种键控哈希算法,被用作 HMAC(基于哈希的消息验证代码)。 此 HMAC 进程将密钥与消息数据混合,使用哈希函数对混合结果进行哈希计算,将所得哈希值与该密钥混合,然后再次应用哈希函数。 输出的哈希值长度为 160 位。

在发送方和接收方共享机密密钥的前提下,HMAC 可用于确定通过不安全信道发送的消息是否已被篡改。 发送方计算原始数据的哈希值,并将原始数据和哈希值放在一个消息中同时传送。 接收方重新计算所接收消息的哈希值,并检查计算所得的 HMAC 是否与传送的 HMAC 匹配。

因为更改消息和重新生成正确的哈希值需要密钥,所以对数据或哈希值的任何更改都会导致不匹配。 因此,如果原始的哈希值与计算得出的哈希值相匹配,则消息通过身份验证。

SHA-1(安全哈希算法,也称为 SHS、安全哈希标准)是由美国政府发布的一种加密哈希算法。 它将从任意长度的字符串生成 28位长的字符串。

签名采用HmacSHA1算法 + Base64,编码采用:UTF-8参考代码如下:

String sign = sign(accessSecret + "&", stringToSign.toString());

 

public static String sign(String accessSecret, String stringToSign) throws Exception {

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

mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), "HmacSHA1"));

byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));

return new sun.misc.BASE64Encoder().encode(signData);

}

 

附加完整的Java签名Demo代码(摘自阿里短信验证):

其中随机字符串的作用是:主要保证签名不可预测;

public class SignDemo {

 

public static void main(String[] args) throws Exception {

String accessKeyId = "testId";

String accessSecret = "testSecret";

 

java.text.SimpleDateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));// 这里一定要设置GMT时区

 

java.util.Map<String, String> paras = new java.util.HashMap<String, String>();

// 1. 系统参数

paras.put("SignatureMethod", "HMAC-SHA1");

paras.put("SignatureNonce", java.util.UUID.randomUUID().toString());

paras.put("AccessKeyId", accessKeyId);

paras.put("SignatureVersion", "1.0");

paras.put("Timestamp", df.format(new java.util.Date()));

paras.put("Format", "XML");

 

// 2. 业务API参数

paras.put("Action", "SendSms");

paras.put("Version", "2017-05-25");

paras.put("RegionId", "cn-hangzhou");

paras.put("PhoneNumbers", "15300000001");

paras.put("SignName", "阿里云短信测试专用");

paras.put("TemplateParam", "{\"customer\":\"test\"}");

paras.put("TemplateCode", "SMS_71390007");

paras.put("OutId", "123");

 

// 3. 去除签名关键字Key

if (paras.containsKey("Signature"))

paras.remove("Signature");

 

// 4. 参数KEY排序

java.util.TreeMap<String, String> sortParas = new java.util.TreeMap<String, String>();

sortParas.putAll(paras);

 

// 5. 构造待签名的字符串

java.util.Iterator<String> it = sortParas.keySet().iterator();

StringBuilder sortQueryStringTmp = new StringBuilder();

while (it.hasNext()) {

String key = it.next();

sortQueryStringTmp.append("&").append(specialUrlEncode(key)).append("=").append(specialUrlEncode(paras.get(key)));

}

String sortedQueryString = sortQueryStringTmp.substring(1);// 去除第一个多余的&符号

 

StringBuilder stringToSign = new StringBuilder();

stringToSign.append("GET").append("&");

stringToSign.append(specialUrlEncode("/")).append("&");

stringToSign.append(specialUrlEncode(sortedQueryString));

 

String sign = sign(accessSecret + "&", stringToSign.toString());

// 6. 签名最后也要做特殊URL编码

String signature = specialUrlEncode(sign);

 

System.out.println(paras.get("SignatureNonce"));

System.out.println("\r\n=========\r\n");

System.out.println(paras.get("Timestamp"));

System.out.println("\r\n=========\r\n");

System.out.println(sortedQueryString);

System.out.println("\r\n=========\r\n");

System.out.println(stringToSign.toString());

System.out.println("\r\n=========\r\n");

System.out.println(sign);

System.out.println("\r\n=========\r\n");

System.out.println(signature);

System.out.println("\r\n=========\r\n");

// 最终打印出合法GET请求的URL

System.out.println("http://dysmsapi.aliyuncs.com/?Signature=" + signature + sortQueryStringTmp);

}

 

public static String specialUrlEncode(String value) throws Exception {

return java.net.URLEncoder.encode(value, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");

}

 

public static String sign(String accessSecret, String stringToSign) throws Exception {

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

mac.init(new javax.crypto.spec.SecretKeySpec(accessSecret.getBytes("UTF-8"), "HmacSHA1"));

byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));

return new sun.misc.BASE64Encoder().encode(signData);

}

 

}

`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值