php生成md5簽名原理


數字簽名(又稱公鑰數字簽名、電子簽章)是一種類似寫在紙上的普通的物理簽名,但是使用了公鑰加密領域的技術實現,用於鑒別數字信息的方法。一套數字簽名通常定義兩種互補的運算,一個用於簽名,另一個用於驗證。

MD5是沒辦法反向破解的

在講解這個之前一定要了解一個東西:MD5是沒辦法反向破解的,如果你不了解這個那這原理理解起來有點難,當然一些簡單的組合通過一些網站的暴力破解,但我們的數據都是32甚至更多的MD5加密,所以這是幾乎不能破解的。了解了這一點,你才能不在這個原理上走彎路。

雙方約定:

服務方一般會給請求方一個appid和appkey, appid是請求方請求的唯一標識,這個是可以在網絡上傳輸的,而appkey是不在網絡上傳輸的。

請求方:

請求方如果需要請求,他會把請求的數據(這個請求數據中一定包含appid)按一定的規則(這個規則是雙方規定好的一個算法)進行過濾排序,然后把過濾排序后的參數加上appkey進行MD5加密碼(這也就是我們說的簽名),然后再把請求的參數加上簽名一起傳給服務方。

服務方:

服務方收到請求,會首先把請求參數的不需要或空的參數值過濾掉,然后按照同樣的算法進行過濾排序,然后拿出請求中的appid,在服務器數據庫搜索中appid對應的appkey,然后把參數加上appkey進行MD5加密同樣生成簽名,這時拿這個簽名去與請求方傳的參數中的簽名對比,如果相等,簽名成功。

注意點:

在整個過程中其實就是參數加appkey進行MD5加密后的一個對比,但是appkey是不在網絡上傳輸的,是請求方和服務方分別在本地保存的一個同樣的標識,這樣可以起到防止網絡數據劫持的危險。

核心程序:

里面只寫了md5的程序,rsa的略。

<?php
/**
 * 資料來源:支付寶
 * 簽名:所有交互的數據都需要簽名,除了 sign(簽名),和 sign_type(簽名方式:md5,rsa)
 * md5簽名
 * 1.私鑰:只有你和服務器知道,用於加密數據,由英文字母和數據組成,共32位
 * 2.請求時簽名:$sign=md5((待簽名字符串.md5私鑰));
 * 3.返回時驗證:$_POST['sign']==md5((待驗證字符串,md5私鑰))
 * rsa簽名
 * 1.私鑰與公鑰:openssl生成
 * 2.請求時簽名:$sign = rsaSign(待簽名字符串,私鑰);
 * 3.返回時驗證:$_POST['sign'] == rsaVerify(待驗證字符串,公鑰);
 */

/**
 * 演示md5簽名過程
 */

/**
 * 除去數組中的空值和簽名參數
 * @param $para 簽名參數組
 * return 去掉空值與簽名參數后的新簽名參數組
 */
function paraFilter($para) {
    $para_filter = array();
    while (list ($key, $val) = each ($para)) {
        if($key == "sign" || $key == "sign_type" || $val == "")continue;
        else    $para_filter[$key] = $para[$key];
    }
    return $para_filter;
}
/**
 * 對數組排序
 * @param $para 排序前的數組
 * return 排序后的數組
 */
function argSort($para) {
    ksort($para);
    reset($para);
    return $para;
}
/**
 * 把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串
 * @param $para 需要拼接的數組
 * return 拼接完成以后的字符串
 */
function createLinkstring($para) {
    $arg  = "";
    while (list ($key, $val) = each ($para)) {
        $arg.=$key."=".$val."&";
    }
    //去掉最后一個&字符
    $arg = substr($arg,0,count($arg)-2);
    //如果存在轉義字符,那么去掉轉義
    if(get_magic_quotes_gpc()){
        $arg = stripslashes($arg);
    }
    return $arg;
}
/**
 * 生成md5簽名字符串
 * @param $prestr 需要簽名的字符串
 * @param $key 私鑰
 * return 簽名結果
 */
function md5Sign($prestr, $key) {
    $prestr = $prestr . $key;
    return md5($prestr);
}

class Submit{
    public $_sign_type ='';
    public $_md5_key = '';
    public $_private_key_path = '';

    public function __construct($sign_type){
        $this->_sign_type = strtoupper($sign_type);
    }
    /**
     * 對參數進行過濾,然后排序
     * @param array $para_temp
     */
    function filterPara($para_temp){
        $para_filter = paraFilter($para_temp);//除去待簽名參數數組中的空值和簽名參數
        return argSort($para_filter);//對待簽名參數數組排序
    }
    /**
     * 生成簽名結果
     * @param $para_sort 已排序要簽名的數組
     * @return string 簽名結果字符串
     */
    function buildRequestMysign($para_sort) {
        //把數組所有元素,按照“參數=參數值”的模式用“&”字符拼接成字符串
        $prestr = createLinkstring($para_sort);
        $mysign = "";
        switch ($this->_sign_type) {
            case "MD5":$mysign = md5Sign($prestr, $this->_md5_key);break;
            case "RSA" :$mysign = rsaSign($prestr, $this->_private_key_path);break;
            default :$mysign = "";
        }
        return $mysign;
    }
    /**
     * 生成要發送給支付寶的參數數組
     * @param $para_temp 請求前的參數數組
     * @return 要請求的參數數組
     */
    public function buildRequestPara($para_temp) {
        $para_sort = $this->filterPara($para_temp);//對待簽名參數進行過濾
        $para_sort['sign'] = $this->buildRequestMysign($para_sort);//生成簽名結果,並與簽名方式加入請求提交參數組中
        $para_sort['sign_type'] = strtoupper(trim($this->_sign_type));
        return $para_sort;
    }
}
 
        
 

 測試數據:

//1.准備要提交的字符串
$para_token = array(
		'title'=> 'app',
		'money'=>'5.60',
);
$md5 = new Submit('md5');
// 2.准備md5私鑰
$md5->_md5_key =  'd41d8cd98f00b204e9800998ecf8427e';
// 3.生成要提交的數據
$a=$md5->buildRequestPara($para_token);
echo "<pre>";
print_r($a);

//打印結果:Array ( [money] => 5.6 [title] => app [sign] => 9ae9554fac509eea96e6e8efba6846d5 [sign_type] => MD5 )

//4.假設現在服務器返回以下數據,如何驗證此數據是由服務發送的
$return = array(
		'title'=> 'app',
		'money'=>'5.60',
		'sign'=>'9ae9554fac509eea96e6e8efba6846d5',
		'sign_type'=>'MD5'
		);
	//5.按照加密流程:過濾數數組->把數組轉為字符串->生成簽名,檢查是否生成同樣的簽名
	$md5_vertiry = new Submit('md5');
	$md5_vertiry->_md5_key =  'd41d8cd98f00b204e9800998ecf8427e';
	$return = $md5_vertiry->filterPara($return);
	echo $md5_vertiry->buildRequestMysign($return)."<br/>";
	//如果生成的簽名相等,即驗證成功
	
	if($a['sign']==$md5_vertiry->buildRequestMysign($return)){
		echo "驗證成功";
	}else{
		echo "驗證失敗";
	}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM