.gitignore000064400000000047150736750370006552 0ustar00vendor2/ vendor/ composer.lock .vscode README.md000064400000016220150736750370006041 0ustar00# php sm2 sm3 sm4 国密算法整理 * 本项目支持php版本的国密sm2的签名算法,非对称加解密算法,sm3的hash, sm4的对称加解密,要求PHP7,打开gmp支持 * 目前如果服务器配套的使用的是openssl 1.1.1x, 目前到1.1.1.l(w) ,sm3,sm4都可以直接用openssl_xxx系列函数直接实现,不必大量的代码,不支持sm2的签名,sm2的加解密 * 该版本是基于PHP-ECC,也支持其他的椭圆算法的,依赖比较多,如果只想要简单的 sm2相关的签名,加密,可以使用本版本的简化版 https://github.com/lpilp/simplesm2 ## 安装 ``` composer require lpilp/guomi ``` > 请确保你升级到 `composer 2` 及以上版本。`PHP >=7.2`,打开gmp组件支持。 如需要使用php5.6 请使用wzhih童鞋fork修改的 https://github.com/wzhih/guomi ; ``` composer require wzhih/guomi ``` > 或是使用该项目的简化版本 https://github.com/lpilp/simplesm2 ## 使用 ### SM2 * 签名验签算法主体基于PHPECC算法架构,添加了sm2的椭圆参数, * 参考了 https://github.com/ToAnyWhere/phpsm2 童鞋的sm2验签算法,密钥生成算法 * 添加了签名算法, 支持sm2的16进制,base64公私钥的签名,验签算法 * 支持从文件中读取pem文件的签名,验签算法 * 由于 openssl没有实现sm2withsm3算法,用系统函数无法实现签名及证书的自签名分发 ### SM2签名常见问题 * 提供的私钥是base64的短串,一般直接 bin2hex(base64_decode(str)) 就是明文的密钥了 * 文件格式的密钥一般有pkcs1与pkcs8两个格式,本项目只支持pkcs1格式的密钥,使用前请先进行相关的转换,一般 pkcs8是四行,pkcs1是三行,区别见 https://www.jianshu.com/p/a428e183e72e * 关于签名的字符串的问题,有些项目会将原始字符串哈稀后,再对哈稀值进行签名,有些对这哈稀值又进行了hex2bin操作后再签名,请双方按约定的标准确定最后签名的数据值,双方保持一致即可 * 签名的结果是asn1(r,s),个别的项目签名出来的只是 r+s的字符串组合,验证签名的时候注意下。 base64的签名如果以MEU开头的(hex的话是30开头),这个是asn1的,如解开后是固定64字节(hex是 128的)是r + s 的 在src/util/SmSignFormatRS.php 有相关的转换函数,请按需使用 ### SM2非对称加密 * 添加了sm2的非对称加密的算法,但速度一般,有待优化,不能保证兼容所有语言进行加解密,目前测试了js, python的相互加解密 * sm2的加密解密算法在openssl 1.1.1的版本下自带的函数中暂无sm2的公钥私钥的加密函数,得自己实现,建议使用C,C++的算法,打包成PHP扩展的方式 * SM2的非对称加密缺省的是c1c3c2, 请使用的时候注意下,对方返回的是c1c3c2还是c1c2c3,进行相应的修改更新,还有一点就是本项目中c1前面没有04, 视对接方的需求,看是否添加\x04, v1.0.6版已对c1c3c2还是c1c2c3做了兼容,缺省是c1c3c2,添加相应的modetype后可以兼容两种模式,使用方法见 test/tsm2_encrypt.php * 如对方sm2非对称加密生成的不是c1c3c2 而是 asn1(c1x,c1y,c3,c2), 目前本项目不支持这种样式的,请先asn1解开后,拼接成 C1C3C2的形式后再调用解密函数,否则会报椭圆不匹配错误, 请自行处理 ### 关于数据格式 * sm2的缺省返回是asn1(r,s)的base64字符串 * sm2的非对称加密返回的是 c1c3c2的hex字符串 * sm3缺省hex的字符串 * sm4缺省也是hex的字符串 * 在于其他语言互通的时候请自行统一格式,以免因为格式的问题而造成运算不成功 ### SM3 * 该算法直接使用 https://github.com/ToAnyWhere/phpsm2 中sm2签名用到的匹配sm3, 未做修改 * 也可使用 openssl的函数, 详见openssl_tsm3.php * hmac-sm3,这个算法与hmac-sha256在hmac的算法是一样的,只是hash的算法不一样,一个是sm3,一个sha256, 没有什么特殊的注意的地方 ### SM4 * 该算法直接封装使用 https://github.com/lizhichao/sm 的sm4算法, 同时该项目支持 sm3,sm4 ,可以composer安装 * 由于sm4-ecb, sm4-cbc加密需要补齐,项目lizhichao/sm项目未做补齐操作,这里封装的时候,针对这两个算法做了补齐操作, 其他如sm4-ctr,sm4-cfb,sm4-ofb等,可以直接用 * 在openssl 1.1.1下可使用系统的函数,已支持sm4-cbc,sm4-cfb,sm4-ctr,sm4-ecb,sm4-ofb, 详见openssl_tsm4.php ,有一点很诡异,用yum/dnf安装的openssl只支持sm3, 如果是自己编译安装的就支持sm3,sm4 ### SM2各语言总结 * 这里封装的测试函数已与相关的js,python,java,go等都可以互签互认 * js: https://github.com/JuneAndGreen/sm-crypto 一个注意点就是: js的中文字符转成byte[]时,缺省的是unicode编码两字节,需要转成utf8的三字节编码,一个简单的方案 unescape(encodeURIComponent(str)) 然后再一个字节一个字节读就行了 * python: https://github.com/duanhongyi/gmssl 使用 pip install gmssl 安装就可 * java: https://github.com/ZZMarquis/gmhelper 注意下java中文的转码问题,getBytes("UTF-8"), 要加上编码类型, 因为 getBytes()函数的缺省编码是随操作系统的,如果是在中文版的windows中使用,缺省是GBK编码,就会出现中文的编码的问题,而造成签名无法通过 * openssl: 升到1.1.1以后,支持sm3,sm4的加解密,还不支持sm2的公私钥加解密,也不支持sm2的签名 + go: https://github.com/tjfoc/gmsm 一家做区块链的公司开源的项目,在go方面可以说是最早开源的了,https://github.com/deatil/go-cryptobin 这个是个go的宝藏项目,有各种的加解密,签名 + C#: 项目也比较少,基本是基于https://www.bouncycastle.org/ 的BC加密库(java也是基于该库),该库1.8.4后版本支持sm2,sm3,sm4,考察搜索到的几个项目,https://github.com/hz281529512/SecretTest 完整性算比较好 + C: https://github.com/guanzhi/GmSSL 北大计算机的开源项目,fork多,star也多。 + php-openssl: php7 好像支持了sm3, 在openssl1.1.1以上,可用编译的方式加入sm3,sm4的支持。 xampp套件下的php7以上的版本支持sm3, sm4的openssl_系列函数, openssl_get_md_methods() 查看是否支持sm3, openssl_get_cipher_methods() 查看是否支持sm4 ## 特别注意 * sm2的构造函数中缺省是固定了中间椭圆,目前发现个别的接入方(目前发现是招行金融平台)将这个中间椭圆私钥随机算法给加黑了, 请使用的时候 $randFixed 设为false 以及重新生成一个中间椭圆的密钥对替换原有程序的数据 ``` function __construct($formatSign='hex', $randFixed = true) { // 注意: 这个randFixed尽量取false, 如需要固定,请重新生成$foreignkey密码对 $this->adapter = RtEccFactory::getAdapter(); $this->generator = RtEccFactory::getSmCurves()->generatorSm2(); if(in_array($formatSign,$this->arrFormat)){ $this->formatSign = $formatSign; } else { $this->formatSign = 'hex'; } if(!$randFixed){ $this->useDerandomizedSignatures = false; $this->useDerandomizedEncrypt = false; } } ``` composer.json000064400000001107150736750370007302 0ustar00{ "name": "lpilp/guomi", "description": "国密sm2", "type": "library", "license": "MIT", "authors": [ { "name": "recent" } ], "minimum-stability": "stable", "require": { "php": ">=7.2", "paragonie/ecc": "^2.0" }, "autoload": { "psr-4": { "Rtgm\\": "src" }, "files": ["src/overwrite.php"] }, "repositories": { "packagist": { "type": "composer", "url": "https://mirrors.aliyun.com/composer/" } } } example/readme.txt000064400000000011150736750370010202 0ustar00见 test oid对照表.md000064400000022614150736750370011104 0ustar00```php array( '1.2.156.10197.1.301' => 'sm2', '1.2.156.10197.1.501' => 'sm3WithSM2Encryption', '1.3.14.3.2.26' => 'sha1', '2.16.840.1.101.3.4.2.1' => 'sha256', '2.16.840.1.101.3.4.2.2' => 'sha384', '2.16.840.1.101.3.4.2.3' => 'sha512', '2.16.840.1.101.3.4.2.4' => 'sha224', '1.2.840.113549.2.5' => 'md5', '1.2.840.113549.2.2' => 'md2', '1.3.36.3.2.1' => 'ripemd160', '1.2.840.113549.1.1.3' => 'MD4withRSA', '1.2.840.10045.4.1' => 'SHA1withECDSA', '1.2.840.10045.4.3.1' => 'SHA224withECDSA', '1.2.840.10045.4.3.2' => 'SHA256withECDSA', '1.2.840.10045.4.3.3' => 'SHA384withECDSA', '1.2.840.10045.4.3.4' => 'SHA512withECDSA', '1.2.840.10040.4.1' => 'dsa', '1.2.840.10040.4.3' => 'SHA1withDSA', '2.16.840.1.101.3.4.3.1' => 'SHA224withDSA', '2.16.840.1.101.3.4.3.2' => 'SHA256withDSA', '1.2.840.113549.1.1.1' => 'rsaEncryption', '2.5.4.6' => 'countryName', '2.5.4.10' => 'organization', '2.5.4.11' => 'organizationalUnit', '2.5.4.8' => 'stateOrProvinceName', '2.5.4.7' => 'locality', '2.5.4.3' => 'commonName', '2.5.29.14' => 'subjectKeyIdentifier', '2.5.29.15' => 'keyUsage', '2.5.29.17' => 'subjectAltName', '2.5.29.19' => 'basicConstraints', '2.5.29.30' => 'nameConstraints', '2.5.29.31' => 'cRLDistributionPoints', '2.5.29.32' => 'certificatePolicies', '2.5.29.35' => 'authorityKeyIdentifier', '2.5.29.36' => 'policyConstraints', '2.5.29.37' => 'extKeyUsage', '1.3.6.1.5.5.7.1.1' => 'authorityInfoAccess', '2.5.29.37.0' => 'anyExtendedKeyUsage', '1.3.6.1.5.5.7.3.1' => 'serverAuth', '1.3.6.1.5.5.7.3.2' => 'clientAuth', '1.3.6.1.5.5.7.3.3' => 'codeSigning', '1.3.6.1.5.5.7.3.4' => 'emailProtection', '1.3.6.1.5.5.7.48.3' => 'timeStamping', '1.3.6.1.5.5.7.3.9' => 'ocspSigning', '1.2.840.10045.2.1' => 'ecPublicKey', '1.2.840.10045.3.1.7' => 'secp256r1', '1.3.132.0.10' => 'secp256k1', '1.3.132.0.34' => 'secp384r1', '1.2.840.113549.1.5.13' => 'pkcs5PBES2', '1.2.840.113549.1.5.12' => 'pkcs5PBKDF2', '1.2.840.113549.3.7' => 'des-EDE3-CBC', '1.2.840.113549.1.7.1' => 'data', '1.2.840.113549.1.7.2' => 'signed-data', '1.2.840.113549.1.7.3' => 'enveloped-data', '1.2.840.113549.1.7.5' => 'digested-data', '1.2.840.113549.1.7.6' => 'encrypted-data', '1.2.840.113549.1.9.16.1.2' => 'authenticated-data', '1.2.840.113549.1.9.16.1.4' => 'tstinfo', '1.3.6.1.5.5.7' => 'pkix', '1.3.6.1.5.5.7.1' => 'pe', '1.3.6.1.5.5.7.2' => 'qt', '1.3.6.1.5.5.7.3' => 'kp', '1.3.6.1.5.5.7.48' => 'ad', '1.3.6.1.5.5.7.2.1' => 'cps', '1.3.6.1.5.5.7.2.2' => 'unotice', '1.3.6.1.5.5.7.48.1' => 'ocsp', '1.3.6.1.5.5.7.48.2' => 'caIssuers', '1.3.6.1.5.5.7.48.5' => 'caRepository', '2.5.4' => 'at', '2.5.4.41' => 'name', '2.5.4.4' => 'surname', '2.5.4.42' => 'givenName', '2.5.4.43' => 'initials', '2.5.4.44' => 'generationQualifier', '2.5.4.7' => 'localityName', '2.5.4.10' => 'organizationName', '2.5.4.11' => 'organizationalUnitName', '2.5.4.12' => 'title', '2.5.4.13' => 'description', '2.5.4.46' => 'dnQualifier', '2.5.4.5' => 'serialNumber', '2.5.4.65' => 'pseudonym', '2.5.4.17' => 'postalCode', '2.5.4.9' => 'streetAddress', '2.5.4.45' => 'uniqueIdentifier', '2.5.4.72' => 'role', '2.5.4.16' => 'postalAddress', '0.9.2342.19200300.100.1.25' => 'domainComponent', '1.2.840.113549.1.9' => 'pkcs-9', '1.2.840.113549.1.9.1' => 'emailAddress', '2.5.29' => 'ce', '2.5.29.16' => 'privateKeyUsagePeriod', '2.5.29.32.0' => 'anyPolicy', '2.5.29.33' => 'policyMappings', '2.5.29.18' => 'issuerAltName', '2.5.29.9' => 'subjectDirectoryAttributes', '1.3.6.1.5.5.7.3.1' => 'kp-serverAuth', '1.3.6.1.5.5.7.3.2' => 'kp-clientAuth', '1.3.6.1.5.5.7.3.3' => 'kp-codeSigning', '1.3.6.1.5.5.7.3.4' => 'kp-emailProtection', '1.3.6.1.5.5.7.3.8' => 'kp-timeStamping', '1.3.6.1.5.5.7.3.9' => 'kp-OCSPSigning', '2.5.29.54' => 'inhibitAnyPolicy', '2.5.29.46' => 'freshestCRL', '1.3.6.1.5.5.7.1.1' => 'pe-authorityInfoAccess', '1.3.6.1.5.5.7.1.11' => 'pe-subjectInfoAccess', '2.5.29.20' => 'cRLNumber', '2.5.29.28' => 'issuingDistributionPoint', '2.5.29.27' => 'deltaCRLIndicator', '2.5.29.21' => 'cRLReasons', '2.5.29.29' => 'certificateIssuer', '2.5.29.23' => 'holdInstructionCode', '1.2.840.10040.2' => 'holdInstruction', '1.2.840.10040.2.1' => 'holdinstruction-none', '1.2.840.10040.2.2' => 'holdinstruction-callissuer', '1.2.840.10040.2.3' => 'holdinstruction-reject', '2.5.29.24' => 'invalidityDate', '1.2.840.10040.4.3' => 'dsa-with-sha1', '1.2.840.113549.1.1' => 'pkcs-1', '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption', '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption', '1.3.14.3.2.29' => 'sha1WithRSAEncryption', '1.2.840.10046.2.1' => 'dhpublicnumber', '2.16.840.1.101.2.1.1.22' => 'keyExchangeAlgorithm', '1.2.840.10045' => 'ansi-X9-62', '1.2.840.10045.4' => 'ecSigType', '1.2.840.10045.4.1' => 'ecdsa-with-SHA1', '1.2.840.10045.1' => 'fieldType', '1.2.840.10045.1.1' => 'prime-field', '1.2.840.10045.1.2' => 'characteristic-two-field', '1.2.840.10045.1.2.3' => 'characteristic-two-basis', '1.2.840.10045.1.2.3.1' => 'gnBasis', '1.2.840.10045.1.2.3.2' => 'tpBasis', '1.2.840.10045.1.2.3.3' => 'ppBasis', '1.2.840.10045.2' => 'publicKeyType', '1.2.840.10045.3' => 'ellipticCurve', '1.2.840.10045.3.0' => 'c-TwoCurve', '1.2.840.10045.3.0.1' => 'c2pnb163v1', '1.2.840.10045.3.0.2' => 'c2pnb163v2', '1.2.840.10045.3.0.3' => 'c2pnb163v3', '1.2.840.10045.3.0.4' => 'c2pnb176w1', '1.2.840.10045.3.0.5' => 'c2pnb191v1', '1.2.840.10045.3.0.6' => 'c2pnb191v2', '1.2.840.10045.3.0.7' => 'c2pnb191v3', '1.2.840.10045.3.0.8' => 'c2pnb191v4', '1.2.840.10045.3.0.9' => 'c2pnb191v5', '1.2.840.10045.3.0.10' => 'c2pnb208w1', '1.2.840.10045.3.0.11' => 'c2pnb239v1', '1.2.840.10045.3.0.12' => 'c2pnb239v2', '1.2.840.10045.3.0.13' => 'c2pnb239v3', '1.2.840.10045.3.0.14' => 'c2pnb239v4', '1.2.840.10045.3.0.15' => 'c2pnb239v5', '1.2.840.10045.3.0.16' => 'c2pnb272w1', '1.2.840.10045.3.0.17' => 'c2pnb304w1', '1.2.840.10045.3.0.18' => 'c2pnb359v1', '1.2.840.10045.3.0.19' => 'c2pnb368w1', '1.2.840.10045.3.0.20' => 'c2pnb431r1', '1.2.840.10045.3.1' => 'primeCurve', '1.2.840.10045.3.1.1' => 'prime192v1', '1.2.840.10045.3.1.2' => 'prime192v2', '1.2.840.10045.3.1.3' => 'prime192v3', '1.2.840.10045.3.1.4' => 'prime239v1', '1.2.840.10045.3.1.5' => 'prime239v2', '1.2.840.10045.3.1.6' => 'prime239v3', '1.2.840.10045.3.1.7' => 'prime256v1', '1.2.840.113549.1.1.7' => 'RSAES-OAEP', '1.2.840.113549.1.1.9' => 'pSpecified', '1.2.840.113549.1.1.10' => 'RSASSA-PSS', '1.2.840.113549.1.1.8' => 'mgf1', '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption', '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption', '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption', '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption', '1.2.643.2.2.4' => 'GostR3411-94-with-GostR3410-94', '1.2.643.2.2.3' => 'GostR3411-94-with-GostR3410-2001', '1.2.643.2.2.20' => 'GostR3410-2001', '1.2.643.2.2.19' => 'GostR3410-94', '2.16.840.1.113730' => 'netscape', '2.16.840.1.113730.1' => 'netscape-cert-extension', '2.16.840.1.113730.1.1' => 'netscape-cert-type', '2.16.840.1.113730.1.13' => 'netscape-comment', '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url', '1.3.6.1.5.5.7.1.12' => 'logotype', '1.2.840.113533.7.65.0' => 'entrustVersInfo', '2.16.840.1.113733.1.6.9' => 'verisignPrivate', '1.2.840.113549.1.9.2' => 'unstructuredName', '1.2.840.113549.1.9.7' => 'challengePassword', '1.2.840.113549.1.9.14' => 'extensionRequest', '0.9.2342.19200300.100.1.1' => 'userid', '1.2.840.113549.1.9.15' => 's/mime', '1.2.840.113549.1.9.8' => 'unstructuredAddress', '1.2.840.113549.3.2' => 'rc2-cbc', '1.2.840.113549.3.4' => 'rc4', '1.3.14.3.2.7' => 'desCBC', '1.3.6.1.5.5.7.1.3' => 'qcStatements', '1.3.6.1.5.5.7.11.1' => 'pkixQCSyntax-v1', '1.3.6.1.5.5.7.11.2' => 'pkixQCSyntax-v2', '1.3.6.1.5.5.7.3.5' => 'ipsecEndSystem', '1.3.6.1.5.5.7.3.6' => 'ipsecTunnel', '1.3.6.1.5.5.7.3.7' => 'ipsecUser', '1.3.6.1.5.5.7.48.1' => 'OCSP', '1.3.6.1.5.5.7.9.4' => 'countryOfCitizenship', '1.3.6.1.5.5.8.2.2' => 'IPSECProtection', '2.5.4.20' => 'telephoneNumber', '2.5.4.97' => 'organizationIdentifier', ); ``` src/ecc/Curves/CurveFactory.php000064400000010103150736750370012471 0ustar00curveSm2(); } $nistFactory = self::getNistFactory($adapter); $secpFactory = self::getSecpFactory($adapter); switch ($name) { case NistCurve::NAME_P192: return $nistFactory->curve192(); case NistCurve::NAME_P224: return $nistFactory->curve224(); case NistCurve::NAME_P256: return $nistFactory->curve256(); case NistCurve::NAME_P384: return $nistFactory->curve384(); case NistCurve::NAME_P521: return $nistFactory->curve521(); case SecgCurve::NAME_SECP_112R1: return $secpFactory->curve112r1(); case SecgCurve::NAME_SECP_192K1: return $secpFactory->curve192k1(); case SecgCurve::NAME_SECP_256K1: return $secpFactory->curve256k1(); case SecgCurve::NAME_SECP_256R1: return $secpFactory->curve256r1(); case SecgCurve::NAME_SECP_384R1: return $secpFactory->curve384r1(); default: $error = new UnsupportedCurveException('Unknown curve.'); $error->setCurveName($name); throw $error; } } /** * @param string $name * @return GeneratorPoint */ public static function getGeneratorByName(string $name): GeneratorPoint { $adapter = MathAdapterFactory::getAdapter(); if($name == Sm2Curve::NAME_PSM2){ return self::getSm2Factory($adapter)->generatorSm2(); } $nistFactory = self::getNistFactory($adapter); $secpFactory = self::getSecpFactory($adapter); switch ($name) { case NistCurve::NAME_P192: return $nistFactory->generator192(); case NistCurve::NAME_P224: return $nistFactory->generator224(); case NistCurve::NAME_P256: return $nistFactory->generator256(); case NistCurve::NAME_P384: return $nistFactory->generator384(); case NistCurve::NAME_P521: return $nistFactory->generator521(); case SecgCurve::NAME_SECP_112R1: return $secpFactory->generator112r1(); case SecgCurve::NAME_SECP_192K1: return $secpFactory->generator192k1(); case SecgCurve::NAME_SECP_256K1: return $secpFactory->generator256k1(); case SecgCurve::NAME_SECP_256R1: return $secpFactory->generator256r1(); case SecgCurve::NAME_SECP_384R1: return $secpFactory->generator384r1(); default: $error = new UnsupportedCurveException('Unknown generator.'); $error->setCurveName($name); throw $error; } } /** * @param GmpMathInterface $math * @return NistCurve */ private static function getNistFactory(GmpMathInterface $math): NistCurve { return new NistCurve($math); } /** * @param GmpMathInterface $math * @return SecgCurve */ private static function getSecpFactory(GmpMathInterface $math): SecgCurve { return new SecgCurve($math); } /** * @param GmpMathInterface $math * @return Sm2 */ private static function getSm2Factory(GmpMathInterface $math): Sm2Curve { return new Sm2Curve($math); } } src/ecc/RtEccFactory.php000064400000002351150736750370011144 0ustar00 self::NIST_P192_OID, NistCurve::NAME_P224 => self::NIST_P224_OID, NistCurve::NAME_P256 => self::NIST_P256_OID, NistCurve::NAME_P384 => self::NIST_P384_OID, NistCurve::NAME_P521 => self::NIST_P521_OID, SecgCurve::NAME_SECP_112R1 => self::SECP_112R1_OID, SecgCurve::NAME_SECP_192K1 => self::SECP_192K1_OID, SecgCurve::NAME_SECP_256K1 => self::SECP_256K1_OID, SecgCurve::NAME_SECP_256R1 => self::SECP_256R1_OID, SecgCurve::NAME_SECP_384R1 => self::SECP_384R1_OID, Sm2Curve::NAME_PSM2 => self::SM2_OID, ); /** * @var array */ private static $sizeMap = array( NistCurve::NAME_P192 => 24, NistCurve::NAME_P224 => 28, NistCurve::NAME_P256 => 32, NistCurve::NAME_P384 => 48, NistCurve::NAME_P521 => 66, SecgCurve::NAME_SECP_112R1 => 14, SecgCurve::NAME_SECP_192K1 => 24, SecgCurve::NAME_SECP_256K1 => 32, SecgCurve::NAME_SECP_256R1 => 32, SecgCurve::NAME_SECP_384R1 => 48, Sm2Curve::NAME_PSM2 =>32, //sm2 也是256位的,32个字节的密码 ); /** * @return array */ public static function getNames(): array { return array_keys(self::$oidMap); } /** * @param CurveFpInterface $curve * @return int */ public static function getByteSize(CurveFpInterface $curve): int { if ($curve instanceof NamedCurveFp && array_key_exists($curve->getName(), self::$sizeMap)) { return self::$sizeMap[$curve->getName()]; } throw new UnsupportedCurveException('Unsupported curve type'); } /** * @param NamedCurveFp $curve * @return ObjectIdentifier */ public static function getCurveOid(NamedCurveFp $curve): ObjectIdentifier { if (array_key_exists($curve->getName(), self::$oidMap)) { $oidString = self::$oidMap[$curve->getName()]; return new ObjectIdentifier($oidString); } throw new UnsupportedCurveException('Unsupported curve type'); } /** * @param ObjectIdentifier $oid * @return NamedCurveFp */ public static function getCurveFromOid(ObjectIdentifier $oid): NamedCurveFp { $oidString = $oid->getContent(); $invertedMap = array_flip(self::$oidMap); if (array_key_exists($oidString, $invertedMap)) { return CurveFactory::getCurveByName($invertedMap[$oidString]); } $error = new UnsupportedCurveException('Invalid data: unsupported curve.'); $error->setOid($oidString); throw $error; } /** * @param ObjectIdentifier $oid * @return GeneratorPoint */ public static function getGeneratorFromOid(ObjectIdentifier $oid): GeneratorPoint { $oidString = $oid->getContent(); $invertedMap = array_flip(self::$oidMap); if (array_key_exists($oidString, $invertedMap)) { return CurveFactory::getGeneratorByName($invertedMap[$oidString]); } $error = new UnsupportedCurveException('Invalid data: unsupported generator.'); $error->setOid($oidString); throw $error; } } src/ecc/Sm2Curve.php000064400000003445150736750370010267 0ustar00adapter = $adapter; // echo "I am sm ecc\n"; } /** * Returns an sm2国密 curve. * * @return NamedCurveFp */ public function curveSm2(): NamedCurveFp { $p = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16); $b = gmp_init('0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16); $a = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16); $parameters = new CurveParameters(256, $p, $a, $b); return new NamedCurveFp(self::NAME_PSM2, $parameters, $this->adapter); } /** * Returns an sm2 generator. * * @param RandomNumberGeneratorInterface $randomGenerator * @return GeneratorPoint */ public function generatorSm2(RandomNumberGeneratorInterface $randomGenerator = null): GeneratorPoint { $curve = $this->curveSm2(); $order = gmp_init('0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 16); $x = gmp_init('0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7', 16); $y = gmp_init('0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0', 16); return $curve->getGenerator($x, $y, $order, $randomGenerator); } } src/ecc/Sm2Signer.php000064400000010312150736750370010421 0ustar00adapter = $adapter; } /** * @param PrivateKeyInterface $key * @param \GMP $truncatedHash - hash truncated for use in ECDSA hash算法然后truncated by 相关的椭圆字节 * @param \GMP $randomK * @return SignatureInterface */ public function sign( PrivateKeyInterface $key, \GMP $truncatedHash, \GMP $randomK ): SignatureInterface { $math = $this->adapter; $generator = $key->getPoint(); // var_dump($generator);die(); $n = $generator->getOrder(); $modMath = $math->getModularArithmetic( $n ); $prikey = $key->getSecret(); //第一二步是userid, msg 生成 trucatedhash , $count = 0; while (true) { $count++; // echo "count: $count\n"; if($count >5){ throw new \RuntimeException( 'Error: sign R or S = 0' ); } // 第三步生成随机数 $k = $math->mod( $randomK, $n ); // 第四步 计算pt1(x1,y1) = [K]G这个点 // 生成一个新的点P = kG $p1 = $generator->mul( $k ); // var_dump($p1);die(); // 第五步 计算 r = (truncatedHash + x1) mod n $r = $modMath->add($truncatedHash,$p1->getX()); // var_dump(gmp_strval($r,16));die(); $zero = gmp_init( 0, 10 ); if ( $math->equals( $r, $zero ) ) { // @todo 如报错,重来 // continue; //报错重来一次 // @todo throw new \RuntimeException( 'Error: random number R = 0' ); } // 第六步 计算 s = ((1 + d)^-1 * (k - rd)) mod n $one = gmp_init(1,10); $s1 = $math->inverseMod($math->add($one, $prikey),$n ); // print_r(gmp_strval($s1,16));die(); $s2 = $math->sub($k,$math->mul($r,$prikey)); // print_r(gmp_strval($s2,16));die(); $s = $modMath->mul($s1,$s2); // var_dump($generator->mul($s));die(); if ( $math->equals( $s, $zero ) ) { // continue; throw new \RuntimeException( 'Error: random number S = 0' ); } return new Signature( $r, $s ); } } /** * @param PublicKeyInterface $key * @param SignatureInterface $signature * @param \GMP $hash * @return bool */ public function verify( PublicKeyInterface $key, SignatureInterface $signature, \GMP $hash ): bool { $generator = $key->getGenerator(); // var_dump($generator);die(); $n = $generator->getOrder(); $r = $signature->getR(); $s = $signature->getS(); $math = $this->adapter; $one = gmp_init( 1, 10 ); if ( $math->cmp( $r, $one ) < 0 || $math->cmp( $r, $math->sub( $n, $one ) ) > 0 ) { return false; } if ( $math->cmp( $s, $one ) < 0 || $math->cmp( $s, $math->sub( $n, $one ) ) > 0 ) { return false; } // 1.2.3.4 sm3 取msg,userid的 hash值,这里直接就传过来了, $modMath = $math->getModularArithmetic( $n ); // 第五步 计算t=(r'+s')mod n $t = $modMath->add($r,$s); // // 第六步 计算(x1,y1) = [s]G + [t]PA $p1 = $generator->mul($s); // p1 = sG 是OK的与签名生成的sG一样 $p2 = $key->getPoint()->mul($t); $xy = $p1->add($p2); // // 第七步 R=(e' + x1') 验证R==r'? $v = $modMath->add($hash, $xy->getX()); return BinaryString::constantTimeCompare( $math->toString( $v ), $math->toString( $r ) ); } } src/overwrite.php000064400000000664150736750370010115 0ustar00 __DIR__ .'/ecc/Serializer/Util/CurveOidMapper.php', 'Mdanter\Ecc\Curves\CurveFactory'=>__DIR__ .'/ecc/Curves/CurveFactory.php', ); if (isset($map[$cls])) { // echo $cls . ' loaded abc '. $map[$cls]. PHP_EOL; include_once $map[$cls]; return true; } }, true, true); src/sm/RtSm2.php000064400000040065150736750370007454 0ustar00adapter = RtEccFactory::getAdapter(); $this->generator = RtEccFactory::getSmCurves()->generatorSm2(); if (in_array($formatSign, $this->arrFormat)) { $this->formatSign = $formatSign; } else { $this->formatSign = 'hex'; } if (!$randFixed) { $this->useDerandomizedSignatures = false; $this->useDerandomizedEncrypt = false; } } /** * 随机生成一对16进制明文公私钥 */ public function generatekey() { // $adapter = $this->adapter; $generator = $this->generator; //随机生成一个私钥类 $private = $generator->createPrivateKey(); //取出私钥16进制表示出来 $privateKey = $this->decHex($private->getSecret()); //取出公钥的椭圆点 $pubPoint = $private->getPublicKey()->getPoint(); //公钥上的点x, y $pubX = $this->decHex($pubPoint->getX()); $pubY = $this->decHex($pubPoint->getY()); $publicKey = '04' . $pubX . $pubY; return [$privateKey, $publicKey]; } /** * 随机生成一对PEM编码公私钥 */ public function generatePemkey() { $adapter = $this->adapter; $generator = $this->generator; $private = $generator->createPrivateKey(); $derSerializer = new DerPrivateKeySerializer($adapter); // der包 ans1编码 1 版本号 2私钥 3 oid 4 公钥 四组数据 // $der = $derSerializer->serialize( $private ); $pemSerializer = new PemPrivateKeySerializer($derSerializer); $privateKeyPem = $pemSerializer->serialize($private); $derPubSerializer = new DerPublicKeySerializer($adapter); $pemPubSerializer = new PemPublicKeySerializer($derPubSerializer); $publicKeyPem = $pemPubSerializer->serialize($private->getPublicKey()); return [$privateKeyPem, $publicKeyPem]; } /** * SM2 公钥加密算法 * * @param string $document * @param string $publicKey 如提供的base64的,可使用 bin2hex(base64_decode($publicKey)) * @return string */ public function doEncrypt($document, $publicKey, $model = C1C3C2) { $adapter = $this->adapter; $generator = $this->generator; $this->cipher = new \Rtgm\smecc\SM2\Cipher(); $arrMsg = Hex2ByteBuf::HexStringToByteArray2(bin2hex($document)); list($pubKeyX, $pubKeyY) = $this->_getKeyXY($publicKey); // $key = $this->_getPubKeyObject( $pubKeyX, $pubKeyY ); $point = new Point($adapter, $generator->getCurve(), gmp_init($pubKeyX, 16), gmp_init($pubKeyY, 16)); // 是否使用固定的中间椭圆加密, if ($this->useDerandomizedEncrypt) { $c1 = $this->cipher->initEncipher($point, $this->foreignKey); } else { $c1 = $this->cipher->initEncipher($point, null); } // print_r($c1); $arrMsg = $this->cipher->encryptBlock($arrMsg); $c2 = strtolower(Hex2ByteBuf::ByteArrayToHexString($arrMsg)); // print_R($c2);echo "\n"; $c3 = strtolower(Hex2ByteBuf::ByteArrayToHexString($this->cipher->Dofinal())); // print_r($c1.$c3.$c2); if ($model == C1C3C2) { return $c1 . $c3 . $c2; } else { return $c1 . $c2 . $c3; } } /** * SM2 私钥解密算法, * * @param string $document * @param string $privateKey 如提供的base64的,可使用 bin2hex(base64_decode($privateKey)) * @param bool $trim 是否做04开头的去除,看业务返回 * @return string */ public function doDecrypt($encryptData, $privateKey, $trim = true, $model = C1C3C2) { // $encryptData = $c1.$c3.$c2 if (substr($encryptData, 0, 2) == '04' && $trim) { $encryptData = substr($encryptData, 2); } if (strlen($privateKey) == 66 && substr($privateKey, 0, 2) == '00') { $privateKey = substr($privateKey, 2); // 个别的key 前面带着00 } $adapter = $this->adapter; $generator = $this->generator; $this->cipher = new \Rtgm\smecc\SM2\Cipher(); $c1X = substr($encryptData, 0, 64); $c1Y = substr($encryptData, strlen($c1X), 64); $c1Length = strlen($c1X) + strlen($c1Y); if ($model == C1C3C2) { $c3 = substr($encryptData, $c1Length, 64); $c2 = substr($encryptData, $c1Length + strlen($c3)); } else { $c3 = substr($encryptData, -64); $c2 = substr($encryptData, $c1Length, strlen($encryptData) - $c1Length - 64); } $p1 = new Point($adapter, $generator->getCurve(), gmp_init($c1X, 16), gmp_init($c1Y, 16)); $this->cipher->initDecipher($p1, $privateKey); $arrMsg = Hex2ByteBuf::HexStringToByteArray2($c2); $arrMsg = $this->cipher->decryptBlock($arrMsg); $document = hex2bin(Hex2ByteBuf::ByteArrayToHexString($arrMsg)); $c3_ = strtolower(Hex2ByteBuf::ByteArrayToHexString($this->cipher->Dofinal())); $c3 = strtolower($c3); if ($c3 == $c3_) { //hash签名相同, return $document; } else { return ''; } } /** * 解密ASN1(c1xc1yc3c2)格式的密文 * @param $encryptData * @param $privateKey * @param $trim * @param $model * @return string * @throws \Exception */ public function doDecryptASN1($encryptData, $privateKey, $trim = true, $model = C1C3C2): string { $newEncryptData = $this->transformANS1($encryptData); return $this->doDecrypt($newEncryptData, $privateKey, $trim, $model); } /** * 密文格式转换 ANS1(c1xc1yc3c2) -> c1c3c2 * * @param string $encryptData * @return string * @throws \Exception */ private function transformANS1(string $encryptData): string { $asn1Object = \FG\ASN1\ASNObject::fromBinary($encryptData); if (! $asn1Object instanceof \FG\ASN1\Universal\Sequence) { throw new \Exception('Invalid ASN.1 format'); } // 提取 x 和 y 坐标 $c1X = $asn1Object->getChildren()[0]->getContent(); $c1Y = $asn1Object->getChildren()[1]->getContent(); // 使用 GMP 处理大整数 $c1xHex = gmp_strval(gmp_init($c1X, 10), 16); $c1yHex = gmp_strval(gmp_init($c1Y, 10), 16); // 确保十六进制字符串长度为 64 个字符(256 位) $c1xHex = str_pad($c1xHex, 64, '0', STR_PAD_LEFT); $c1yHex = str_pad($c1yHex, 64, '0', STR_PAD_LEFT); // 提取 c3 和 c2 $c3 = $asn1Object->getChildren()[2]->getContent(); $c2 = $asn1Object->getChildren()[3]->getContent(); return $c1xHex . $c1yHex . $c3 . $c2; } /** * SM2 签名明文16进制密码, 如提供的base64的,可使用 bin2hex(base64_decode($privateKey)) * */ public function doSign($document, $privateKey, $userId = null) { if (empty($userId)) { $userId = $this->userId; } $adapter = $this->adapter; $generator = $this->generator; $algorithm = 'sha256'; $secret = gmp_init($privateKey, 16); $key = new PrivateKey($adapter, $generator, $secret); return $this->_dosign($document, $key, $adapter, $generator, $userId, $algorithm); } /** * SM2 签名pem密码 * */ public function doSignOutKey($document, $privateKeyFile, $userId = null) { if (empty($userId)) { $userId = $this->userId; } if (!file_exists($privateKeyFile)) { throw new \Exception('privatekey file not exists'); } $adapter = $this->adapter; $generator = $this->generator; //这个sha256 只是生成随机数时用到,和主体算法无关 $algorithm = 'sha256'; $pemSerializer = new PemPrivateKeySerializer(new DerPrivateKeySerializer($adapter)); $keyData = file_get_contents($privateKeyFile); $key = $pemSerializer->parse($keyData); return $this->_dosign($document, $key, $adapter, $generator, $userId, $algorithm); } protected function _dosign($document, $key, $adapter, $generator, $userId, $algorithm = 'sha256') { // $publickey = $key->getPublicKey(); $obPoint = $key->getPublicKey()->getPoint(); $pubKeyX = $adapter->decHex($obPoint->getX()); $pubKeyY = $adapter->decHex($obPoint->getY()); $hash = $this->_doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId); # Derandomized signatures are not necessary, but is avoids # the risk of a low entropy RNG, causing accidental reuse # of a k value for a different message, which leaks the # private key. if ($this->useDerandomizedSignatures) { $random = \Mdanter\Ecc\Random\RandomGeneratorFactory::getHmacRandomGenerator($key, $hash, $algorithm); } else { $random = \Mdanter\Ecc\Random\RandomGeneratorFactory::getRandomGenerator(); } $randomK = $random->generate($generator->getOrder()); $signer = new Sm2Signer($adapter); $signature = $signer->sign($key, $hash, $randomK); $serializer = new DerSignatureSerializer(); $serializedSig = $serializer->serialize($signature); if ($this->formatSign == 'hex') { return bin2hex($serializedSig); } else if ($this->formatSign == 'base64') { return base64_encode($serializedSig) . PHP_EOL; } //缺省 hex return bin2hex($serializedSig); } public function verifySign($document, $sign, $publicKey, $userId = null) { $adapter = $this->adapter; $generator = $this->generator; if (empty($userId)) { $userId = $this->userId; } if ($this->formatSign == 'hex') { $sigData = hex2bin($sign); } else if ($this->formatSign == 'base64') { $sigData = base64_decode($sign); } else { $sigData = hex2bin($sign); } // Parse signature $sigSerializer = new DerSignatureSerializer(); $sig = $sigSerializer->parse($sigData); // get hash list($pubKeyX, $pubKeyY) = $this->_getKeyXY($publicKey); $hash = $this->_doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId); // get pubkey parse $key = $this->_getPubKeyObject($pubKeyX, $pubKeyY); $signer = new Sm2Signer($adapter); return $signer->verify($key, $sig, $hash); } public function verifySignOutKey($document, $sign, $publickeyFile, $userId = null) { if (empty($userId)) { $userId = $this->userId; } if (!file_exists($publickeyFile)) { throw new \Exception('publickey file not exists'); } $adapter = $this->adapter; $generator = $this->generator; if ($this->formatSign == 'hex') { $sigData = hex2bin($sign); } else if ($this->formatSign == 'base64') { $sigData = base64_decode($sign); } else { $sigData = hex2bin($sign); } // Parse signature $sigSerializer = new DerSignatureSerializer(); $sig = $sigSerializer->parse($sigData); // Parse public key $keyData = file_get_contents($publickeyFile); $derSerializer = new DerPublicKeySerializer($adapter); $pemSerializer = new PemPublicKeySerializer($derSerializer); $key = $pemSerializer->parse($keyData); $pubKeyX = $this->decHex($key->getPoint()->getX()); $pubKeyY = $this->decHex($key->getPoint()->getY()); $hash = $this->_doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId); $signer = new Sm2Signer($adapter); return $signer->verify($key, $sig, $hash); } /** * */ protected function _doS3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId) { $hasher = new Sm2WithSm3(); $hash = $hasher->getSm3Hash($document, $pubKeyX, $pubKeyY, $generator, $userId); return gmp_init(Hex2ByteBuf::ByteArrayToHexString($hash), 16); } protected function _getKeyXY($publicKey) { if (strlen($publicKey) == 128) { $pubKeyX = substr($publicKey, 0, 64); $pubKeyY = substr($publicKey, -64); } else if (strlen($publicKey) == 130 && substr($publicKey, 0, 2) == '04') { $pubKeyX = substr($publicKey, 2, 64); $pubKeyY = substr($publicKey, -64); } else { throw new \Exception('publickey format error'); } return [$pubKeyX, $pubKeyY]; } protected function _getPubKeyObject($pubKeyX, $pubKeyY) { $generator = $this->generator; // __construct( GmpMathInterface $adapter, CurveFpInterface $curve, \GMP $x, \GMP $y, \GMP $order = null, bool $infinity = false ) $x = gmp_init($pubKeyX, 16); $y = gmp_init($pubKeyY, 16); $point = new Point($this->adapter, $generator->getCurve(), $x, $y); // __construct( GmpMathInterface $adapter, GeneratorPoint $generator, PointInterface $point ) return new PublicKey($this->adapter, $this->generator, $point); } protected function _str2hex($str) { $res = array(); for ($i = 0; $i < strlen($str); $i++) { $res[$i] = sprintf("%02x", ord($str[$i])); } return implode("", $res); } private function decHex($dec, $len = 64): string { if (gettype($dec) == 'string') { $dec = gmp_init($dec, 10); } if (gmp_cmp($dec, 0) < 0) { throw new \InvalidArgumentException('Unable to convert negative integer to string'); } $hex = gmp_strval($dec, 16); /* if (strlen($hex) % 2 != 0) { $hex = '0'.$hex; } */ $left = $len - strlen($hex); if ($left > 0) { $hex = str_repeat('0', $left) . $hex; } return $hex; } } src/sm/RtSm3.php000064400000001154150736750370007451 0ustar00BlockUpdate($msgArray, 1, sizeof($msgArray)); $sm3->DoFinal($md, 0); if($format){ return $this->_dec2hex($md); } else { return $md; } } protected function _dec2hex($md){ $res = array(); for($i=0; $ism4 = new Sm4($key); } public function encrypt($data, $type = 'sm4', $iv = '', $formatOut = 'hex') { if ($type != 'sm4-ecb') { $this->check_iv($iv); } $ret = ''; switch ($type) { case 'sm4': case 'sm4-cbc': $data = $this->mystr_pad($data, $this->keyLen); //需要补齐 $ret = $this->sm4->enDataCbc($data, $iv); break; case 'sm4-ecb': $data = $this->mystr_pad($data, $this->keyLen); //需要补齐 $ret = $this->sm4->enDataEcb($data); break; case 'sm4-ctr': $ret = $this->sm4->enDataCtr($data, $iv); break; case 'sm4-ofb': $ret = $this->sm4->enDataOfb($data, $iv); break; case 'sm4-cfb': $ret = $this->sm4->enDataCfb($data, $iv); break; default: throw new Exception('bad type'); } if ($formatOut == 'hex') { return bin2hex($ret); } else if ($formatOut == 'base64') { return base64_encode($ret); } return $ret; } public function decrypt($data, $type = 'sm4', $iv = '', $formatInput = 'hex') { if ($type != 'sm4-ecb') { $this->check_iv($iv); } if ($formatInput == 'hex') { $data = hex2bin($data); } else if ($formatInput == 'base64') { $data = base64_decode($data); } //else is raw switch ($type) { case 'sm4': case 'sm4-cbc': $ret = $this->sm4->deDataCbc($data, $iv); $ret = $this->mystr_unpad($ret); break; case 'sm4-ecb': $ret = $this->sm4->deDataEcb($data); $ret = $this->mystr_unpad($ret); break; case 'sm4-ctr': $ret = $this->sm4->deDataCtr($data, $iv); break; case 'sm4-ofb': $ret = $this->sm4->deDataOfb($data, $iv); break; case 'sm4-cfb': $ret = $this->sm4->deDataCfb($data, $iv); break; default: throw new Exception('bad type'); } return $ret; } //加密前补齐 protected function mystr_pad($data, $len = 16) { $n = $len - strlen($data) % $len; return $data . str_repeat(chr($n), $n); } // 解密后去掉补齐 protected function mystr_unpad($data) { $n = ord(substr($data, -1)); return substr($data, 0, -$n); } protected function check_iv($iv) { if (strlen($iv) != $this->ivLen) { throw new Exception('bad iv'); } } } src/smecc/SM2/Cipher.php000064400000005717150736750370011000 0ustar00sm3keybase = new SM3Digest(); $this->sm3c3 = new SM3Digest(); $p = array(); $gmp_x = $this->p2->GetX(); $x = Hex2ByteBuf::ConvertGmp2ByteArray($gmp_x); $this->sm3keybase->BlockUpdate($x, 0, sizeof($x)); $this->sm3c3->BlockUpdate($x, 0, sizeof($x)); $gmp_y = $this->p2->GetY(); $y = Hex2ByteBuf::ConvertGmp2ByteArray($gmp_y); $this->sm3keybase->BlockUpdate($y, 0, sizeof($y)); $this->ct = 1; $this->NextKey(); } public function initEncipher($userPoint, $foreignKey = null) { if (empty($foreignKey)) { $sm2 = new RtSm2(); $foreignKey = $sm2->generatekey(); } $foreignPriKey = $foreignKey[0]; $foreignPubKey = $foreignKey[1]; $this->p2 = $userPoint->mul(gmp_init($foreignPriKey, 16)); $this->reset(); return substr($foreignPubKey, -128); } public function initDecipher($userPoint, $privateKey) { $this->p2 = $userPoint->mul(gmp_init($privateKey, 16)); $this->reset(); } private function NextKey() { $sm3keycur = new SM3Digest(); $sm3keycur->setSM3Digest($this->sm3keybase); $sm3keycur->Update(($this->ct >> 24 & 0x00ff)); $sm3keycur->Update(($this->ct >> 16 & 0x00ff)); $sm3keycur->Update(($this->ct >> 8 & 0x00ff)); $sm3keycur->Update(($this->ct & 0x00ff)); $sm3keycur->DoFinal($this->key, 0); $this->keyOff = 0; $this->ct++; } public function encryptBlock($data) { $len = count($data); $this->sm3c3->BlockUpdate($data, 0, $len); // print_r($data);die(); for ($i = 0; $i < $len; $i++) { if ($this->keyOff == sizeof($this->key)) { $this->NextKey(); } $data[$i] ^= $this->key[$this->keyOff++]; } return $data; } public function decryptBlock($data) { $len = count($data); for ($i = 0; $i < $len; $i++) { if ($this->keyOff == sizeof($this->key)) $this->NextKey(); $data[$i] ^= $this->key[$this->keyOff++]; } $this->sm3c3->BlockUpdate($data, 0, $len); return $data; } public function Dofinal() { $c3 = array(); $gmp_p = $this->p2->GetY(); $p = Hex2ByteBuf::ConvertGmp2ByteArray($gmp_p); $this->sm3c3->BlockUpdate($p, 0, sizeof($p)); $this->sm3c3->DoFinal($c3, 0); $this->Reset(); return $c3; } } src/smecc/SM2/Hex2ByteBuf.php000064400000004630150736750370011646 0ustar00getPublicKeyFrom($Kx,$Ky,null); $n = 0; $incount = 0; $outcount = 0; $temp_InBuf = array(); $temp_OutBuf = array(); $inlen = strlen($InString) + 1; $outlen = ($inlen / $this::MAX_ENCLEN + 1) * $this::SM2_ADDBYTE + $inlen; $OutBuf = array(); $InBuf = array(); $InBuf=unpack("C*",$InString); $InBuf[$inlen]=0;//这样是为了保挂与其它开发语言一致 $ret = 0; $temp_inlen = 0; while ( $inlen > 0) { if ( $inlen > $this::MAX_ENCLEN) $temp_inlen = $this::MAX_ENCLEN; else $temp_inlen = $inlen; for ( $n = 0; $n < $temp_inlen; $n++) { $temp_InBuf[$n] = $InBuf[$incount + $n + 1];//注意,这里要加1,因为UNPACK后是从1开始 } $temp_OutBuf=$this->sub_EncBufBySoft($temp_InBuf, $temp_inlen, $userKey); for ( $n = 0; $n < ($temp_inlen + $this::SM2_ADDBYTE); $n++) { $OutBuf[ $outcount + $n] = $temp_OutBuf[$n]; } $inlen = $inlen - $this::MAX_ENCLEN; $incount = $incount + $this::MAX_ENCLEN; $outcount = $outcount + $this::MAX_DECLEN; } return Hex2ByteBuf::ByteArrayToHexString( $OutBuf, sizeof($OutBuf)); } private function sub_EncBufBySoft($InBuf, $InBuflen, $userKey) { $n = 0 ; $data = array(); $data = $InBuf; $cipher = new Cipher(); $c1 = $cipher->Init_enc( $userKey); $bc1[0]=4; $gmp_x = $c1->getPoint()->GetX(); $x=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_x); SM3Digest::arraycopy($x,0,$bc1,1,sizeof($x)); $gmp_y = $c1->getPoint()->GetY(); $y=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_y); SM3Digest::arraycopy($y,0,$bc1,1+32,sizeof($y)); $c1_len = sizeof($bc1); $data=$cipher->Encrypt( $data ,$InBuflen); $c3 = array(); $c3=$cipher->Dofinal( ); $OutBuf=array(); for ( $n = 0; $n < $c1_len; $n++) { $OutBuf[$n] = $bc1[ $n]; } for ( $n = 0; $n < $InBuflen; $n++) { $OutBuf[ $n + $c1_len] = $data[ $n]; } for ( $n = 0; $n < 32; $n++) { $OutBuf[ $n + $c1_len + $InBuflen] = $c3[ $n]; } return $OutBuf; } */ } src/smecc/SM2/Sm2WithSm3.php000064400000010664150736750370011443 0ustar00Update( ($len >> 8 & 0x00ff)); $sm3->Update( ($len & 0x00ff)); // userId $sm3->BlockUpdate($id, 1, sizeof($id)); // a,b $gmp_a = $generator->getCurve()->GetA(); $a=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_a); $sm3->BlockUpdate($a, 0, sizeof($a)); $gmp_b = $generator->getCurve()->GetB(); $b=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_b); $sm3->BlockUpdate($b, 0, sizeof($b)); // gx,gy $gmp_gx = $generator->GetX(); $gx=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_gx); $sm3->BlockUpdate($gx, 0, sizeof($gx)); $gmp_gy = $generator->GetY(); $gy=Hex2ByteBuf::ConvertGmp2ByteArray($gmp_gy); $sm3->BlockUpdate($gy, 0, sizeof($gy)); // x,y $bPubKeyX=array(); $bPubKeyX=Hex2ByteBuf::HexStringToByteArray($HexPubKeyX); $sm3->BlockUpdate($bPubKeyX, 0, sizeof($bPubKeyX)); $bPubKeyY=array(); $bPubKeyY=Hex2ByteBuf::HexStringToByteArray($HexPubKeyY); $sm3->BlockUpdate($bPubKeyY, 0, sizeof($bPubKeyY)); $sm3->DoFinal($md, 0); return $md; } private function GetE($z, $HashMsgValue) { $md = array(); $sm3 = new SM3Digest(); $sm3->BlockUpdate($z, 0, sizeof($z)); // byte[] p = Encoding.Default.GetBytes(msg); // sm3.BlockUpdate(p, 0, p.Length); $sm3->BlockUpdate($HashMsgValue, 0, 32); $sm3->DoFinal($md, 0); return $md; } public function GetMsgHash( $msg) { $md = array(); $sm3 = new SM3Digest(); $msgArray=unpack("C*",$msg); $sm3->BlockUpdate($msgArray, 1, sizeof($msgArray)); $sm3->DoFinal($md, 0); return $md; } private function Sm2Verify($md, $PubKeyX, $PubKeyY, $VerfiySign,$generator) { //SM2Result sm2Ret = new SM2Result(); $InSignBuf = array(); $InSignBuf=Hex2ByteBuf::HexStringToByteArray($VerfiySign); $Kx = gmp_init($PubKeyX, 16); $Ky = gmp_init($PubKeyY, 16); $PubKey = $generator->getPublicKeyFrom($Kx,$Ky,null); $r = gmp_init(substr($VerfiySign,0, 64), 16); $s = gmp_init(substr($VerfiySign,64, 64), 16); $ecc_point_g=$generator->getCurve()->getPoint($generator->GetX(), $generator->GetY()); $Sm2Ret=$this->sub_Sm2Verify($md, $PubKey , $r, $s,$ecc_point_g,$generator); if (gmp_cmp($r,$Sm2Ret)==0) { return true; } else return false; } private function sub_Sm2Verify($md, $userKey,$r, $s,$ecc_point_g,$generator) { $generator = $userKey->getGenerator(); $ecc_n = $generator->getOrder(); // e_ $md_gmp=Hex2ByteBuf::ByteArrayToHexString($md,sizeof($md)); $e =gmp_init($md_gmp,16); // t $t=gmp_add($r,$s); $t=gmp_mod($t,$ecc_n); $zero = gmp_init(0, 10); if (gmp_cmp($t,$zero)==0) return null; // x1y1 $x1y1 = $ecc_point_g->mul($s); $x1y1 = $x1y1->add($userKey->getPoint()->mul($t)); // R return gmp_mod(gmp_add($e,$x1y1->GetX()),$ecc_n); } public function YtVerfiyBySoft($id, $msg, $PubKeyX, $PubKeyY, $VerfiySign,$generator) { $Z = array(); $E = array(); $MsgHashValue = array(); $Z = $this->GetZ($id, $PubKeyX, $PubKeyY,$generator); $MsgHashValue = $this->GetMsgHash($msg); $E = $this->GetE($Z, $MsgHashValue); $IsVailSign = $this->Sm2Verify($E, $PubKeyX, $PubKeyY, $VerfiySign,$generator); return $IsVailSign; } public function getSm3Hash($msg,$PubKeyX, $PubKeyY, $generator, $userId="1234567812345678") { // sm3(z+msg) $z = $this->GetZ($userId, $PubKeyX, $PubKeyY,$generator); $md = array(); $sm3 = new SM3Digest(); $sm3->BlockUpdate($z, 0, sizeof($z)); $msgArray=unpack("C*",$msg); $sm3->BlockUpdate($msgArray, 1, sizeof($msgArray)); $sm3->DoFinal($md, 0); return $md; } } src/smecc/SM3/GeneralDigest.php000064400000004347150736750370012302 0ustar00arraycopy($t->xBuf, 0, $this->xBuf, 0, sizeof($t->xBuf)); $this->xBufOff = $t->xBufOff; $this->byteCount = $t->byteCount; } public function __construct( ) { $this->xBuf[0]=0; $this->xBuf[1]=0; $this->xBuf[2]=0; $this->xBuf[3]=0; } public function Update($input) { $this->xBuf[$this->xBufOff++] = $input; if ($this->xBufOff == sizeof($this->xBuf)) { $this->ProcessWord($this->xBuf, 0); $this->xBufOff = 0; } $this->byteCount++; } public function BlockUpdate( $input, $inOff, $length) { // // fill the current word // while (($this->xBufOff != 0) && ($length > 0)) { $this->Update($input[$inOff]); $inOff++; $length--; } // // process whole words. // while ($length > sizeof($this->xBuf)) { $this->ProcessWord($input, $inOff); $inOff += sizeof($this->xBuf); $length -= sizeof($this->xBuf); $this->byteCount += sizeof($this->xBuf); } // // load in the remainder. // while ($length > 0) { $this->Update($input[$inOff]); $inOff++; $length--; } } public function Finish() { // $bitLength = ($this->byteCount << 3); $bitLength = $this->LeftRotateLong($this->byteCount , 3); // // add the pad bytes. // $this->Update(128); while ($this->xBufOff != 0) $this->Update(0); $this->ProcessLength($bitLength); $this->ProcessBlock(); } public function Reset() { $this->byteCount = 0; $this->xBufOff = 0; $this->xBuf[0]=0; $this->xBuf[1]=0; $this->xBuf[2]=0; $this->xBuf[3]=0; } public function GetByteLength():int { return $this::BYTE_LENGTH; } } src/smecc/SM3/SM3Digest.php000064400000021650150736750370011323 0ustar00Reset(); } public function setSM3Digest($t) { parent::setGeneralDigest($t); $this->arraycopy($t->X, 0, $this->X, 0, sizeof($t->X)); $this->xOff = $t->xOff; $this->arraycopy($t->v, 0, $this->v, 0, sizeof($t->v)); } public function Reset() { parent::Reset(); $this->arraycopy(SM3Digest::$v0, 0, $this->v, 0, sizeof(SM3Digest::$v0)); $this->xOff = 0; $this->arraycopy(SM3Digest::$X0, 0, $this->X, 0, sizeof(SM3Digest::$X0)); } public static function arraycopy($InBuf,$InBufPos,&$OutBuf,$OutBufPos,$Len) { for( $n = 0 ;$n< $Len;$n++) { $OutBuf[$n + $OutBufPos] =$InBuf[$n+$InBufPos]; } } public function ProcessBlock() { $ww = $this->X; $ww_ = array(); for ($i = 16; $i < 68; $i++) { $ww[$i] = $this->P1( $ww[ $i - 16] ^ $ww[$i - 9] ^ ($this->ROTATE($ww[$i - 3], 15))) ^ ($this->ROTATE($ww[$i - 13], 7)) ^ $ww[$i - 6]; } for ($i = 0; $i < 64; $i++) { $ww_[$i] = $ww[$i] ^ $ww[$i + 4]; } $vv = $this->v; $vv_ = $this->v_; $this->arraycopy($vv, 0, $vv_, 0, sizeof($vv)); // int SS1, SS2, TT1, TT2, aaa; for ($i = 0; $i < 16; $i++) { $aaa = $this->ROTATE($vv_[0], 12); $SS1 = $this->MyAdd($aaa , $vv_[4]); $SS1 = $this->MyAdd($SS1, $this->ROTATE($this->T_00_15, $i)); $SS1 = $this->ROTATE($SS1, 7); $SS2 = $SS1 ^ $aaa; $TT1=$this->FF_00_15($vv_[0], $vv_[1], $vv_[2]); $TT1=$this->MyAdd($TT1, $vv_[3]); $TT1=$this->MyAdd($TT1, $SS2); $TT1=$this->MyAdd($TT1, $ww_[$i]); $TT2=$this->GG_00_15($vv_[4], $vv_[5], $vv_[6]); $TT2=$this->MyAdd($TT2, $vv_[7]); $TT2=$this->MyAdd($TT2, $SS1); $TT2=$this->MyAdd($TT2, $ww[$i]); $vv_[3] = $vv_[2]; $vv_[2] = $this->ROTATE($vv_[1], 9); $vv_[1] = $vv_[0]; $vv_[0] = $TT1; $vv_[7] = $vv_[6]; $vv_[6] = $this->ROTATE($vv_[5], 19); $vv_[5] = $vv_[4]; $vv_[4] = $this->P0($TT2); } for ($i = 16; $i < 64; $i++) { $aaa = $this->ROTATE($vv_[0], 12); $SS1 = $this->MyAdd($aaa , $vv_[4]); $z= $this->ROTATE($this->T_16_63, $i); $SS1 = $this->MyAdd( $SS1, $this->ROTATE($this->T_16_63, $i)); $SS1 = $this->ROTATE($SS1, 7); $SS2 = $SS1 ^ $aaa; $TT1 = $this->MyAdd($this->FF_16_63($vv_[0], $vv_[1], $vv_[2]) , $vv_[3]); $TT1 = $this->MyAdd( $TT1, $SS2); $TT1 = $this->MyAdd( $TT1, $ww_[$i]); $TT2 = $this->MyAdd($this->GG_16_63($vv_[4], $vv_[5], $vv_[6]) , $vv_[7]); $TT2 = $this->MyAdd( $TT2, $SS1); $TT2 = $this->MyAdd($TT2 , $ww[$i]); $vv_[3] = $vv_[2]; $vv_[2] = $this->ROTATE($vv_[1], 9); $vv_[1] = $vv_[0]; $vv_[0] = $TT1; $vv_[7] = $vv_[6]; $vv_[6] = $this->ROTATE($vv_[5], 19); $vv_[5] = $vv_[4]; $vv_[4] = $this->P0($TT2); } for ($i = 0; $i < 8; $i++) { $vv[$i] ^= $vv_[$i]; } $this->v=$vv; $this->v_=$vv_; // Reset $this->xOff = 0; $this->arraycopy(SM3Digest::$X0, 0, $this->X, 0, sizeof(SM3Digest::$X0)); } public function ProcessWord($in_Renamed, $inOff) { $n = $this->LeftRotateLong($in_Renamed[$inOff] , 24); $n |= $this->LeftRotateLong(($in_Renamed[++$inOff] & 0xff) , 16); $n |= $this->LeftRotateLong(($in_Renamed[++$inOff] & 0xff) , 8); $n |= ($in_Renamed[++$inOff] & 0xff); $this->X[$this->xOff] = $n; if (++$this->xOff == 16) { $this->ProcessBlock(); } } public function ProcessLength($bitLength) { if ($this->xOff > 14) { $this->ProcessBlock(); } $this->X[14] = ($this->RightRotateLong($bitLength, 32)); $this->X[15] = ($bitLength & 0xffffffff); } public function IntToBigEndian($n, &$bs, $off) { $bs[$off] = ($this->RightRotateLong($n, 24)) & 0xff; $bs[++$off] = ($this->RightRotateLong($n, 16)) & 0xff; $bs[++$off] = ($this->RightRotateLong($n, 8)) & 0xff; $bs[++$off] = ($n) & 0xff ; } public function DoFinal(&$out_Renamed, $outOff):int { $this->Finish(); for ($i = 0; $i < 8; $i++) { $this->IntToBigEndian($this->v[$i], $out_Renamed, $outOff + $i * 4); } $this->Reset(); return $this::DIGEST_LENGTH; } private function HandleSign($lValue) { $lValue = $lValue & 0xFFFFFFFF; if($lValue>=0x80000000) { $lValue=$lValue-(0xffffffff+1); } return $lValue; } private function MyAdd($A,$B) { $lValue=$this->HandleSign($A) + $this->HandleSign($B); return $this->HandleSign($lValue); } public function LeftRotateLong($lValue, $lBits ) { $lBits = $lBits % 32; $lValue=$lValue<< $lBits; $lValue=$lValue & 0xffffffff; if($lValue>=0x80000000) { $lValue=$lValue-(0xffffffff+1); } return $lValue; /* $lngSign=0; $intI=0; $mValue=0; $lBits = $lBits % 32; $mValue = $lValue; if($lBits == 0) return $mValue; For ($intI = 1 ;$intI<= $lBits;$intI++) { $lngSign = $mValue & 0x40000000; $mValue = ($mValue & 0x3FFFFFFF) * 2; if($lngSign & 0x40000000) $mValue = $mValue | 0x80000000; } return $mValue;*/ } private function RightRotateLong($lValue , $lBits) { $lngSign=0;$intI=0; $mValue =0; $mValue = $lValue; // $lBits = $lBits % 32; if( $lBits == 0 ) { return $mValue ; } if ($lValue >= 0) { if($lBits<0) $lBits= 32+ $lBits; $r = $lValue >> $lBits; } else { $t=~$lBits; if($t<0) $t= 32+ $t; // $t = $t % 32; $r= ($lValue >> $lBits) + (2 << $t); } return $r; /* For ($intI = 1 ;$intI<= $lBits;$intI++) { $lngSign = $mValue & 0x80000000; $mValue = ($mValue & 0x7FFFFFFF) / 2; if ($lngSign) $mValue = $mValue | 0x40000000; } return $mValue;*/ } private function FFj($X, $Y, $Z, $j) :int { if($j>=0 && $j<=15) { return $this->FF_00_15($X, $Y, $Z); } else { return $this->FF_16_63($X, $Y, $Z); } } private function GGj($X, $Y, $Z, $j) :int { if($j>=0 && $j<=15) { return $this->GG_00_15($X, $Y, $Z); } else { return $this->GG_16_63($X, $Y, $Z); } } private function ROTATE($X, $n):int { // $r=($this->RightRotateLong($X, (32 - $n))); //$r1=$this->LeftRotateLong($X , $n); // $r2=($X << $n); return $this->LeftRotateLong($X , $n) | ($this->RightRotateLong($X, (32 - $n))); } private function P0($X):int { $a=$this->ROTATE(($X), 9); $b= $this->ROTATE(($X), 17); return (($X) ^ $this->ROTATE(($X), 9) ^ $this->ROTATE(($X), 17)); } private function P1($X):int { return (($X) ^ $this->ROTATE(($X), 15) ^ $this->ROTATE(($X), 23)); } private static function FF_00_15($X, $Y, $Z):int { return ($X ^ $Y ^ $Z); } private static function FF_16_63($X, $Y, $Z):int { return (($X & $Y) | ($X & $Z) | ($Y & $Z)); } private static function GG_00_15($X, $Y, $Z):int { return ($X ^ $Y ^ $Z); } private static function GG_16_63($X, $Y, $Z):int { return (($X & $Y) | (~ $X & $Z)); } }src/smecc/SM4/Sm4.php000064400000023664150736750370010234 0ustar00ck16($key); $this->crk($key); } private function dd(&$data) { $n = strlen($data) % $this->len; $data = $data . str_repeat($this->b, $n); } private function ck16($str) { if (strlen($str) !== $this->len) { throw new \Exception('秘钥长度为16位'); } } private function add($v) { $arr = unpack('N*', $v); $max = 0xffffffff; $j = 1; for ($i = 4; $i > 0; $i--) { if ($arr[$i] > $max - $j) { $j = 1; $arr[$i] = 0; } else { $arr[$i] += $j; break; } } return pack('N*', ...$arr); } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function deDataCtr($str, $iv) { return $this->enDataCtr($str, $iv); } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function enDataCtr($str, $iv) { $this->ck16($iv); $r = ''; $this->dd($str); $l = strlen($str) / $this->len; for ($i = 0; $i < $l; $i++) { $s = substr($str, $i * $this->len, $this->len); $tr = []; $this->encode(array_values(unpack('N*', $iv)), $tr); $s1 = pack('N*', ...$tr); $s1 = $s1 ^ $s; $iv = $this->add($iv); $r .= $s1; } return $r; } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function enDataOfb($str, $iv) { $this->ck16($iv); $r = ''; $this->dd($str); $l = strlen($str) / $this->len; for ($i = 0; $i < $l; $i++) { $s = substr($str, $i * $this->len, $this->len); $tr = []; $this->encode(array_values(unpack('N*', $iv)), $tr); $iv = pack('N*', ...$tr); $s1 = $s ^ $iv; $r .= $s1; } return $r; } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function deDataOfb($str, $iv) { return $this->enDataOfb($str, $iv); } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function deDataCfb($str, $iv) { $this->ck16($iv); $r = ''; $this->dd($str); $l = strlen($str) / $this->len; for ($i = 0; $i < $l; $i++) { $s = substr($str, $i * $this->len, $this->len); $tr = []; $this->encode(array_values(unpack('N*', $iv)), $tr); $s1 = pack('N*', ...$tr); $s1 = $s ^ $s1; $iv = $s; $r .= $s1; } return $r; } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function enDataCfb($str, $iv) { $this->ck16($iv); $r = ''; $this->dd($str); $l = strlen($str) / $this->len; for ($i = 0; $i < $l; $i++) { $s = substr($str, $i * $this->len, $this->len); $tr = []; $this->encode(array_values(unpack('N*', $iv)), $tr); $s1 = pack('N*', ...$tr); $iv = $s ^ $s1; $r .= $iv; } return $r; } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function enDataCbc($str, $iv) { $this->ck16($iv); $r = ''; $this->dd($str); $l = strlen($str) / $this->len; for ($i = 0; $i < $l; $i++) { $s = substr($str, $i * $this->len, $this->len); $s = $iv ^ $s; $tr = []; $this->encode(array_values(unpack('N*', $s)), $tr); $iv = pack('N*', ...$tr); $r .= $iv; } return $r; } /** * @param string $str 加密字符串 * @param string $iv 初始化字符串16位 * @return string * @throws \Exception */ public function deDataCbc($str, $iv) { $this->ck16($iv); $r = ''; $this->dd($str); $l = strlen($str) / $this->len; for ($i = 0; $i < $l; $i++) { $s = substr($str, $i * $this->len, $this->len); $tr = []; $this->decode(array_values(unpack('N*', $s)), $tr); $s1 = pack('N*', ...$tr); $s1 = $iv ^ $s1; $iv = $s; $r .= $s1; } return $r; } /** * @param string $str 加密字符串 * @return string */ public function enDataEcb($str) { $r = []; $this->dd($str); $ar = unpack('N*', $str); do { $this->encode([current($ar), next($ar), next($ar), next($ar)], $r); } while (next($ar)); return pack('N*', ...$r); } /** * @param string $str 解密字符串 * @return string */ 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); } private function encode($ar, &$r) { for ($i = 0; $i < 32; $i++) { $ar[$i + 4] = $this->f($ar[$i], $ar[$i + 1], $ar[$i + 2], $ar[$i + 3], $this->rk[$i]); } $r[] = $ar[35]; $r[] = $ar[34]; $r[] = $ar[33]; $r[] = $ar[32]; } private function decode($ar, &$r) { for ($i = 0; $i < 32; $i++) { $ar[$i + 4] = $this->f($ar[$i], $ar[$i + 1], $ar[$i + 2], $ar[$i + 3], $this->rk[31 - $i]); } $r[] = $ar[35]; $r[] = $ar[34]; $r[] = $ar[33]; $r[] = $ar[32]; } private function crk($key) { $keys = array_values(unpack('N*', $key)); $keys = [ $keys[0] ^ $this->fk[0], $keys[1] ^ $this->fk[1], $keys[2] ^ $this->fk[2], $keys[3] ^ $this->fk[3] ]; for ($i = 0; $i < 32; $i++) { $this->rk[] = $keys[] = $keys[$i] ^ $this->t1($keys[$i + 1] ^ $keys[$i + 2] ^ $keys[$i + 3] ^ $this->ck[$i]); } } private function lm($a, $n) { return ($a >> (32 - $n) | (($a << $n) & 0xffffffff)); } private function f($x0, $x1, $x2, $x3, $r) { return $x0 ^ $this->t($x1 ^ $x2 ^ $x3 ^ $r); } private function s($n) { return $this->Sbox[($n & 0xff)] | $this->Sbox[(($n >> 8) & 0xff)] << 8 | $this->Sbox[(($n >> 16) & 0xff)] << 16 | $this->Sbox[(($n >> 24) & 0xff)] << 24; } private function t($n) { $b = $this->s($n); return $b ^ $this->lm($b, 2) ^ $this->lm($b, 10) ^ $this->lm($b, 18) ^ $this->lm($b, 24); } private function t1($n) { $b = $this->s($n); return $b ^ $this->lm($b, 13) ^ $this->lm($b, 23); } }src/util/FormatSign.php000064400000003574150736750370011120 0ustar00_decode_rs(base64_decode($sign)); $binR = $this->_trim_int_pad($binR); $binS = $this->_trim_int_pad($binS); $lenR = strlen($binR); $lenS = strlen($binS); $result = chr(48) . chr(2 + $lenR + 2 + $lenS) . chr(2) . chr($lenR) . $binR . chr(2) . chr($lenS) . $binS; return base64_encode($result); } /** * * * @return string */ /** * 招行的解签,没有用标准的asn1解析函数,当出现r,s的位数不足的时候就报错了,只支持rs, 31,32字节,当字节数少时强制补0吧 * * @param string $sign * @return string */ public function format_cmbc($sign){ list($binR, $binS) = $this->_decode_rs(base64_decode($sign)); while(strlen($binR)<32){ $binR = chr(0).$binR; } while(strlen($binS)<32){ $binS = chr(0).$binS; } $lenR = strlen($binR); $lenS = strlen($binS); $result = chr(48) . chr(2 + $lenR + 2 + $lenS) . chr(2) . chr($lenR) . $binR . chr(2) . chr($lenS) . $binS; return base64_encode($result); } private function _trim_int_pad($binStr) { // echo bin2hex($binStr)."\n"; //trim 0 while(ord($binStr[0])==0){ $binStr = substr($binStr,1); } // add 0 if necessary if(ord($binStr[0])>127){ $binStr = chr(0).$binStr; } // echo bin2hex($binStr)."\n"; return $binStr; } private function _decode_rs($binSign) { $rLen = ord($binSign[3]); $binR = substr($binSign, 4, $rLen); $binS = substr($binSign, (4 + $rLen + 2)); // echo bin2hex($binR) . "\n----------\n" . bin2hex($binS) . "\n"; return [$binR, $binS]; } } src/util/KeyCompress.php000064400000005322150736750370011304 0ustar00getContent(); if (is_array($content)) { $result = array(); foreach ($object as $child) { $rs = self::printObject($child, $depth + 1); $result[] = $rs; } return $result; } else { $type = $object->getType(); // $strval = $object->__toString(); // 如果是 oid的话,tostring时是取的oidText, PHPasn1没有sm2等相关的就会去调用 http://oid-info.com/get/{$oidString}的接口,然后超时0.5秒 // 这里相当于直接取get_contents(), 也是可以的 $strval = $content; if ($type == 6) { //oid $rt = self::OIDtoText($strval); } else if ($type == 2) { $rt = self::format_bigint($strval); } // else if($type==4){ // if(substr($strval,0,2)=='30') { //可以再分解 // return self::decode($strval, 'hex'); // } else { // $rt = $strval; // } // } else { $rt = $strval; } return $rt; // $name = Identifier::getShortName($type); // $name = str_replace(" ", "-", $name); // return "{$name}($type)_$rt"; } } public static function printObject2(ASNObject $object, $depth = 0) { $treeSymbol = ''; $depthString = str_repeat('─', $depth); if ($depth > 0) { $treeSymbol = '├'; } // $type = $object->getType(); $name = Identifier::getShortName($object->getType()); echo "{$treeSymbol}{$depthString}{$name}: "; $strval = $object->__toString(); $result[] = $strval; echo $object->__toString() . PHP_EOL; $content = $object->getContent(); // print_R($content); if (is_array($content)) { foreach ($object as $child) { self::printObject2($child, $depth + 1); } } } protected static function pem2der($pem_data) { $begin = "-----"; $end = "-----END"; $pem_data = substr($pem_data, strpos($pem_data, $begin, 6) + strlen($begin)); $pem_data = substr($pem_data, 0, strpos($pem_data, $end)); $der = base64_decode($pem_data); return $der; } /** * 大数都转成16进制 * * @param bigint|string $data * @return string */ protected static function format_bigint($data) { $hex = gmp_strval(gmp_init($data, 10), 16); return self::padding_one_zero($hex); } public static function padding_one_zero($hex) { if (strlen($hex) % 2 == 1) { $hex = '0' . $hex; } return $hex; } public static function padding_zero($hex, $len = 64) { $left = $len - strlen($hex); if ($left > 0) { $hex = str_repeat('0', $left) . $hex; } return $hex; } /** * from https://github.com/vakata/asn1 * * @var array */ public static $oids = array( 'sm2' => '1.2.156.10197.1.301', 'sm3WithSM2Encryption' => '1.2.156.10197.1.501', 'sha1' => '1.3.14.3.2.26', 'sha256' => '2.16.840.1.101.3.4.2.1', 'sha384' => '2.16.840.1.101.3.4.2.2', 'sha512' => '2.16.840.1.101.3.4.2.3', 'sha224' => '2.16.840.1.101.3.4.2.4', 'md5' => '1.2.840.113549.2.5', 'md2' => '1.3.14.7.2.2.1', 'ripemd160' => '1.3.36.3.2.1', 'MD4withRSA' => '1.2.840.113549.1.1.3', 'SHA1withECDSA' => '1.2.840.10045.4.1', 'SHA224withECDSA' => '1.2.840.10045.4.3.1', 'SHA256withECDSA' => '1.2.840.10045.4.3.2', 'SHA384withECDSA' => '1.2.840.10045.4.3.3', 'SHA512withECDSA' => '1.2.840.10045.4.3.4', 'dsa' => '1.2.840.10040.4.1', 'SHA1withDSA' => '1.2.840.10040.4.3', 'SHA224withDSA' => '2.16.840.1.101.3.4.3.1', 'SHA256withDSA' => '2.16.840.1.101.3.4.3.2', 'rsaEncryption' => '1.2.840.113549.1.1.1', 'countryName' => '2.5.4.6', 'organization' => '2.5.4.10', 'organizationalUnit' => '2.5.4.11', 'stateOrProvinceName' => '2.5.4.8', 'locality' => '2.5.4.7', 'commonName' => '2.5.4.3', 'subjectKeyIdentifier' => '2.5.29.14', 'keyUsage' => '2.5.29.15', 'subjectAltName' => '2.5.29.17', 'basicConstraints' => '2.5.29.19', 'nameConstraints' => '2.5.29.30', 'cRLDistributionPoints' => '2.5.29.31', 'certificatePolicies' => '2.5.29.32', 'authorityKeyIdentifier' => '2.5.29.35', 'policyConstraints' => '2.5.29.36', 'extKeyUsage' => '2.5.29.37', 'authorityInfoAccess' => '1.3.6.1.5.5.7.1.1', 'anyExtendedKeyUsage' => '2.5.29.37.0', 'serverAuth' => '1.3.6.1.5.5.7.3.1', 'clientAuth' => '1.3.6.1.5.5.7.3.2', 'codeSigning' => '1.3.6.1.5.5.7.3.3', 'emailProtection' => '1.3.6.1.5.5.7.3.4', 'timeStamping' => '1.3.6.1.5.5.7.3.8', 'ocspSigning' => '1.3.6.1.5.5.7.3.9', 'ecPublicKey' => '1.2.840.10045.2.1', 'secp256r1' => '1.2.840.10045.3.1.7', 'secp256k1' => '1.3.132.0.10', 'secp384r1' => '1.3.132.0.34', 'pkcs5PBES2' => '1.2.840.113549.1.5.13', 'pkcs5PBKDF2' => '1.2.840.113549.1.5.12', 'des-EDE3-CBC' => '1.2.840.113549.3.7', 'data' => '1.2.840.113549.1.7.1', // CMS data 'signed-data' => '1.2.840.113549.1.7.2', // CMS signed-data 'enveloped-data' => '1.2.840.113549.1.7.3', // CMS enveloped-data 'digested-data' => '1.2.840.113549.1.7.5', // CMS digested-data 'encrypted-data' => '1.2.840.113549.1.7.6', // CMS encrypted-data 'authenticated-data' => '1.2.840.113549.1.9.16.1.2', // CMS authenticated-data 'tstinfo' => '1.2.840.113549.1.9.16.1.4', // RFC3161 TSTInfo, 'pkix' => '1.3.6.1.5.5.7', 'pe' => '1.3.6.1.5.5.7.1', 'qt' => '1.3.6.1.5.5.7.2', 'kp' => '1.3.6.1.5.5.7.3', 'ad' => '1.3.6.1.5.5.7.48', 'cps' => '1.3.6.1.5.5.7.2.1', 'unotice' => '1.3.6.1.5.5.7.2.2', 'ocsp' => '1.3.6.1.5.5.7.48.1', 'caIssuers' => '1.3.6.1.5.5.7.48.2', 'timeStamping' => '1.3.6.1.5.5.7.48.3', 'caRepository' => '1.3.6.1.5.5.7.48.5', 'at' => '2.5.4', 'name' => '2.5.4.41', 'surname' => '2.5.4.4', 'givenName' => '2.5.4.42', 'initials' => '2.5.4.43', 'generationQualifier' => '2.5.4.44', 'commonName' => '2.5.4.3', 'localityName' => '2.5.4.7', 'stateOrProvinceName' => '2.5.4.8', 'organizationName' => '2.5.4.10', 'organizationalUnitName' => '2.5.4.11', 'title' => '2.5.4.12', 'description' => '2.5.4.13', 'dnQualifier' => '2.5.4.46', 'countryName' => '2.5.4.6', 'serialNumber' => '2.5.4.5', 'pseudonym' => '2.5.4.65', 'postalCode' => '2.5.4.17', 'streetAddress' => '2.5.4.9', 'uniqueIdentifier' => '2.5.4.45', 'role' => '2.5.4.72', 'postalAddress' => '2.5.4.16', 'domainComponent' => '0.9.2342.19200300.100.1.25', 'pkcs-9' => '1.2.840.113549.1.9', 'emailAddress' => '1.2.840.113549.1.9.1', 'ce' => '2.5.29', 'authorityKeyIdentifier' => '2.5.29.35', 'subjectKeyIdentifier' => '2.5.29.14', 'keyUsage' => '2.5.29.15', 'privateKeyUsagePeriod' => '2.5.29.16', 'certificatePolicies' => '2.5.29.32', 'anyPolicy' => '2.5.29.32.0', 'policyMappings' => '2.5.29.33', 'subjectAltName' => '2.5.29.17', 'issuerAltName' => '2.5.29.18', 'subjectDirectoryAttributes' => '2.5.29.9', 'basicConstraints' => '2.5.29.19', 'nameConstraints' => '2.5.29.30', 'policyConstraints' => '2.5.29.36', 'cRLDistributionPoints' => '2.5.29.31', 'extKeyUsage' => '2.5.29.37', 'anyExtendedKeyUsage' => '2.5.29.37.0', 'kp-serverAuth' => '1.3.6.1.5.5.7.3.1', 'kp-clientAuth' => '1.3.6.1.5.5.7.3.2', 'kp-codeSigning' => '1.3.6.1.5.5.7.3.3', 'kp-emailProtection' => '1.3.6.1.5.5.7.3.4', 'kp-timeStamping' => '1.3.6.1.5.5.7.3.8', 'kp-OCSPSigning' => '1.3.6.1.5.5.7.3.9', 'inhibitAnyPolicy' => '2.5.29.54', 'freshestCRL' => '2.5.29.46', 'pe-authorityInfoAccess' => '1.3.6.1.5.5.7.1.1', 'pe-subjectInfoAccess' => '1.3.6.1.5.5.7.1.11', 'cRLNumber' => '2.5.29.20', 'issuingDistributionPoint' => '2.5.29.28', 'deltaCRLIndicator' => '2.5.29.27', 'cRLReasons' => '2.5.29.21', 'certificateIssuer' => '2.5.29.29', 'holdInstructionCode' => '2.5.29.23', 'holdInstruction' => '1.2.840.10040.2', 'holdinstruction-none' => '1.2.840.10040.2.1', 'holdinstruction-callissuer' => '1.2.840.10040.2.2', 'holdinstruction-reject' => '1.2.840.10040.2.3', 'invalidityDate' => '2.5.29.24', 'md2' => '1.2.840.113549.2.2', 'md5' => '1.2.840.113549.2.5', 'sha1' => '1.3.14.3.2.26', 'dsa' => '1.2.840.10040.4.1', 'dsa-with-sha1' => '1.2.840.10040.4.3', 'pkcs-1' => '1.2.840.113549.1.1', 'rsaEncryption' => '1.2.840.113549.1.1.1', 'md2WithRSAEncryption' => '1.2.840.113549.1.1.2', 'md5WithRSAEncryption' => '1.2.840.113549.1.1.4', 'sha1WithRSAEncryption' => ['1.2.840.113549.1.1.5', '1.3.14.3.2.29'], 'dhpublicnumber' => '1.2.840.10046.2.1', 'keyExchangeAlgorithm' => '2.16.840.1.101.2.1.1.22', 'ansi-X9-62' => '1.2.840.10045', 'ecSigType' => '1.2.840.10045.4', 'ecdsa-with-SHA1' => '1.2.840.10045.4.1', 'fieldType' => '1.2.840.10045.1', 'prime-field' => '1.2.840.10045.1.1', 'characteristic-two-field' => '1.2.840.10045.1.2', 'characteristic-two-basis' => '1.2.840.10045.1.2.3', 'gnBasis' => '1.2.840.10045.1.2.3.1', 'tpBasis' => '1.2.840.10045.1.2.3.2', 'ppBasis' => '1.2.840.10045.1.2.3.3', 'publicKeyType' => '1.2.840.10045.2', 'ecPublicKey' => '1.2.840.10045.2.1', 'ellipticCurve' => '1.2.840.10045.3', 'c-TwoCurve' => '1.2.840.10045.3.0', 'c2pnb163v1' => '1.2.840.10045.3.0.1', 'c2pnb163v2' => '1.2.840.10045.3.0.2', 'c2pnb163v3' => '1.2.840.10045.3.0.3', 'c2pnb176w1' => '1.2.840.10045.3.0.4', 'c2pnb191v1' => '1.2.840.10045.3.0.5', 'c2pnb191v2' => '1.2.840.10045.3.0.6', 'c2pnb191v3' => '1.2.840.10045.3.0.7', 'c2pnb191v4' => '1.2.840.10045.3.0.8', 'c2pnb191v5' => '1.2.840.10045.3.0.9', 'c2pnb208w1' => '1.2.840.10045.3.0.10', 'c2pnb239v1' => '1.2.840.10045.3.0.11', 'c2pnb239v2' => '1.2.840.10045.3.0.12', 'c2pnb239v3' => '1.2.840.10045.3.0.13', 'c2pnb239v4' => '1.2.840.10045.3.0.14', 'c2pnb239v5' => '1.2.840.10045.3.0.15', 'c2pnb272w1' => '1.2.840.10045.3.0.16', 'c2pnb304w1' => '1.2.840.10045.3.0.17', 'c2pnb359v1' => '1.2.840.10045.3.0.18', 'c2pnb368w1' => '1.2.840.10045.3.0.19', 'c2pnb431r1' => '1.2.840.10045.3.0.20', 'primeCurve' => '1.2.840.10045.3.1', 'prime192v1' => '1.2.840.10045.3.1.1', 'prime192v2' => '1.2.840.10045.3.1.2', 'prime192v3' => '1.2.840.10045.3.1.3', 'prime239v1' => '1.2.840.10045.3.1.4', 'prime239v2' => '1.2.840.10045.3.1.5', 'prime239v3' => '1.2.840.10045.3.1.6', 'prime256v1' => '1.2.840.10045.3.1.7', 'RSAES-OAEP' => '1.2.840.113549.1.1.7', 'pSpecified' => '1.2.840.113549.1.1.9', 'RSASSA-PSS' => '1.2.840.113549.1.1.10', 'mgf1' => '1.2.840.113549.1.1.8', 'sha224WithRSAEncryption' => '1.2.840.113549.1.1.14', 'sha256WithRSAEncryption' => '1.2.840.113549.1.1.11', 'sha384WithRSAEncryption' => '1.2.840.113549.1.1.12', 'sha512WithRSAEncryption' => '1.2.840.113549.1.1.13', 'sha224' => '2.16.840.1.101.3.4.2.4', 'sha256' => '2.16.840.1.101.3.4.2.1', 'sha384' => '2.16.840.1.101.3.4.2.2', 'sha512' => '2.16.840.1.101.3.4.2.3', 'GostR3411-94-with-GostR3410-94' => '1.2.643.2.2.4', 'GostR3411-94-with-GostR3410-2001' => '1.2.643.2.2.3', 'GostR3410-2001' => '1.2.643.2.2.20', 'GostR3410-94' => '1.2.643.2.2.19', 'netscape' => '2.16.840.1.113730', 'netscape-cert-extension' => '2.16.840.1.113730.1', 'netscape-cert-type' => '2.16.840.1.113730.1.1', 'netscape-comment' => '2.16.840.1.113730.1.13', 'netscape-ca-policy-url' => '2.16.840.1.113730.1.8', 'logotype' => '1.3.6.1.5.5.7.1.12', 'entrustVersInfo' => '1.2.840.113533.7.65.0', 'verisignPrivate' => '2.16.840.1.113733.1.6.9', 'unstructuredName' => '1.2.840.113549.1.9.2', 'challengePassword' => '1.2.840.113549.1.9.7', 'extensionRequest' => '1.2.840.113549.1.9.14', 'userid' => '0.9.2342.19200300.100.1.1', 's/mime' => '1.2.840.113549.1.9.15', 'unstructuredAddress' => '1.2.840.113549.1.9.8', 'rc2-cbc' => '1.2.840.113549.3.2', 'rc4' => '1.2.840.113549.3.4', 'desCBC' => '1.3.14.3.2.7', 'qcStatements' => '1.3.6.1.5.5.7.1.3', 'pkixQCSyntax-v1' => '1.3.6.1.5.5.7.11.1', 'pkixQCSyntax-v2' => '1.3.6.1.5.5.7.11.2', 'ipsecEndSystem' => '1.3.6.1.5.5.7.3.5', 'ipsecTunnel' => '1.3.6.1.5.5.7.3.6', 'ipsecUser' => '1.3.6.1.5.5.7.3.7', 'OCSP' => '1.3.6.1.5.5.7.48.1', 'countryOfCitizenship' => '1.3.6.1.5.5.7.9.4', 'IPSECProtection' => '1.3.6.1.5.5.8.2.2', 'telephoneNumber' => '2.5.4.20', 'organizationIdentifier' => '2.5.4.97', ); public static $oidTexts = array( '1.2.156.10197.1.301' => 'sm2', '1.2.156.10197.1.501' => 'sm3WithSM2Encryption', '1.3.14.3.2.26' => 'sha1', '2.16.840.1.101.3.4.2.1' => 'sha256', '2.16.840.1.101.3.4.2.2' => 'sha384', '2.16.840.1.101.3.4.2.3' => 'sha512', '2.16.840.1.101.3.4.2.4' => 'sha224', '1.2.840.113549.2.5' => 'md5', '1.2.840.113549.2.2' => 'md2', '1.3.36.3.2.1' => 'ripemd160', '1.2.840.113549.1.1.3' => 'MD4withRSA', '1.2.840.10045.4.1' => 'SHA1withECDSA', '1.2.840.10045.4.3.1' => 'SHA224withECDSA', '1.2.840.10045.4.3.2' => 'SHA256withECDSA', '1.2.840.10045.4.3.3' => 'SHA384withECDSA', '1.2.840.10045.4.3.4' => 'SHA512withECDSA', '1.2.840.10040.4.1' => 'dsa', '1.2.840.10040.4.3' => 'SHA1withDSA', '2.16.840.1.101.3.4.3.1' => 'SHA224withDSA', '2.16.840.1.101.3.4.3.2' => 'SHA256withDSA', '1.2.840.113549.1.1.1' => 'rsaEncryption', '2.5.4.6' => 'countryName', '2.5.4.10' => 'organization', '2.5.4.11' => 'organizationalUnit', '2.5.4.8' => 'stateOrProvinceName', '2.5.4.7' => 'locality', '2.5.4.3' => 'commonName', '2.5.29.14' => 'subjectKeyIdentifier', '2.5.29.15' => 'keyUsage', '2.5.29.17' => 'subjectAltName', '2.5.29.19' => 'basicConstraints', '2.5.29.30' => 'nameConstraints', '2.5.29.31' => 'cRLDistributionPoints', '2.5.29.32' => 'certificatePolicies', '2.5.29.35' => 'authorityKeyIdentifier', '2.5.29.36' => 'policyConstraints', '2.5.29.37' => 'extKeyUsage', '1.3.6.1.5.5.7.1.1' => 'authorityInfoAccess', '2.5.29.37.0' => 'anyExtendedKeyUsage', '1.3.6.1.5.5.7.3.1' => 'serverAuth', '1.3.6.1.5.5.7.3.2' => 'clientAuth', '1.3.6.1.5.5.7.3.3' => 'codeSigning', '1.3.6.1.5.5.7.3.4' => 'emailProtection', '1.3.6.1.5.5.7.48.3' => 'timeStamping', '1.3.6.1.5.5.7.3.9' => 'ocspSigning', '1.2.840.10045.2.1' => 'ecPublicKey', '1.2.840.10045.3.1.7' => 'secp256r1', '1.3.132.0.10' => 'secp256k1', '1.3.132.0.34' => 'secp384r1', '1.2.840.113549.1.5.13' => 'pkcs5PBES2', '1.2.840.113549.1.5.12' => 'pkcs5PBKDF2', '1.2.840.113549.3.7' => 'des-EDE3-CBC', '1.2.840.113549.1.7.1' => 'data', '1.2.840.113549.1.7.2' => 'signed-data', '1.2.840.113549.1.7.3' => 'enveloped-data', '1.2.840.113549.1.7.5' => 'digested-data', '1.2.840.113549.1.7.6' => 'encrypted-data', '1.2.840.113549.1.9.16.1.2' => 'authenticated-data', '1.2.840.113549.1.9.16.1.4' => 'tstinfo', '1.3.6.1.5.5.7' => 'pkix', '1.3.6.1.5.5.7.1' => 'pe', '1.3.6.1.5.5.7.2' => 'qt', '1.3.6.1.5.5.7.3' => 'kp', '1.3.6.1.5.5.7.48' => 'ad', '1.3.6.1.5.5.7.2.1' => 'cps', '1.3.6.1.5.5.7.2.2' => 'unotice', '1.3.6.1.5.5.7.48.1' => 'ocsp', '1.3.6.1.5.5.7.48.2' => 'caIssuers', '1.3.6.1.5.5.7.48.5' => 'caRepository', '2.5.4' => 'at', '2.5.4.41' => 'name', '2.5.4.4' => 'surname', '2.5.4.42' => 'givenName', '2.5.4.43' => 'initials', '2.5.4.44' => 'generationQualifier', '2.5.4.7' => 'localityName', '2.5.4.10' => 'organizationName', '2.5.4.11' => 'organizationalUnitName', '2.5.4.12' => 'title', '2.5.4.13' => 'description', '2.5.4.46' => 'dnQualifier', '2.5.4.5' => 'serialNumber', '2.5.4.65' => 'pseudonym', '2.5.4.17' => 'postalCode', '2.5.4.9' => 'streetAddress', '2.5.4.45' => 'uniqueIdentifier', '2.5.4.72' => 'role', '2.5.4.16' => 'postalAddress', '0.9.2342.19200300.100.1.25' => 'domainComponent', '1.2.840.113549.1.9' => 'pkcs-9', '1.2.840.113549.1.9.1' => 'emailAddress', '2.5.29' => 'ce', '2.5.29.16' => 'privateKeyUsagePeriod', '2.5.29.32.0' => 'anyPolicy', '2.5.29.33' => 'policyMappings', '2.5.29.18' => 'issuerAltName', '2.5.29.9' => 'subjectDirectoryAttributes', '1.3.6.1.5.5.7.3.1' => 'kp-serverAuth', '1.3.6.1.5.5.7.3.2' => 'kp-clientAuth', '1.3.6.1.5.5.7.3.3' => 'kp-codeSigning', '1.3.6.1.5.5.7.3.4' => 'kp-emailProtection', '1.3.6.1.5.5.7.3.8' => 'kp-timeStamping', '1.3.6.1.5.5.7.3.9' => 'kp-OCSPSigning', '2.5.29.54' => 'inhibitAnyPolicy', '2.5.29.46' => 'freshestCRL', '1.3.6.1.5.5.7.1.1' => 'pe-authorityInfoAccess', '1.3.6.1.5.5.7.1.11' => 'pe-subjectInfoAccess', '2.5.29.20' => 'cRLNumber', '2.5.29.28' => 'issuingDistributionPoint', '2.5.29.27' => 'deltaCRLIndicator', '2.5.29.21' => 'cRLReasons', '2.5.29.29' => 'certificateIssuer', '2.5.29.23' => 'holdInstructionCode', '1.2.840.10040.2' => 'holdInstruction', '1.2.840.10040.2.1' => 'holdinstruction-none', '1.2.840.10040.2.2' => 'holdinstruction-callissuer', '1.2.840.10040.2.3' => 'holdinstruction-reject', '2.5.29.24' => 'invalidityDate', '1.2.840.10040.4.3' => 'dsa-with-sha1', '1.2.840.113549.1.1' => 'pkcs-1', '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption', '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption', '1.3.14.3.2.29' => 'sha1WithRSAEncryption', '1.2.840.10046.2.1' => 'dhpublicnumber', '2.16.840.1.101.2.1.1.22' => 'keyExchangeAlgorithm', '1.2.840.10045' => 'ansi-X9-62', '1.2.840.10045.4' => 'ecSigType', '1.2.840.10045.4.1' => 'ecdsa-with-SHA1', '1.2.840.10045.1' => 'fieldType', '1.2.840.10045.1.1' => 'prime-field', '1.2.840.10045.1.2' => 'characteristic-two-field', '1.2.840.10045.1.2.3' => 'characteristic-two-basis', '1.2.840.10045.1.2.3.1' => 'gnBasis', '1.2.840.10045.1.2.3.2' => 'tpBasis', '1.2.840.10045.1.2.3.3' => 'ppBasis', '1.2.840.10045.2' => 'publicKeyType', '1.2.840.10045.3' => 'ellipticCurve', '1.2.840.10045.3.0' => 'c-TwoCurve', '1.2.840.10045.3.0.1' => 'c2pnb163v1', '1.2.840.10045.3.0.2' => 'c2pnb163v2', '1.2.840.10045.3.0.3' => 'c2pnb163v3', '1.2.840.10045.3.0.4' => 'c2pnb176w1', '1.2.840.10045.3.0.5' => 'c2pnb191v1', '1.2.840.10045.3.0.6' => 'c2pnb191v2', '1.2.840.10045.3.0.7' => 'c2pnb191v3', '1.2.840.10045.3.0.8' => 'c2pnb191v4', '1.2.840.10045.3.0.9' => 'c2pnb191v5', '1.2.840.10045.3.0.10' => 'c2pnb208w1', '1.2.840.10045.3.0.11' => 'c2pnb239v1', '1.2.840.10045.3.0.12' => 'c2pnb239v2', '1.2.840.10045.3.0.13' => 'c2pnb239v3', '1.2.840.10045.3.0.14' => 'c2pnb239v4', '1.2.840.10045.3.0.15' => 'c2pnb239v5', '1.2.840.10045.3.0.16' => 'c2pnb272w1', '1.2.840.10045.3.0.17' => 'c2pnb304w1', '1.2.840.10045.3.0.18' => 'c2pnb359v1', '1.2.840.10045.3.0.19' => 'c2pnb368w1', '1.2.840.10045.3.0.20' => 'c2pnb431r1', '1.2.840.10045.3.1' => 'primeCurve', '1.2.840.10045.3.1.1' => 'prime192v1', '1.2.840.10045.3.1.2' => 'prime192v2', '1.2.840.10045.3.1.3' => 'prime192v3', '1.2.840.10045.3.1.4' => 'prime239v1', '1.2.840.10045.3.1.5' => 'prime239v2', '1.2.840.10045.3.1.6' => 'prime239v3', '1.2.840.10045.3.1.7' => 'prime256v1', '1.2.840.113549.1.1.7' => 'RSAES-OAEP', '1.2.840.113549.1.1.9' => 'pSpecified', '1.2.840.113549.1.1.10' => 'RSASSA-PSS', '1.2.840.113549.1.1.8' => 'mgf1', '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption', '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption', '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption', '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption', '1.2.643.2.2.4' => 'GostR3411-94-with-GostR3410-94', '1.2.643.2.2.3' => 'GostR3411-94-with-GostR3410-2001', '1.2.643.2.2.20' => 'GostR3410-2001', '1.2.643.2.2.19' => 'GostR3410-94', '2.16.840.1.113730' => 'netscape', '2.16.840.1.113730.1' => 'netscape-cert-extension', '2.16.840.1.113730.1.1' => 'netscape-cert-type', '2.16.840.1.113730.1.13' => 'netscape-comment', '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url', '1.3.6.1.5.5.7.1.12' => 'logotype', '1.2.840.113533.7.65.0' => 'entrustVersInfo', '2.16.840.1.113733.1.6.9' => 'verisignPrivate', '1.2.840.113549.1.9.2' => 'unstructuredName', '1.2.840.113549.1.9.7' => 'challengePassword', '1.2.840.113549.1.9.14' => 'extensionRequest', '0.9.2342.19200300.100.1.1' => 'userid', '1.2.840.113549.1.9.15' => 's/mime', '1.2.840.113549.1.9.8' => 'unstructuredAddress', '1.2.840.113549.3.2' => 'rc2-cbc', '1.2.840.113549.3.4' => 'rc4', '1.3.14.3.2.7' => 'desCBC', '1.3.6.1.5.5.7.1.3' => 'qcStatements', '1.3.6.1.5.5.7.11.1' => 'pkixQCSyntax-v1', '1.3.6.1.5.5.7.11.2' => 'pkixQCSyntax-v2', '1.3.6.1.5.5.7.3.5' => 'ipsecEndSystem', '1.3.6.1.5.5.7.3.6' => 'ipsecTunnel', '1.3.6.1.5.5.7.3.7' => 'ipsecUser', '1.3.6.1.5.5.7.48.1' => 'OCSP', '1.3.6.1.5.5.7.9.4' => 'countryOfCitizenship', '1.3.6.1.5.5.8.2.2' => 'IPSECProtection', '2.5.4.20' => 'telephoneNumber', '2.5.4.97' => 'organizationIdentifier', ); /** * from https://github.com/vakata/asn1 * * @param string $id * @return string */ public static function OIDtoText($id) { // echo $id."\n"; $text = self::$oidTexts[$id] ?? $id; return $text; } /** * from https://github.com/vakata/asn1 * * @param string $text * @return string */ public static function TextToOID($text) { $res = static::$oids[$text] ?? null; if (is_array($res)) { $res = $res[0]; } return $res ?? $text; } } function getMillisecond() { list($microsecond, $time) = explode(' ', microtime()); //' '中间是一个空格 return (float)sprintf('%.0f', (floatval($microsecond) + floatval($time)) * 1000); } src/util/SmSignFormatRS.php000064400000004347150736750370011664 0ustar00getContent());die(); $r = self::_padding_zero(self::_format_bigint($arr[0]->getContent())); $s = self::_padding_zero(self::_format_bigint($arr[1]->getContent())); return base64_encode($r . $s); } protected static function _format_bigint($data) { $hex = gmp_strval(gmp_init($data, 10), 16); return $hex; } /** * rs要固定长度,经测试会有1%的概率出现长度短的,要补0 * * @param string $hex * @return string */ protected static function _padding_zero($hex) { $len = 64; // r,s都是32字节 $left = $len - strlen($hex); if ($left > 0) { $hex = str_repeat('0', $left) . $hex; } return hex2bin($hex); } /** * r+s ==> asn1(r+s) * * @param string $str * @param string $format * @return string */ public static function rs_to_asn1($str, $format = 'base64') { if ($format == 'base64') { $str = base64_decode($str); } else if ($format == 'hex') { $str = hex2bin($str); } $binR = self::_trim_int_pad(substr($str, 0, 32)); $binS = self::_trim_int_pad(substr($str, 32)); $lenR = strlen($binR); $lenS = strlen($binS); $result = chr(48) . chr(2 + $lenR + 2 + $lenS) . chr(2) . chr($lenR) . $binR . chr(2) . chr($lenS) . $binS; return base64_encode($result); } /** * 去掉多余的0 * * @param string $binStr * @return string */ protected static function _trim_int_pad($binStr) { //trim 0 while (ord($binStr[0]) == 0) { $binStr = substr($binStr, 1); } // add 0 if necessary if (ord($binStr[0]) > 127) { $binStr = chr(0) . $binStr; } // echo bin2hex($binStr)."\n"; return $binStr; } } test/data/rsa.pem000064400000001624150736750370007744 0ustar00-----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALjnVY4j/UG0tJ5o HZclp1R1+HsCQmUctzPiN5VO56ZYuFP4T3oDhVkmWReL52WGaKYGrxJymqM6mPt8 C3AXNd/KGTpZtXaoBvjK21nPmgDpo6m5nifi+IQTXmjrwDPErr0yIrAvDMP+3wQl w/WJTXVMJb074bYpytmx9WXL2mRTAgMBAAECgYB8/TuTKvbOTKXvkne2LWjQKjK+ jAdvrBqXQurJzh2/D6gCcw7ebrTcT5TX2uWfdl0VJd2AfeHURw8UqIRe0AHEzj98 yLF4DNgJRbGLCbJm67idyt41E+jnc6zrboLmpOkQ0njYibNulqgbJQ2DaFhnoLI1 1CoPW383WxUfV6LquQJBAPLbtfPs+tKrun7zOaJ0GWMYRZBFxVNKE9EQS4X2pg+g NHo+b3bNPPoE66Ug+D69R1AYKC7QkP/zvXqT8dC1UVcCQQDC6MjeJqX4M4C9sfm6 x75VqmKNX6qaXzv28wrtMk7anSiR7YQUCs0kchHQz8hpYb+SQio4DhRYJyDHnO+f V/tlAkEAl33IbYVpHNs0tZYhYJ4NbAwq8IklQwRVgjco9ULbaankslCaFUCHhepl 2BbN480MXAEFp9ZAbPjtPDZnRGqmdwJARxy1hM/nCAqKcyuHKM2NtSWoNVptHUuX zj7YgrgzKvHiBnP5F3Lla+GufFgDD+fZBFzdmHwSkiMcg5fPmXx5PQJAfKdeiisM 1qDcCIFgHSD8JX3Di/oKPF/zyZ3dgFDC8SfqHh/0UuF3WBNUFHpHCO8CoZS/QioK YKN9KVMfaZThsw== -----END PRIVATE KEY----- test/data/rsapub.pem000064400000000420150736750370010444 0ustar00-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC451WOI/1BtLSeaB2XJadUdfh7 AkJlHLcz4jeVTuemWLhT+E96A4VZJlkXi+dlhmimBq8ScpqjOpj7fAtwFzXfyhk6 WbV2qAb4yttZz5oA6aOpuZ4n4viEE15o68AzxK69MiKwLwzD/t8EJcP1iU11TCW9 O+G2KcrZsfVly9pkUwIDAQAB -----END PUBLIC KEY----- test/data/sm2.pem000064400000000342150736750370007654 0ustar00-----BEGIN EC PRIVATE KEY----- MHcCAQEEIDMLq58c/Ox37b0NA4Ok65BcRRG+OmF1O+LtAIwRvmm8oAoGCCqBHM9V AYItoUQDQgAEyqo4GGHqDU6XIBpDCzEfi7Z2EpUzmU/s46pJioQkd7tNYAb3Em2J JJRFMK4l6WPlGze3zC66NaRZuyBagjDiVQ== -----END EC PRIVATE KEY-----test/data/sm2_cs8.pem000064400000000401150736750370010425 0ustar00-----BEGIN PRIVATE KEY----- MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgHaEvjmM9ZMt0xCHT Y65RBRkWxY9bBfl/Fag0bvP1r9OgCgYIKoEcz1UBgi2hRANCAATQeZSDbPzUA57d UZTQBjdiY36CNk6ecsEuMvG3XpNxoJzome32RDEUkDc/qihPAmHaK48SCuVaoG5B Hk+QBDaJ -----END PRIVATE KEY-----test/data/sm2pub.pem000064400000000261150736750370010363 0ustar00-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEyqo4GGHqDU6XIBpDCzEfi7Z2EpUz mU/s46pJioQkd7tNYAb3Em2JJJRFMK4l6WPlGze3zC66NaRZuyBagjDiVQ== -----END PUBLIC KEY-----test/openssl_encryptsm2.php000064400000001716150736750370012127 0ustar00 OPENSSL_KEYTYPE_EC, "curve_name" => "SM2" ); $sslconf = "/usr/local/php/extras/openssl/openssl.cnf"; $config['config'] = $sslconf; $prikey = openssl_pkey_new($config); openssl_pkey_export($prikey, $prikeypem,null,$config); echo $prikeypem."\n"; $pubkeypem = openssl_pkey_get_details($prikey)["key"]; echo $pubkeypem."\n"; test/openssl_tsm3.php000064400000000104150736750370010675 0ustar00run($badSign); echo $newSign."\n"; if ($newSign == $goodSign) { echo "OK"; } else { echo "Bad"; } echo "\n=========\n"; //good 补0, $goodSign2 = "MEMCHx7T5iZF+kfk0mNDxVOX2ZOytWjcFBDCRMyUZsvdk\/8CICOZz0A91TlSbZWAhs8J24nWT35l1Su8zegr+vomI9P+"; echo (bin2hex(base64_decode($goodSign2))); echo "\n"; $newSign2 = $fs->format_cmbc($goodSign2); echo (bin2hex(base64_decode($newSign2)));test/tsm2.php000064400000003060150736750370007135 0ustar00generatekey()); //生成明文密钥 echo "\n----------生成pem密钥对--------------------------\n"; print_r($sm2->generatePemkey()); //生成pem密钥,请放到相应的文件中 } if(SIGN){ echo "\n---------明文密钥签名---------------------------\n"; $sign = $sm2->doSign( $document, $privateKey, $userId); print_r($sign); echo "\n---------明文密钥验签---------------------------\n"; var_dump($sm2->verifySign( $document, $sign, $publicKey, $userId )); } if(SIGNPEM){ echo "\n---------PEM密钥签名---------------------------\n"; $sign = $sm2->doSignOutKey( $document, $privatefile, $userId); print_r($sign); echo "\n---------PEM密钥验签---------------------------\n"; var_dump($sm2->verifySignOutKey( $document, $sign, $publicfile, $userId )); } test/tsm2_encrypt.php000064400000003564150736750370010712 0ustar00doEncrypt($document, $publicKey); echo ("\n加密后: ".$m2EncryptData); $m2DecryptData = $sm2->doDecrypt($m2EncryptData,$privateKey); echo ("\n解密后:".$m2DecryptData); echo "\n------------------------------------------------------------------\n"; $document = "我爱你ILOVEYOU!"; echo "\n原始: $document"; $m2EncryptData = $sm2 ->doEncrypt($document, $publicKey); echo ("\n加密后: ".$m2EncryptData); $m2DecryptData = $sm2->doDecrypt($m2EncryptData,$privateKey); echo ("\n解密后: ".$m2DecryptData); echo "\n------------------以上是标准的 c1c3c2 串----------------------------\n"; // define("C1C3C2",1); // define("C1C2C3",0); // doEncrypt($document, $publicKey, $model = C1C3C2), // trim是如果加密后前面带着04就去掉 // doDecrypt($encryptData,$privateKey,$trim = true,$model = C1C3C2) echo "\n------------------以下是使用 c1c2c3 串可对比上面生成------------------\n"; $document = "我爱你ILOVEYOU!"; echo "\n原始: $document"; $m2EncryptData = $sm2 ->doEncrypt($document, $publicKey,C1C2C3); echo ("\n加密后: ".$m2EncryptData); $m2DecryptData = $sm2->doDecrypt($m2EncryptData,$privateKey,1,C1C2C3); echo ("\n解密后: ".$m2DecryptData); test/tsm3.php000064400000000221150736750370007132 0ustar00digest($data,1));test/tsm4.php000064400000002440150736750370007140 0ustar00encrypt($data, $type = 'sm4', $iv = '', $format = 'hex') // openssl_encrypt ,和服务器openssl版本,PHP版本有关,有些服务器可能不支持sm4-* 相关的对称加密算法, echo "==== test sm4 sm4-cbc============"; echo "\nphp sm4: ".$hex = $sm4->encrypt($data,'sm4',$iv); //default is cbc echo "\nphp decode: ".$sm4->decrypt($hex,'sm4',$iv,'hex'); echo "\n==== test sm4-ecb============"; echo "\nphp sm4-ecb: ".$hex = $sm4->encrypt($data,'sm4-ecb'); echo "\nphp decode: ".$sm4->decrypt($hex,'sm4-ecb','','hex'); echo "\n==== test sm4-ofb============"; echo "\nphp sm4-ofb: ".$hex = $sm4->encrypt($data,'sm4-ofb',$iv); echo "\nphp decode: ".$sm4->decrypt($hex,'sm4-ofb',$iv,'hex'); echo "\n==== test sm4-cfb============"; echo "\nphp sm4-cfb: ".$hex = $sm4->encrypt($data,'sm4-cfb',$iv); echo "\nphp decode: ".$sm4->decrypt($hex,'sm4-cfb',$iv,'hex'); echo "\n==== test sm4-ctr============"; echo "\nphp sm4-ctr: ".$hex = $sm4->encrypt($data,'sm4-ctr',$iv); echo "\nphp decode: ".$sm4->decrypt($hex,'sm4-ctr',$iv,'hex');test/ttsm2.php000064400000001751150736750370007326 0ustar00doSign( $document, $privateKey, $userId); print_r($sign); echo "\n---------明文密钥验签---------------------------\n"; var_dump($sm2->verifySign( $document, $sign, $publicKey, $userId )); }