特别声明:
本文原文出自http://bbs.yi700.com/forum.php?mod=viewthread&tid=30;只是基于此做一个补充;感谢原作者的分享
建行提供的验签DEMO,要么是java版本的;要么是NET版本的;还有sockt方式的;但是唯独没有php版本的;有的也只是一个php在win32系统中使用COM组件来实现的版本;但是很多人用的是linux版本,所以就卡带在此了。
网上查了一些资料,发现原文作者的方法是最可靠的,也是最简单省事的;(LINUX 的对COM组件不支持(听说网上有方法支持,太烦放弃)。
还有种方法是用PHP 调用JAVA的类 (PHP-Java-Bridge方法 这个这里不说自己百度)这些变向解决的方法都太麻烦)
详细说下用PHP 的openssl_verify 来验签(主要涉及到两个方面)
1.openssl_verify 需要一个PEM格式的公钥;从建行下载一个公钥(建行提供的公钥是一串字符串并且是16进制的,并且如果你每次下载都将是一个新的公钥,即下载即是更新,所以如果不是特殊情况,不要去做反复的下载操作),在自己系统保存这个公钥字符串。
2.想办法把这串16进制的公钥转成PEM格式于是百度发现没有具体的方案。现在给出php代码 通过下面的代码即可转成PEM格式;
function der2pem($public_key)
{
$pem = chunk_split(base64_encode(hex2bin($public_key)), 64, "\n");
$pem = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----\n";
return $pem;
}
/**
* 验证签名
* @param array $val 原字符串
* @param type $sign 加密串
*/
public function verifySign($val, $sign)
{
//$val即是建行返回的参数字符串(特别注意,返回的什么样保持原样,否则验签会失败)
$public_key = $this->ccb_public_key;
//公钥串转成pem格式
$public_key = der2pem($public_key);
$pkeyid = openssl_get_publickey($public_key);
$verifyResult = openssl_verify($val, pack("H" . strlen($sign), $sign), $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
return $verifyResult == 1 ? true : false;
}
3、举例说明(新建一个文件名ccbCheckSign.php):
class CCB{
//公钥(建议这里不应写死在文件中,应该根据自己系统业务从对应配置表或者文件中读取)
public $ccb_public_key = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
function der2pem($der_data)
{
$pem = chunk_split(base64_encode(hex2bin($der_data)), 64, "\n");
$pem = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----\n";
return $pem;
}
public function verifySign($val, $sign){
//$val即是建行返回的参数字符串(特别注意,返回的什么样保持原样,否则验签会失败)
//比如建行返回POSID=000000&BRANCHID=110000000&ORDERID=00320995&PAYMENT=0.01&CURCODE=01&REMARK1=test1&REMARK2=test2&SUCCESS=Y
//则$val="POSID=000000&BRANCHID=110000000&ORDERID=00320995&PAYMENT=0.01&CURCODE=01&REMARK1=test1&REMARK2=test2&SUCCESS=Y"
//这里可根据系统业务逻辑动态给$this->ccb_public_key赋值;最好的方式是在new CCB()后就给赋值;这样这里就是纯粹的签名,不涉及业务逻辑的东西
$public_key = $this->ccb_public_key;
//公钥串转成pem格式
$public_key = $this->der2pem($public_key);
$pkeyid = openssl_get_publickey($public_key);
$verifyResult = openssl_verify($val, pack("H" . strlen($sign), $sign), $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
return $verifyResult == 1 ? true : false;
}
}
?>
4.特别说明:
1.openssl_verify($data, pack("H" . strlen($sign),
$sign), $pkeyid, OPENSSL_ALGO_MD5);
//建行是采用的rsawithmd5的加密方法所有验签时要用到OPENSSL_ALGO_MD5参数并且把加密串转2进制 pack("H" .
strlen($sign), $sign)
2、签名的字符串一定是建行返回后得到的串,不要做任何的变化,就保持原样传入签名验证即可,不然会出错