php sm4踩坑记录
由于工作需要,需要实现多个算法对sm4的实现,并且可以互相加密解密。本来想着开源算法网上又有很多库应该问题不大,但是却走了很多弯路,记录下来以免以后再犯。
本文只记录了php和python的方法,其他方法点应该都差不多。先要感谢https://github.com/lizhichao/sm。已经实现了算法,只是有以下几个问题:
1、padding的方式是用空格的,这种跟其他语言不一样,其他语言基本都是用PKCS5Padding或者PKCS7Padding来实现的,这样就导致计算出来的内容不一致,需要修改为PKCS5Padding的话,需要修改dd函数。
private function dd(&$data)
{
$n = strlen($data) % $this->len;
$data = $data . str_repeat($this->b, $n);
}
修改为:
private function dd(&$data)
{
$n = $this->len - (strlen($data) % $this->len);
$data = $data . str_repeat(chr($n), $n);
}
2、在调用解密函数的时候没有进行删除padding操作,导致解密出来的内容与原文不一致。需要添加udd函数,并在deDataEcb时进行调用。
private function udd(&$data)
{
$n = ord($data[strlen($data) - 1]);
$data = substr($data, 0, -1 * $n);
return $data;
}
public function deDataEcb($str)
{
$r = [];
- $this->dd($str);
$ar = unpack('N*', $str);
do {
$this->decode([current($ar), next($ar), next($ar), next($ar)], $r);
} while (next($ar));
- return pack('N*', ...$r);
+ $rs = pack('N*', ...$r);
+ return $this->udd($rs);
}
3、加密后的内容为二进制无法直接查看,如果要直观查看的话可以调用hex2bin函数转换为十六进制来进行查看。
python调用sm4很简单,直接使用pip安装sm4库就可以,但是padding是默认false的,如果实际使用还是要打开
# -*- coding: utf-8 -*-
from hashlib import md5
from sm4 import SM4Key
appId = 'test'
data = 'sm4 testing encoding'
secretkey = md5(bytes(appId, encoding="utf8")).digest()
key = SM4Key(secretkey)
sm = key.encrypt(bytes(data, encoding="utf8"), padding=True)
sign = sm.hex()