php报文加签验签与读取证书
写在前面
在一些比较注重安全的项目中,需要对报文进行加解密,签名等操作,下面说一些这方面的概念:
- 算法:算法用来加密报文,常见的sha1,sha256等这里就不多讲了。但普通的算法加密解密是不安全的,因为报文如果被抓取,知道了算法,很轻易就可以篡改报文信息。所以就有签名,具体看以下的签名说明。
- 签名:
- 在说到签名前,得谈谈SHA1withRSA,SHA256withRSA这些算法,其实这些也是sha1、sha256加密,那为什么会有个withRSA后缀?这牵涉到RSA非对称性加密(复杂的概念不多讲,有兴趣可以自己查),简单来讲,就是双方拥有不同的钥匙,这对钥匙同时生成,分为自留的私钥和分发的公钥,都可以用来加密和解对方加密的报文。因此,他们是在sha1、sha256基础上用钥匙来加签名。
- 那为什么说签名会比较安全?因为签名的过程是这样的,本地用私钥(或公钥)对报文进行加密生成一串签名,并将签名附加到原有报文发送出去。对方接受到后,用他们本地的公钥(或者私钥)解密签名,看解密出的内容是否与报文一致,如果一致说明没问题,不一致的话emmm,说明安全堪忧啊😆。而钥匙是生成后直接派发到对应的人员和计算机上的,所以无法获取钥匙就无法解密,安全性也就提高了
- 证书和公私钥:常见的证书文件后缀有pfx(等同于.p12,是pcks#12的)、cer。cer里面一般都是存放的公钥,pfx则是同时存放私钥和公钥
php生成签名和验证签名
//读取pfx文件的方法
$cerContent=file_get_contents(__DIR__."/cert/abcdefg.pfx");
//读取pkcs文件内容到数组,其中pfx属于pcks#12
openssl_pkcs12_read($cerContent,$readCerContent,"123123");
print_r($readCerContent);
//结果如下:
//Array
//(
// [cert] => -----BEGIN CERTIFICATE-----
// 钥匙内容base64格式 * n行
//-----END CERTIFICATE-----
// [pkey] => -----BEGIN PRIVATE KEY-----
// 钥匙内容base64格式 * n行
//-----END PRIVATE KEY-----
//已知cer公钥内容则用这段读取公钥
$pubKeyCotent = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap("你的公钥内容", 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$pukey=openssl_pkey_get_public($pubKeyCotent);
/**
* @desc 私钥生成签名方法
* @param string pfxFile (包含begin和end标准格式)pfx文件绝对路径
* @param string privateKey 读取pfx文件的密码,例如123123
*/
function genPriSign($toSign, $pfxFile,$pass){
//读取x.509证书文件
$cerContent=file_get_contents($pfxFile);
//用pfx打开的密码,将pfx文件读取到数组
openssl_pkcs12_read($cerContent,$readCerContent,$pass);
//得到私钥
$pkey=openssl_pkey_get_private($readCerContent['pkey']);
//生成签名$sign,默认是sha1加密, 这里用sha256
openssl_sign($toSign,$sign,$pkey,"SHA256");
openssl_free_key($pkey);
$sign = base64_encode($sign);
return $sign;
}
//使用例子
$sign=genPriSign("test",DIR."/cer/server.pfx","123123");
echo $sign.PHP_EOL;
```php
/**
* @desc 公钥验证签名方法
* @param string sign 需要验证的签名
* @param string data 需要验证的数据
* @param string pfxFile (包含begin和end标准格式)pfx文件绝对路径
* @param string privateKey 读取pfx文件的密码,例如123123
*/
function verPubSign($sign,$data, $pfxFile,$pass){
$sign = base64_decode($sign);
$cerContent=file_get_contents($pfxFile);
openssl_pkcs12_read($cerContent,$readCerContent,$pass);
//得到公钥
$pukey=openssl_pkey_get_public($readCerContent['cert']);
$result = openssl_verify($data, $sign, $pukey, "SHA256") === 1;
return $result;
}
//使用例子
//这里的sign为上一步生成的结果
$sign="MWhI7xujNa7PshsrYCnsJH7nC+ZB60rkISqqNeNA+Me7R8qOsGqvKq25uO9uSN00OpniV0k8uIGnJ4OSchj99v9f7cfpg1gt9aqgJ64oohx0As1+S+UtO/UDK5Y2YqvOy22H386khlLVqQ1s4XtCa7x7a/xWMtpRTkbsIvu/l3xbZPG69/E8tTTMuCkXYOW89DrSk0OiHlL60hQjL69Pl1dvP5RMwWs5Bcw6XAtTLlqe3mYXYSS1ojQqzCJR4ha0yj+UudwIilN7/vow6Tmy7nKIgl7DM0WSZ2ZQqXe/xCunkRBGt5skcM2w55N+foiXLSIFuuYjbnnXJRTp8CnLgQ==";
var_dump(verPubSign($sign,"test",DIR."/cer/server.pfx","123123"));