php hmac,PHP签名验证之hash_hmac sha1

前言

secret_id: 密钥的Id

secret_key: 密钥的Key

SHA1: 签名方式

hash_hmac: php hash函数

hash_hmac_file:生成密钥

1.生成secret_key

hash_hmac_file('SHA1','signature.txt','secret');

2.生成签名

base64_encode(hash_hmac('SHA1', $init, $secret_key, true).$init);

3.签名比对

base64_decode($initSign);

base64_encode(hash_hmac('SHA1', $init, $secret_key, true).$init);

4.网站验证(sha1.html)

访问 sha1.html

5.代码

5.1 HashHmacSha1.php

class HashHmacSha1

{

/** code

* @var int

*/

protected $code = 200;

/** message

* @var string

*/

protected $message = 'success';

/** 获取处理code

* @return int

*/

public function getCode()

{

return $this->code;

}

/** 获取处理message

* @return string

*/

public function getMessage()

{

return $this->message;

}

/** 产生随机字符串,不长于32位

* @param int $length

* @return string

*/

public function getNonceStr($length = 32)

{

$chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#%^&*;:-=_+,.";

$str ="";

for ( $i = 0; $i < $length; $i++ ) {

$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);

}

return $str;

}

/** 生成sha1的secret

* @other 绑定生成的 内容,secret_key,secret_id

* @return string

*/

public function signSha1Create()

{

$nonce = $this->getNonceStr();

$rand = rand();

$time = time();

$content = "The signature : nonce={$nonce}; rand={$rand}; time={$time}, by sok yo!";

//生成签名内容

file_put_contents('signature.txt', $content);

$signature = hash_hmac_file('SHA1','signature.txt','secret');

unlink('signature.txt');

return $signature;

}

/** sha1数据加密

* @param $secret_id

* @param $secret_key

* @return string

*/

public function signSha1Encrypt($secret_id,$secret_key)

{

$time = time();

// 业务逻辑,向参数列表填入参数(可抽离)

$arg_list = array(

"secretId" => $secret_id,

"currentTimeStamp" => $time,

"expireTime" => $time+86400,

"random" =>rand(),

);

$init = http_build_query($arg_list);

// 计算签名

// raw_output = false ; 53e55273e57c3cf6b7c16e5840479566be3aa0d2,16进制小写字符串格式(40个字符)

// raw_output = true ; �� Ej���۔����̠��,原始二进制数据(20个字符)

// base64_encode 设计此种编码是为了使二进制数据可以通过非纯 8-bit 的传输层传输(防止特殊字符在传输过程中被转义)。

// base64_encode 数据要比原始数据多占用 33% 左右的空间。

$signature = base64_encode(hash_hmac('SHA1', $init, $secret_key, true).$init);

// JS CryptoJS

return $signature ;

}

/** sha1数据解密

* @param $initSign

* @param $secretId

* @param $secretKey

* @return bool

*/

public function signSha1Decrypt($initSign,$secretId,$secretKey)

{

//先做 base64 解码,拿到数据

$sign = base64_decode($initSign);

//前 5 个单元是 sha1 ,这里的代码单元默认为:编码+16进制(0041),5个单元 = 5 * 4(字节) = 20(字节)

$signStr = substr($sign,20);

//数组形式

parse_str($signStr,$signArr);

//逻辑判断(可抽离)

$mustKey = ['secretId','currentTimeStamp','expireTime','random'];

foreach ($mustKey as $k) {

if(!isset($signArr[$k])) {

$this->code = 400;

$this->message = 'miss '.$k;

return false;

}

}

//secretId

if((string)$signArr['secretId'] !== (string)$secretId) {

$this->code = 400;

$this->message = 'error secretId';

return false;

}

//时间

if($signArr['currentTimeStamp'] > $signArr['expireTime']) {

$this->code = 400;

$this->message = 'error currentTimeStamp';

return false;

}

//过期

if($signArr['expireTime'] < time()) {

$this->code = 400;

$this->message = 'expireTime expired';

return false;

}

// 计算签名

$signature = base64_encode(hash_hmac('SHA1', $signStr, $secretKey, true).$signStr);

if($signature === $initSign) {

$this->code = 200;

$this->message = 'success';

return true;

}else{

$this->code = 400;

$this->message = 'error signature';

return false;

}

}

}

5.2 sha1.html

hash_hmac sha1 签名校验工具

.form-value{

width:74% !important;

}

.form-name{

width:25% !important;

}

.form-block{

width: 100% !important;

}

.text-danger{

color:red;

}

.form-inline{

margin-bottom: 10px;

}

.control-label{

text-align: left !important;

padding:0 0 0 15px;

}

.non-required-form .control-label{

font-weight: normal;

}

.non-required-form{

display: none;

}

hash_hmac sha1 签名校验工具

签名结果串(必填)*

解析签名

中间结果(Query String)

Secret ID

当前时间戳

签名失效时间戳

随机数

Secret Key(必填)*

校验

签名校验结果

var signature,secret_key;

$("#decodeSig").click(function(){

signature = $("input[name=signature]").val();

if(!signature) {

alert('签名结果串 不能为空');

} else {

var signature = $("input[name=signature]").val();

decodeSignature(signature);

}

});

