From 6315b88ebae33393355544991330545c0959f73c Mon Sep 17 00:00:00 2001 From: wanghongjun <1445693971@qq,com> Date: Mon, 14 Oct 2024 16:02:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=B7=B1=E5=9C=B3=E7=A8=8E?= =?UTF-8?q?=E5=8A=A1=E6=8E=A5=E5=8F=A39?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/service/webService/ChinaTaxes.php | 8 +- app/util/Sm4.php | 205 ++++++++++++++++++++++++++ 2 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 app/util/Sm4.php diff --git a/app/service/webService/ChinaTaxes.php b/app/service/webService/ChinaTaxes.php index b8a09fd..93a03c2 100644 --- a/app/service/webService/ChinaTaxes.php +++ b/app/service/webService/ChinaTaxes.php @@ -3,6 +3,7 @@ namespace app\service\webService; use app\util\NewSm4; +use app\util\Sm4; use fast\FuncException; class ChinaTaxes @@ -398,7 +399,8 @@ xmlns:ns2="http://www.chinatax.gov.cn/dataspec/">'; // dump($xml2); - $sm4 = new NewSm4(); + //$sm4 = new NewSm4(); + $sm4 = new Sm4(); if ($type == 2) { //return $start1 . base64_encode(gzencode($xml2)) . $end; @@ -406,12 +408,12 @@ xmlns:ns2="http://www.chinatax.gov.cn/dataspec/">'; // return $start1.$xml2.$end; $gzencode = gzencode($xml2); - $sm4Code = $sm4->setKey($this->my)->encryptData($gzencode); + $sm4Code = $sm4->encrypt($this->my, $gzencode); return $start . $sm4Code . $end; } $gzencode = gzencode($xml); - $sm4Code = $sm4->setKey($this->my)->encryptData($gzencode); + $sm4Code = $sm4->encrypt($this->my, $gzencode); return $start . $sm4Code . $end; } diff --git a/app/util/Sm4.php b/app/util/Sm4.php new file mode 100644 index 0000000..d9bf4b4 --- /dev/null +++ b/app/util/Sm4.php @@ -0,0 +1,205 @@ +_Key; + } + $this->sm4KeySchedule($key); + + $bytes = $this->pad($data, $this->_block_size); + $chunks = array_chunk($bytes, $this->_block_size); + + $ciphertext = ""; + foreach ($chunks as $chunk) { + $ciphertext .= $this->sm4Encrypt($chunk); + } + + return bin2hex($ciphertext); + } + + /** + * sm4解密 + * @param $key + * @param $data + * @return bool|string + */ + public function decrypt($key = "", $data = "") + { + if (empty($key)) { + $key = $this->_Key; + } + $data = hex2bin($data); + if (strlen($data) < 0 || strlen($data) % $this->_block_size != 0) { + return false; + } + + $this->sm4KeySchedule($key); + $bytes = unpack("C*", $data); + $chunks = array_chunk($bytes, $this->_block_size); + + $plaintext = ""; + foreach ($chunks as $chunk) { + $plaintext .= substr($this->sm4Decrypt($chunk), 0, 16); + } + $plaintext = $this->unPad($plaintext); + + return $plaintext; + } + + private function sm4Decrypt($cipherText) + { + $x = []; + for ($j = 0; $j < 4; $j++) { + $x[$j] = ($cipherText[$j * 4] << 24) | ($cipherText[$j * 4 + 1] << 16) | ($cipherText[$j * 4 + 2] << 8) | ($cipherText[$j * 4 + 3]); + } + + for ($i = 0; $i < 32; $i++) { + $tmp = $x[$i + 1] ^ $x[$i + 2] ^ $x[$i + 3] ^ $this->_rk[31 - $i]; + $buf = (self::SM4_SBOX[($tmp >> 24) & 0xFF]) << 24 | (self::SM4_SBOX[($tmp >> 16) & 0xFF]) << 16 | (self::SM4_SBOX[($tmp >> 8) & 0xFF]) << 8 | (self::SM4_SBOX[$tmp & 0xFF]); + $x[$i + 4] = $x[$i] ^ ($buf ^ $this->sm4Rotl32(($buf), 2) ^ $this->sm4Rotl32(($buf), 10) ^ $this->sm4Rotl32(($buf), 18) ^ $this->sm4Rotl32(($buf), 24)); + } + + $plainText = []; + for ($k = 0; $k < 4; $k++) { + $plainText[4 * $k] = ($x[35 - $k] >> 24) & 0xFF; + $plainText[4 * $k + 1] = ($x[35 - $k] >> 16) & 0xFF; + $plainText[4 * $k + 2] = ($x[35 - $k] >> 8) & 0xFF; + $plainText[4 * $k + 3] = ($x[35 - $k]) & 0xFF; + } + + return $this->bytesToString($plainText); + } + + private function sm4Encrypt($plainText) + { + $x = []; + for ($j = 0; $j < 4; $j++) { + $x[$j] = ($plainText[$j * 4] << 24) | ($plainText[$j * 4 + 1] << 16) | ($plainText[$j * 4 + 2] << 8) | ($plainText[$j * 4 + 3]); + } + + for ($i = 0; $i < 32; $i++) { + $tmp = $x[$i + 1] ^ $x[$i + 2] ^ $x[$i + 3] ^ $this->_rk[$i]; + $buf = (self::SM4_SBOX[($tmp >> 24) & 0xFF]) << 24 | (self::SM4_SBOX[($tmp >> 16) & 0xFF]) << 16 | (self::SM4_SBOX[($tmp >> 8) & 0xFF]) << 8 | (self::SM4_SBOX[$tmp & 0xFF]); + $x[$i + 4] = $x[$i] ^ ($buf ^ $this->sm4Rotl32(($buf), 2) ^ $this->sm4Rotl32(($buf), 10) ^ $this->sm4Rotl32(($buf), 18) ^ $this->sm4Rotl32(($buf), 24)); + } + + $cipherText = []; + for ($k = 0; $k < 4; $k++) { + $cipherText[4 * $k] = ($x[35 - $k] >> 24) & 0xFF; + $cipherText[4 * $k + 1] = ($x[35 - $k] >> 16) & 0xFF; + $cipherText[4 * $k + 2] = ($x[35 - $k] >> 8) & 0xFF; + $cipherText[4 * $k + 3] = ($x[35 - $k]) & 0xFF; + } + + return $this->bytesToString($cipherText); + } + + private function stringToBytes($string) + { + return unpack('C*', $string); + } + + private function bytesToString($bytes) + { + return vsprintf(str_repeat('%c', count($bytes)), $bytes); + } + + private function pad($data) + { + $bytes = $this->stringToBytes($data); + $rem = $this->_block_size - count($bytes) % $this->_block_size; + for ($i = 0; $i < $rem; $i++) { + array_push($bytes, $rem); + } + return $bytes; + } + + private function unPad($data) + { + $bytes = $this->stringToBytes($data); + $rem = $bytes[count($bytes)]; + $bytes = array_slice($bytes, 0, count($bytes) - $rem); + return $this->bytesToString($bytes); + } + + private function sm4Rotl32($buf, $n) + { + return (($buf << $n) & 0xffffffff) | ($buf >> (32 - $n)); + } + + private function sm4KeySchedule($key) + { + $this->_rk = []; + $key = array_values(unpack("C*", $key)); + + $k = []; + for ($i = 0; $i < 4; $i++) { + $k[$i] = self::SM4_FK[$i] ^ (($key[4 * $i] << 24) | ($key[4 * $i + 1] << 16) | ($key[4 * $i + 2] << 8) | ($key[4 * $i + 3])); + } + + for ($j = 0; $j < 32; $j++) { + $tmp = $k[$j + 1] ^ $k[$j + 2] ^ $k[$j + 3] ^ self::SM4_CK[$j]; + $buf = (self::SM4_SBOX[($tmp >> 24) & 0xFF]) << 24 | (self::SM4_SBOX[($tmp >> 16) & 0xFF]) << 16 | (self::SM4_SBOX[($tmp >> 8) & 0xFF]) << 8 | (self::SM4_SBOX[$tmp & 0xFF]); + + $k[$j + 4] = $k[$j] ^ (($buf) ^ ($this->sm4Rotl32(($buf), 13)) ^ ($this->sm4Rotl32(($buf), 23))); + $this->_rk[$j] = $k[$j + 4]; + } + } +} \ No newline at end of file