Closed zhiYu2017 closed 10 months ago
你这方法弄错啦,不是 sm2签名, 正常的流程是:对接的参数使用 sm4加密, 加密的密码使用sm2公钥非对称加密,你弄成签名了,还有一个是我这缺省使用了固定中间椭圆,被招行加黑名单了, $sm2 = new RtSm2('base64',false); 构造这里第二参数设为 false , 本地测试可以设为true, 这样每次加密的值都长一样比较好调试,设为false后,同样加密串每次都不一样,不好调
按照大佬的提示修改完代码,自我加解密都是成功的,但是传给招行就是解密失败,暂时没找到原因
按照大佬的提示修改完代码,自我加解密都是成功的,但是传给招行就是解密失败,暂时没找到原因
问题1: 格式上不对呢,JAVA sm2的非对称加密中
byte[] wEncKeyByt = cipherRawToAsn1(sm2EncryptOld(wSm4Key.getBytes(), bcecPublicKey));
这个java里做了一个asn1, 为asn1(c1x,c1y, c3,c2) , 我的生成的是 c1c3c2 , 就是你在上一个已关的issue里 里的问题,所以要进行转换
2 那个 sm4 的向量,
byte[] wEncByt = GmUtil.sm4EncryptCBC(wSm4Key.getBytes(), contents[i].getBytes(), SM4_CBC_IV);
用到的向量SM4_CBC_IV, 这个得修改成与你的一致,
SM4_CBC_IV 招行的值是 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ,我处理成字符串是16个0:"0000000000000000",这个是否正确
SM4_CBC_IV 招行的值是 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ,我处理成字符串是16个0:"0000000000000000",这个是否正确
不是呢, 字符‘0’ 是\0x30 , 你可以用 $iv = str_repeat(chr(0),16)
sm4向量问题已经解决,格式转化的问题我看了demo是将asn1(c1x,c1y,c3,c2)转成c1c3c2,如何反转呢
https://github.com/lpilp/simplesm2/blob/main/src/smecc/SPLSM2/Sm2Asn1.php
function asn1_cccc($c1x, $c1y, $c3, $c2, $outFormat = 'hex')
感谢大佬,是格式的问题。只需要将sm2加密后的结果转成base64。不用将c1c3c2转成asn1(c1x,c1y,c3,c2)。 大佬上个赞助码吧,请大佬喝个咖啡。 示例代码如下
$selfPrivateKey = "1234567890123456";//自有测试密钥
$sm4CbcIv = str_repeat(chr(0x00),16);
//$privateKey = "D5F2AFA24E6BA9071B54A8C9AD735F9A1DE9C4657FA386C09B592694BC118B38";
$publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE6Q+fktsnY9OFP+LpSR5Udbxf5zHCFO0PmOKlFNTxDIGl8jsPbbB/9ET23NV+acSz4FEkzD74sW2iiNVHRLiKHg==";//招行测试公钥
$tStart = "3059301306072a8648ce3d020106082a811ccf5501822d03420004";//招行标准公钥头
$param = [
"device_type" => "###",
"device_id" => "####"
];
$paramString = json_encode($param, JSON_UNESCAPED_SLASHES);
$sm4 = new RtSm4($selfPrivateKey);
//这是SM4加密结果
$sign = $sm4->encrypt($paramString,"sm4",$sm4CbcIv,'base64');
$sm2 = new RtSm2('base64');
$bStr=base64_decode($publicKey);//base64解码公钥
$pk=bin2hex($bStr);//转16进制
//去公钥头
$pkArr=explode($tStart,$pk);
$pubKey=$pkArr[1];//实际公钥
$mySign = $sm2->doEncrypt($selfPrivateKey, $pubKey);
//需要将他转化为base64,这是数字信封结果
$mySign = base64_encode(hex2bin($mySign));
成功了就好!
测试示例代码如下 public function testSM4Key(){ $selfPrivateKey = "1234567890123456";//自有测试密钥 $sm4CbcIv = "0000000000000000";//向量值 $publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE6Q+fktsnY9OFP+LpSR5Udbxf5zHCFO0PmOKlFNTxDIGl8jsPbbB/9ET23NV+acSz4FEkzD74sW2iiNVHRLiKHg==";//招行测试公钥 $tStart = "3059301306072a8648ce3d020106082a811ccf5501822d03420004";//招行标准公钥头
这是招行提供的java版本的代码示例
//**
@return */ public static Map<String, Object> encrypt(String publicKey, String... contents) throws Exception { // 公钥信息 Sm2Vo sm2Vo = parseBase64TRawKey(publicKey); if (null == sm2Vo) { throw new IllegalArgumentException("公钥信息错误"); } BCECPublicKey bcecPublicKey = GmUtil.getPublickeyFromXY(new BigInteger(sm2Vo.getSm2_x(), 16), new BigInteger(sm2Vo.getSm2_y(), 16));
}
目前是SM4加密的值和SM2数字信封加密都和招行跑的不一致,麻烦大佬帮忙看下具体问题在哪里。谢谢。