$("#checkSecretkey").click(function(){

signature = $("input[name=signature]").val();

secret_key = $("input[name=secretKey]").val();

var checkResult;

if(!secret_key) {

$("input[name=decodeResult]").val('Secret Key 不能为空');

} else {

checkResult = check(signature, secret_key);

if(checkResult){

if(checkResult == 'expired') {

$("input[name=decodeResult]").val('签名已过期');

} else if(checkResult == 'notInt') {

$("input[name=decodeResult]").val('时间戳和随机数必须为纯数字');

} else if (checkResult == 'wrongExpireTime') {

$("input[name=decodeResult]").val('expireTime 不可小于 currentTimeStamp');

} else {

$("input[name=decodeResult]").val('签名校验通过');

}

}else {

$("input[name=decodeResult]").val('签名校验失败');

}

}

});

var decodeSignature = function(signature){

// var sha = CryptoJS.HmacSHA1(argStr, secret_key);

// sha.concat(CryptoJS.enc.Utf8.parse(argStr))

// var signature = CryptoJS.enc.Base64.stringify(sha);

$(".non-required-form").hide();

$(".required-form .form-value").val("");

$("input[name=queryString]").val("");

var queryString = getOriginalStr(signature);

//将解析的结果填入input

$("input[name=queryString]").val(queryString);

var arr = queryString.split("&");

arr.map(function(item){

var name = item.split("=")[0].replace(/\./,"_");

var value = decodeURIComponent(item.split("=")[1]);

if(!name || !value) {

alert('签名结果串格式不合法,请检查输入的签名结果串');

return;

}

var input = $("input[name='"+escape(name)+"']");

if(input.length>=1){

$(input).val(value);

$(input).closest(".non-required-form").show();

if (name === 'currentTimeStamp') {

$('.currentTimeStampHuman').text(new Date(value * 1000))

}

if (name === 'expireTime') {

$('.expireTimeHuman').text(new Date(value * 1000))

}

}else{

var customInput = '

'

+ ''

+ '

'

+ ''

+ ''

+ '

';

$(".required-form:last").after(customInput);

$(".required-form:last").next().find('.form-name').val(name);

$(".required-form:last").next().find('.form-value').val(value);

}

})

}

function getOriginalStr(signature) {

var buffer = CryptoJS.enc.Base64.parse(signature);

var argBuffer = CryptoJS.lib.WordArray.create(buffer.words.slice(5), buffer.sigBytes-20);

return argBuffer.toString(CryptoJS.enc.Utf8);

}

function check(signature, secret_key) {

// 先做 base64 解码,拿到整个数据的 buffer

var buffer = CryptoJS.enc.Base64.parse(signature);

// 前 5 个单元是 sha1

var shaBuffer = CryptoJS.lib.WordArray.create(buffer.words.slice(0, 5), 20);

// 后 5 个单元是 querystring,并且是 UTF8 编码的

var argBuffer = CryptoJS.lib.WordArray.create(buffer.words.slice(5), buffer.sigBytes-20);

// 把 querystring 从 UTF8 编码的 buffer 转成 string

var argStr = argBuffer.toString(CryptoJS.enc.Utf8);

// 再次用 sk + querystring 计算出 sha

var sha = CryptoJS.HmacSHA1(argStr, secret_key);

// 对比两个 sha 是不是一样的

if(!$("input[name=expireTime]").val()) {

decodeSignature(signature);

}

if(+$("input[name=currentTimeStamp]").val() > +$("input[name=expireTime]").val()) {

return 'wrongExpireTime';

}

// 校验时间是否过期

if(+$("input[name=expireTime]").val() < Math.floor((+new Date())/1000)) {

return 'expired';

}

if(isNaN($("input[name=random]").val()) || isNaN($("input[name=currentTimeStamp]").val()) || isNaN($("input[name=expireTime]").val())) {

return 'notInt';

}

return sha.toString(CryptoJS.enc.Base64) === shaBuffer.toString(CryptoJS.enc.Base64);

}

var _mtac = {};

(function() {

var mta = document.createElement("script");

mta.src = "https://pingjs.qq.com/h5/stats.js?v2.0.2";

mta.setAttribute("name", "MTAH5");

mta.setAttribute("sid", "500428027");

var s = document.getElementsByTagName("script")[0];

s.parentNode.insertBefore(mta, s);

})();

6.测试

//测试

$model = new HashHmacSha1();

//随机的 secret_id

$secretId = 'abc1234Def453';

//生成 secret_key

$secretKey = $model->signSha1Create();

//'fe08bd195744e08e289174167b1d53cd638e6f7b';

//生成签名

$sign = $model->signSha1Encrypt($secretId,$secretKey);

//'ZQlqVb8DKt14kDD6TCxWQMQARVxzZWNyZXRJZD1hYmMxMjM0RGVmNDUzJmN1cnJlbnRUaW1lU3RhbXA9MTU2Njg4NzA2MyZleHBpcmVUaW1lPTE1NjY5NzM0NjMmcmFuZG9tPTk4MTEzNjMwNA==';

//比对

$res = $model->signSha1Decrypt($sign,$secretId,$secretKey);

var_dump($res);

7.sha1.html 运行参照

9a46dac7da0418ac58e6c18824a5d7b1.png

感谢阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值