现在是8.17日周日晚上11:49分. 总结下这两天一直在搞的一个事情.
起因是客户那边要做密评改造. 涉及到身份认证, 数据保密性, 数据完整性, 操作不可否认性等改造.之前一直忙于其他琐事, 周四回深圳的高铁上才开始着手这件事情.
先看了下安全厂商的PPT, 讲的云里雾里;再看看群里的聊天记录, 大概明白了点; 最后看看接口文档, 算是明白到底要干啥了. 简单来说就三个东西: 一是和ukey交互,读取证书相关东西, 然后向服务器验证. 二是调用加密&解密接口对数据库中敏感数据进行加密和解密, 三是调用签名&验签接口对数据库中特定数据做摘要计算, 再把原文和摘要一起发给接口做验证. 听起来似乎挺简单.
然后就是第一个坑是要用国密算法SM3/SM4. PHP没有直接支持相关算法, 初步打算用openssl扩展来做. 查看了下服务器系统还是centos7的, PHP是7.4.3版本, 自带的openssl 版本不支持sm3/sm4算法. 只好自己升级下openssl版本, 重新编译PHP, 测试了下支持的算法.sm3/sm4可用了.
第二个坑是安全厂商只提供了JAVA的SDK, 我得自己用PHP封装一下. 好在提供了源码和测试代码.然后就是眼花缭乱的撸代码时间, 周五一天的时间总算是理解了整个过程. 难点有两个, 一是需要基于SM3的HMAC算法来签名, 二是参与签名的的参数都是怎么来的.
PHP自带的hash_hmac 貌似不支持SM3, 用hash_hmac_algos()查看了下, 确实不支持. 第一个想法是看看JAVA是怎么实现的, 撸了一个小时后我灵光一闪, 刚好试试Trae, 然后就让他帮忙把相关java类用PHP实现下. Trae整的像模像样的, 它先自己写一个类, 然后写测试代码, 测试过程有bug, 然后自己搁哪分析bug, 改bug, 继续测试,一直重复到能正常运行, 我有点被惊艳到了. 直接拿过来trae封装的PHP类测试了下, 发现输出和JAVA 不一致, 这就尴尬了, 我本身也没有研究过密码学啊, 自己去debug有点不现实.
然后github上找找其他人有没有实现过. 结果都是如何实现SM3摘要算法的. 没有和hmac结合的. 直到发现一个大佬. 大佬说:"hmac-sm3,这个算法与hmac-sha256在hmac的算法是一样的,只是hash的算法不一样,一个是sm3,一个sha256, 没有什么特殊的注意的地方", 然后还给出了具体实现. 原来如此简单! 抄过来, 测试, 和JAVA输出一致.
function myhash( $data,$digest_algo, $binary=false){
// 这时可以是任何的hash算法,也包括了 sm3
return openssl_digest($data, $digest_algo,$binary);
}
function hmac($key, $data, $algorithm = 'sm3')
{
$blockSize = 64;
if (strlen($key) > $blockSize) {
die("please check key len");
}
$key = str_pad($key, $blockSize, chr(0x00));
$innerPad = str_repeat(chr(0x36), $blockSize);
$outerPad = str_repeat(chr(0x5C), $blockSize);
$innerKey = $key ^ $innerPad;
$inner = $innerKey . $data;
$hash = myhash( $inner,$algorithm, true);
$outerKey = $key ^ $outerPad;
$outer = $outerKey . $hash;
$hmac = myhash( $outer,$algorithm);
return $hmac;
}
那么签名参数怎么来的呢, 继续撸JAVA代码. 一直到了周日上午, 感觉差不多了, 就把整个过程用PHP封装了下. 我还不想放到服务器上测试, 因为更新到服务器实在是太麻烦了. 于是想了一个偷懒的办法, 请求地址指向服务器前置机器, 前置机器proxy到内网应用服务器, 内网应用服务器再proxy到安全厂商服务器. 我就直接在本地调试. 然而认证一直失败.
这时候我有两个想法, 要么等周一问厂商具体的签名认证过程. 要么我自己跑一跑他们的java单元测试, 把参数直接打印出来. 此时已经是周日晚上了, 给娃洗漱哄睡然后自己爬起来调试, 好在之前装过eclipse, maven 也配置过, JAVA也略懂一点, 等打印出来他的参数我才发现原来是我缺少了一个换行符. OK, 改PHP, 测试, 通过. 感觉自己又长了点脑子了.
一块大石头落地, 困扰我一个周末的事情总算解决了. 剩下的就是按照文档封装几个接口的请求参数了, 周一再弄吧. 今天先记录下, 以备后查!