first commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
vendor2/
|
||||
vendor/
|
||||
composer.lock
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
# 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的加解密
|
||||
|
||||
### 使用
|
||||
* composer require lpilp/guomi
|
||||
* please make sure you upgrade to 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非对称加密
|
||||
* 添加了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签名常见问题
|
||||
* 提供的私钥是base64的短串,一般直接 bin2hex(base64_decode(str)) 就是明文的密钥了
|
||||
* 文件格式的密钥一般有pkcs1与pkcs8两个格式,本项目只支持pkcs1格式的密钥,使用前请先进行相关的转换,一般 pkcs8是四行,pkcs1是三行,区别见 https://www.jianshu.com/p/a428e183e72e
|
||||
* 关于签名的字符串的问题,有些项目会将原始字符串哈稀后,再对哈稀值进行签名,有些对这哈稀值又进行了hex2bin操作后再签名,请双方按约定的标准确定最后签名的数据值,双方保持一致即可
|
||||
* 签名的结果是asn1(r,s),个别的项目签名出来的只是 r+s的字符串组合,验证签名的时候注意下。 base64的签名如果以MEU开头的,这个是asn1的,解开后是64字节是r + s 的 在src/util/SmSignFormatRS.php 有相关的转换函数,请按需使用
|
||||
### 特别注意
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "lpilp/guomi",
|
||||
"description": "国密sm2",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "recent",
|
||||
"email": "lpilp@126.com",
|
||||
"wx": "xiaopz129"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"mdanter/ecc": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Rtgm\\": "src"
|
||||
},
|
||||
"files": ["src/overwrite.php"]
|
||||
|
||||
},
|
||||
"repositories": {
|
||||
"packagist": {
|
||||
"type": "composer",
|
||||
"url": "https://mirrors.aliyun.com/composer/"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* 覆盖ecc里的椭圆类,添加sm2
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mdanter\Ecc\Curves;
|
||||
|
||||
// use Mdanter\Ecc\Exception\UnknownCurveException;
|
||||
use Mdanter\Ecc\Exception\UnsupportedCurveException;
|
||||
use Mdanter\Ecc\Math\GmpMathInterface;
|
||||
use Mdanter\Ecc\Math\MathAdapterFactory;
|
||||
use Mdanter\Ecc\Primitives\GeneratorPoint;
|
||||
use Rtgm\ecc\Sm2Curve;
|
||||
|
||||
class CurveFactory
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
* @return NamedCurveFp
|
||||
*/
|
||||
public static function getCurveByName(string $name): NamedCurveFp
|
||||
{
|
||||
$adapter = MathAdapterFactory::getAdapter();
|
||||
if($name == Sm2Curve::NAME_PSM2){
|
||||
return self::getSm2Factory($adapter)->curveSm2();
|
||||
}
|
||||
$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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
namespace Rtgm\ecc;
|
||||
|
||||
use Mdanter\Ecc\Math\GmpMathInterface;
|
||||
use Mdanter\Ecc\Math\MathAdapterFactory;
|
||||
use Mdanter\Ecc\EccFactory;
|
||||
|
||||
// use Rtgm\sm\ecc\NistCurve;
|
||||
use Rtgm\ecc\Sm2Curve;
|
||||
/**
|
||||
* 添加sm2的工厂,采用类的继承方式,这里也可以采用如 \Curves\CurveFctory的覆盖的方式
|
||||
*/
|
||||
class RtEccFactory extends EccFactory{
|
||||
|
||||
/**
|
||||
* Selects and creates the most appropriate adapter for the running environment.
|
||||
*
|
||||
* @param bool $debug [optional] Set to true to get a trace of all mathematical operations
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @return GmpMathInterface
|
||||
*/
|
||||
public static function getAdapter(bool $debug = false): GmpMathInterface
|
||||
{
|
||||
|
||||
$adapter = MathAdapterFactory::getAdapter($debug);
|
||||
return $adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a factory to create NIST Recommended curves and generators.
|
||||
*
|
||||
* @param GmpMathInterface $adapter [optional] Defaults to the return value of EccFactory::getAdapter().
|
||||
* @return Sm2Curve
|
||||
*/
|
||||
public static function getSmCurves(GmpMathInterface $adapter = null): Sm2Curve
|
||||
{
|
||||
$adapter = $adapter ?: self::getAdapter();
|
||||
// var_dump($adapter);
|
||||
return new Sm2Curve($adapter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* 覆盖ecc里的oid与椭圆的对照数组,添加sm2
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mdanter\Ecc\Serializer\Util;
|
||||
|
||||
use FG\ASN1\Universal\ObjectIdentifier;
|
||||
use Mdanter\Ecc\Curves\NamedCurveFp;
|
||||
use Mdanter\Ecc\Curves\CurveFactory;
|
||||
use Mdanter\Ecc\Curves\NistCurve;
|
||||
use Mdanter\Ecc\Curves\SecgCurve;
|
||||
use Rtgm\ecc\Sm2Curve;
|
||||
use Mdanter\Ecc\Exception\UnsupportedCurveException;
|
||||
use Mdanter\Ecc\Primitives\CurveFpInterface;
|
||||
use Mdanter\Ecc\Primitives\GeneratorPoint;
|
||||
class CurveOidMapper
|
||||
{
|
||||
|
||||
const NIST_P192_OID = '1.2.840.10045.3.1.1';
|
||||
|
||||
const NIST_P224_OID = '1.3.132.0.33';
|
||||
|
||||
const NIST_P256_OID = '1.2.840.10045.3.1.7';
|
||||
|
||||
const NIST_P384_OID = '1.3.132.0.34';
|
||||
|
||||
const NIST_P521_OID = '1.3.132.0.35';
|
||||
|
||||
const SECP_112R1_OID = '1.3.132.0.6';
|
||||
|
||||
const SECP_192K1_OID = '1.3.132.0.31';
|
||||
|
||||
const SECP_256K1_OID = '1.3.132.0.10';
|
||||
|
||||
const SECP_256R1_OID = '1.2.840.10045.3.1.7';
|
||||
|
||||
const SECP_384R1_OID = '1.3.132.0.34';
|
||||
|
||||
const SM2_OID = '1.2.156.10197.1.301';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $oidMap = array(
|
||||
NistCurve::NAME_P192 => 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Rtgm\ecc;
|
||||
|
||||
use Mdanter\Ecc\Curves\NamedCurveFp;
|
||||
use Mdanter\Ecc\Math\GmpMathInterface;
|
||||
use Mdanter\Ecc\Primitives\CurveParameters;
|
||||
use Mdanter\Ecc\Primitives\GeneratorPoint;
|
||||
use Mdanter\Ecc\Random\RandomNumberGeneratorInterface;
|
||||
|
||||
/**
|
||||
* 国密sm2椭圆
|
||||
*/
|
||||
class Sm2Curve
|
||||
{
|
||||
const NAME_PSM2 = 'SM2';
|
||||
/**
|
||||
* @var GmpMathInterface
|
||||
*/
|
||||
private $adapter;
|
||||
|
||||
/**
|
||||
* @param GmpMathInterface $adapter
|
||||
*/
|
||||
public function __construct(GmpMathInterface $adapter)
|
||||
{
|
||||
$this->adapter = $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);
|
||||
}
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare( strict_types = 1 );
|
||||
|
||||
// namespace Mdanter\Ecc\Crypto\Signature;
|
||||
namespace Rtgm\ecc;
|
||||
|
||||
use Mdanter\Ecc\Math\GmpMathInterface;
|
||||
use Mdanter\Ecc\Crypto\Key\PrivateKeyInterface;
|
||||
use Mdanter\Ecc\Crypto\Key\PublicKeyInterface;
|
||||
use Mdanter\Ecc\Util\BinaryString;
|
||||
use Mdanter\Ecc\Crypto\Signature\SignatureInterface;
|
||||
use Mdanter\Ecc\Crypto\Signature\Signature;
|
||||
/**
|
||||
* sm2签名算法
|
||||
*/
|
||||
class Sm2Signer {
|
||||
|
||||
/**
|
||||
*
|
||||
* @var GmpMathInterface
|
||||
*/
|
||||
private $adapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GmpMathInterface $adapter
|
||||
*/
|
||||
|
||||
public function __construct( GmpMathInterface $adapter ) {
|
||||
$this->adapter = $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 ) );
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
spl_autoload_register(function ($cls) {
|
||||
$map = array(
|
||||
'Mdanter\Ecc\Serializer\Util\CurveOidMapper' => __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);
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
<?php
|
||||
|
||||
namespace Rtgm\sm;
|
||||
|
||||
define("C1C3C2", 1);
|
||||
define("C1C2C3", 0);
|
||||
|
||||
use Rtgm\ecc\RtEccFactory;
|
||||
use Rtgm\ecc\Sm2Signer;
|
||||
use Mdanter\Ecc\Crypto\Key\PrivateKey;
|
||||
use Mdanter\Ecc\Crypto\Key\PublicKey;
|
||||
use Mdanter\Ecc\Primitives\Point;
|
||||
use Mdanter\Ecc\Serializer\PrivateKey\PemPrivateKeySerializer;
|
||||
use Mdanter\Ecc\Serializer\PrivateKey\DerPrivateKeySerializer;
|
||||
use Mdanter\Ecc\Serializer\PublicKey\PemPublicKeySerializer;
|
||||
use Mdanter\Ecc\Serializer\PublicKey\DerPublicKeySerializer;
|
||||
use Mdanter\Ecc\Serializer\Signature\DerSignatureSerializer;
|
||||
|
||||
use Rtgm\smecc\SM2\Sm2WithSm3;
|
||||
use Rtgm\smecc\SM2\Hex2ByteBuf;
|
||||
|
||||
class RtSm2
|
||||
{
|
||||
protected $adapter = null;
|
||||
protected $generator = null;
|
||||
protected $userId = '1234567812345678';
|
||||
// 是否固定签名不随机,好处是同一段参数的签名固定,增大别人的猜测的难度,
|
||||
// 同样的key + document每次签名是一样的,如果为false则每次不一样
|
||||
protected $useDerandomizedSignatures = true;
|
||||
// 是否固定加密不随机,算法中的是否每次都用不同的中间椭圆,如果固定的话,
|
||||
// 同样的文本加密后的数据是一样的,但速度会更快一些,随机的话,每次加密出来的数据不一样
|
||||
protected $useDerandomizedEncrypt = true;
|
||||
// 输入输出的签名方式 16进制的还是base64
|
||||
protected $formatSign = 'hex';
|
||||
// 可扩展自定义多种返回签名方式
|
||||
protected $arrFormat = ['hex', 'base64'];
|
||||
// 加密时的中间椭圆,取任意的sm2中间椭圆都可以,useDerandomizedEncrypt = true时使用,为false时每次加密,重新生成一个
|
||||
protected $foreignKey = [
|
||||
'21fbd478026e2d668e3570e514de0d312e443d1e294c1ca785dfbfb5f74de225',
|
||||
'04e27c3780e7069bda7082a23a489d77587ce309583ed99253f66e1d9833ed1a1d0b5ce86dc6714e9974cf258589139d7b1855e8c9fa2f2c1175ee123a95a23e9b'
|
||||
];
|
||||
protected $cipher = null;
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $formatSign
|
||||
* @param boolean $randFixed 是否使用中间椭圆,使用中间椭圆的话,速度会快一些,但同样的数据的签名或加密的值就固定了
|
||||
*/
|
||||
function __construct($formatSign = 'hex', $randFixed = true)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机生成一对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 '';
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace Rtgm\sm;
|
||||
|
||||
use Rtgm\smecc\SM3\SM3Digest;
|
||||
|
||||
class RtSm3 {
|
||||
public function digest($msg,$format=1){
|
||||
$md = array();
|
||||
$sm3 = new SM3Digest();
|
||||
$msgArray = unpack("C*",$msg);
|
||||
$sm3->BlockUpdate($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; $i<count($md);$i++){
|
||||
$res[$i] = sprintf("%02x",$md[$i]);
|
||||
}
|
||||
return implode("",$res);
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Rtgm\sm;
|
||||
|
||||
/**
|
||||
* Sm4 from https://github.com/lizhichao/sm
|
||||
*/
|
||||
|
||||
use Exception;
|
||||
use Rtgm\smecc\SM4\Sm4;
|
||||
|
||||
class RtSm4
|
||||
{
|
||||
protected $sm4;
|
||||
protected $keyLen = 16;
|
||||
protected $ivLen = 16;
|
||||
|
||||
function __construct($key)
|
||||
{
|
||||
$this->sm4 = 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
//
|
||||
namespace Rtgm\smecc\SM2;
|
||||
|
||||
use Rtgm\smecc\SM3\SM3Digest;
|
||||
use Rtgm\sm\RtSm2;
|
||||
|
||||
class Cipher
|
||||
{
|
||||
private $ct = 1;
|
||||
|
||||
private $p2;
|
||||
/**
|
||||
* @var SM3Digest
|
||||
*/
|
||||
private $sm3keybase;
|
||||
/**
|
||||
* @var SM3Digest
|
||||
*/
|
||||
private $sm3c3;
|
||||
|
||||
private $key = array();
|
||||
private $keyOff = 0;
|
||||
|
||||
|
||||
private function Reset() //注意,加密使用无符号的数组转换,以便与硬件相一致
|
||||
{
|
||||
$this->sm3keybase = 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
//
|
||||
namespace Rtgm\smecc\SM2;
|
||||
|
||||
class Hex2ByteBuf
|
||||
{
|
||||
|
||||
public static function ConvertGmp2ByteArray($GmpData)
|
||||
{
|
||||
$HexStr = gmp_strval($GmpData, 16);
|
||||
$OutBuf = array();
|
||||
$OutBuf = Hex2ByteBuf::HexStringToByteArray($HexStr);
|
||||
return $OutBuf;
|
||||
}
|
||||
|
||||
public static function ByteArrayToHexString($b, $nlen = null)
|
||||
{
|
||||
$outstring = array();
|
||||
$nlen = $nlen == null ? count($b) : 0;
|
||||
// var_dump($nlen);
|
||||
for ($n = 0; $n < $nlen; $n++) {
|
||||
$outstring[] = Hex2ByteBuf::myhex($b[$n]);
|
||||
}
|
||||
// echo (implode("x",$outstring));
|
||||
return implode("", $outstring);
|
||||
}
|
||||
|
||||
private static function myhex($indata)
|
||||
{
|
||||
$temp_1 = intval($indata / 16);
|
||||
if ($temp_1 < 10)
|
||||
$temp_1 = $temp_1 + 0x30;
|
||||
else
|
||||
$temp_1 = $temp_1 + 0x41 - 10;
|
||||
|
||||
$temp_2 = $indata % 16;
|
||||
if ($temp_2 < 10)
|
||||
$temp_2 = $temp_2 + 0x30;
|
||||
else
|
||||
$temp_2 = $temp_2 + 0x41 - 10;
|
||||
|
||||
return chr($temp_1) . chr($temp_2);
|
||||
}
|
||||
|
||||
public static function HexStringToByteArray($InString)
|
||||
{
|
||||
for (
|
||||
$m = strlen($InString);
|
||||
$m < 64;
|
||||
$m++
|
||||
) {
|
||||
$InString = '0' . $InString;
|
||||
}
|
||||
$g_len = 0;
|
||||
$nlen = 0;
|
||||
$n = 0;
|
||||
$i = 0;
|
||||
$temp = '';
|
||||
$nlen = strlen($InString);
|
||||
if ($nlen < 16) $g_len = 16;
|
||||
$g_len = $nlen / 2;
|
||||
|
||||
for (
|
||||
$n = 0;
|
||||
$n < $nlen;
|
||||
$n = $n + 2
|
||||
) {
|
||||
$temp = substr($InString, $n, 2);
|
||||
$temp = '0x' . $temp;
|
||||
$b[$i] = hexdec($temp);
|
||||
$i = $i + 1;
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
public static function HexStringToByteArray2($InString)
|
||||
{
|
||||
// for (
|
||||
// $m = strlen($InString);
|
||||
// $m < 64;
|
||||
// $m++
|
||||
// ) {
|
||||
// $InString = '0' . $InString;
|
||||
// }
|
||||
$g_len = 0;
|
||||
$nlen = 0;
|
||||
$n = 0;
|
||||
$i = 0;
|
||||
$temp = '';
|
||||
$nlen = strlen($InString);
|
||||
if ($nlen < 16) $g_len = 16;
|
||||
$g_len = $nlen / 2;
|
||||
|
||||
for (
|
||||
$n = 0;
|
||||
$n < $nlen;
|
||||
$n = $n + 2
|
||||
) {
|
||||
$temp = substr($InString, $n, 2);
|
||||
$temp = '0x' . $temp;
|
||||
$b[$i] = hexdec($temp);
|
||||
$i = $i + 1;
|
||||
}
|
||||
|
||||
return $b;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace Rtgm\smecc\SM2;
|
||||
|
||||
use Rtgm\smecc\SM3\SM3Digest;
|
||||
|
||||
class SM2Enc
|
||||
{
|
||||
|
||||
private const SM2_ADDBYTE = 97;//加密后的数据会增加的长度
|
||||
private const MAX_ENCLEN = 128; //最大的加密长度分组
|
||||
private const MAX_DECLEN = (self::MAX_ENCLEN + self::SM2_ADDBYTE); //最大的解密长度分组
|
||||
|
||||
/* public function SM2_EncStringBySoft($InString, $PubKeyX, $PubKeyY, $generator)
|
||||
{
|
||||
|
||||
$Kx = gmp_init($PubKeyX, 16);
|
||||
$Ky = gmp_init($PubKeyY, 16);
|
||||
$userKey = $generator->getPublicKeyFrom($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;
|
||||
} */
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
//
|
||||
namespace Rtgm\smecc\SM2;
|
||||
|
||||
|
||||
use Rtgm\smecc\SM3\SM3Digest;
|
||||
|
||||
class Sm2WithSm3
|
||||
{
|
||||
|
||||
|
||||
private function GetZ($userId, $HexPubKeyX,$HexPubKeyY,$generator)
|
||||
{
|
||||
//$PubKeyX_gmp = gmp_init($HexPubKeyX, 16);
|
||||
// $PubKeyY_gmp = gmp_init($HexPubKeyY, 16);
|
||||
|
||||
$md = array();
|
||||
$sm3 = new SM3Digest();
|
||||
|
||||
// userId length
|
||||
|
||||
$id=unpack("C*",$userId);
|
||||
$len = sizeof($id)*8;
|
||||
$sm3->Update( ($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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
//
|
||||
namespace Rtgm\smecc\SM3;
|
||||
|
||||
class GeneralDigest
|
||||
{
|
||||
private const BYTE_LENGTH = 64;
|
||||
|
||||
private $xBuf=array();
|
||||
private $xBufOff;
|
||||
|
||||
private $byteCount;
|
||||
|
||||
|
||||
public function setGeneralDigest($t)
|
||||
{
|
||||
$this->arraycopy($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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
<?php
|
||||
//declare(strict_types=1);
|
||||
namespace Rtgm\smecc\SM3;
|
||||
|
||||
use Rtgm\smecc\SM3\GeneralDigest;
|
||||
|
||||
class SM3Digest extends GeneralDigest
|
||||
{
|
||||
public static $AlgorithmName="SM3";
|
||||
|
||||
private const DIGEST_LENGTH = 32;
|
||||
|
||||
public function GetDigestSize():int
|
||||
{
|
||||
return $this::DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
|
||||
private static $v0 = array(0x7380166f, 0x4914b2b9, 0x172442d7, -628488704, -1452330820, 0x163138aa,-477237683, -1325724082);
|
||||
|
||||
private $v = array(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
private $v_ = array(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
private static $X0 = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
private $X = array();
|
||||
private $xOff;
|
||||
|
||||
private $T_00_15 = 0x79cc4519;
|
||||
private $T_16_63 = 0x7a879d8a;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
// parent::$gSM3Digest=$this;
|
||||
$this->Reset();
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
+349
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
/**
|
||||
* source: https://github.com/lizhichao/sm
|
||||
*/
|
||||
namespace Rtgm\smecc\SM4;
|
||||
class Sm4
|
||||
{
|
||||
private $ck = [
|
||||
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
|
||||
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
|
||||
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
|
||||
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
|
||||
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
|
||||
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
|
||||
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
|
||||
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
|
||||
];
|
||||
|
||||
private $Sbox = [
|
||||
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
|
||||
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
|
||||
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
|
||||
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
|
||||
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
|
||||
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
|
||||
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
|
||||
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
|
||||
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
|
||||
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
|
||||
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
|
||||
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
|
||||
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
|
||||
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
|
||||
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
|
||||
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
|
||||
];
|
||||
|
||||
private $fk = [0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC];
|
||||
|
||||
private $rk = [];
|
||||
|
||||
private $b = '';
|
||||
|
||||
private $len = 16;
|
||||
|
||||
|
||||
/**
|
||||
* Sm4 constructor.
|
||||
* @param string $key 秘钥长度16位
|
||||
* @param string $b 不是16的倍数 需要的补码
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($key, $b = ' ')
|
||||
{
|
||||
$this->ck16($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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,473 @@
|
||||
<?php
|
||||
|
||||
namespace Rtgm\smecc\SPLSM2;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SimpleSm2
|
||||
{
|
||||
protected $p;
|
||||
protected $a;
|
||||
protected $b;
|
||||
protected $n;
|
||||
protected $gx;
|
||||
protected $gy;
|
||||
protected $size;
|
||||
protected $userId = '1234567812345678';
|
||||
//请自行重新生成一对,示例中的foreignKey可能被大量项目使用,而被对方加黑
|
||||
protected $foreignKey = array(
|
||||
'21fbd478026e2d668e3570e514de0d312e443d1e294c1ca785dfbfb5f74de225',
|
||||
'04e27c3780e7069bda7082a23a489d77587ce309583ed99253f66e1d9833ed1a1d0b5ce86dc6714e9974cf258589139d7b1855e8c9fa2f2c1175ee123a95a23e9b'
|
||||
);
|
||||
|
||||
protected $privateKey;
|
||||
protected $publicKey;
|
||||
protected $sm3;
|
||||
protected $randSign = true; // true则同一字符串,同样密钥,每次签名不一样,false是每次签名都一样
|
||||
protected $randEnc = true; // true则同一字符串,同样密钥,每次签名不一样,false是每次签名都一样
|
||||
protected $fixForeignKey = false; //中间了椭圆固定,在加密时减少生成密码对,性能有所提升,安全性有所下降,
|
||||
function __construct()
|
||||
{
|
||||
$this->sm3 = new Sm3();
|
||||
$eccParams = Sm2Ecc::get_params();
|
||||
$this->p = $eccParams['p'];
|
||||
$this->a = $eccParams['a'];
|
||||
$this->b = $eccParams['b'];
|
||||
$this->n = $eccParams['n'];
|
||||
// 计算基点G
|
||||
$this->gx = $eccParams['gx'];
|
||||
$this->gy = $eccParams['gy'];
|
||||
}
|
||||
|
||||
public function general_pair()
|
||||
{
|
||||
$pointG = new Sm2Point($this->gx, $this->gy);
|
||||
$prikeyGmp = $this->rand_prikey();
|
||||
$publicKey = $this->get_pkey_from_prikey($prikeyGmp, $pointG);
|
||||
$prikey = $this->decHex($prikeyGmp, 64);
|
||||
return array(
|
||||
$prikey, $publicKey
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过私钥算公钥 Pub = pG
|
||||
*
|
||||
* @param GMP $prikey
|
||||
* @return string
|
||||
*/
|
||||
public function get_pkey_from_prikey($prikeyGmp, $pointG = null)
|
||||
{
|
||||
if (empty($pointG)) {
|
||||
$pointG = new Sm2Point($this->gx, $this->gy);
|
||||
}
|
||||
$kG = $pointG->mul($prikeyGmp, false);
|
||||
$x1 = $this->decHex($kG->getX(), 64);
|
||||
$y1 = $this->decHex($kG->getY(), 64);
|
||||
$publicKey = '04' . $x1 . $y1;
|
||||
return $publicKey;
|
||||
}
|
||||
// 生成标准的 base64 的 asn1(r,s)签名
|
||||
public function sign($document, $prikey, $publicKey = null, $userId = null){
|
||||
list($r,$s) = $this->sign_raw($document, $prikey, $publicKey, $userId);
|
||||
return Sm2Asn1::rs_2_asn1($r,$s);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string $document
|
||||
* @param string $prikey
|
||||
* @param string $publicKey //这个值虽然可以从prikey中计算出来,但直接给出来,不用每次计算,性能会好一点点
|
||||
* @param string $userId
|
||||
* @return array
|
||||
*/
|
||||
public function sign_raw($document, $prikey, $publicKey = null, $userId = null)
|
||||
{
|
||||
$gmpPrikey = gmp_init($prikey, 16);
|
||||
// 如果知道公钥直接填上是好的,减少运算,虽说从私钥可以算出公钥,这不浪费资源不是
|
||||
if (empty($publicKey)) {
|
||||
$publicKey = $this->get_pkey_from_prikey($gmpPrikey);
|
||||
}
|
||||
|
||||
$hash = $this->get_sm2withsm3_hash($document, $publicKey, $userId);
|
||||
$gmpHash = gmp_init($hash, 16);
|
||||
|
||||
$count = 0;
|
||||
while (true) {
|
||||
$count++;
|
||||
if ($count > 5) {
|
||||
//5次都有问题,肯定有问题了
|
||||
throw new \RuntimeException('Error: sign R or S = 0');
|
||||
}
|
||||
//中间椭圆的私钥
|
||||
// $k = gmp_init('21fbd478026e2d668e3570e514de0d312e443d1e294c1ca785dfbfb5f74de225',16);
|
||||
$k = $this->_get_forign_prikey($document);
|
||||
// var_dump(gmp_strval($k,16),'21fbd478026e2d668e3570e514de0d312e443d1e294c1ca785dfbfb5f74de225');
|
||||
$gmpP1x = $this->_get_forign_pubkey_x($k);
|
||||
$r = gmp_mod(gmp_add($gmpHash, $gmpP1x), $this->n);
|
||||
$zero = gmp_init(0, 10);
|
||||
if (gmp_cmp($r, $zero) === 0) {
|
||||
continue; //报错重来一次
|
||||
}
|
||||
|
||||
$one = gmp_init(1, 10);
|
||||
$s1 = gmp_invert(gmp_add($one, $gmpPrikey), $this->n);
|
||||
$s2 = gmp_sub($k, gmp_mul($r, $gmpPrikey));
|
||||
$s = gmp_mod(gmp_mul($s1, $s2), $this->n);
|
||||
|
||||
if (gmp_cmp($s, $zero) === 0) {
|
||||
continue;
|
||||
// throw new \RuntimeException('Error: random number S = 0');
|
||||
}
|
||||
return array(gmp_strval($r, 16), gmp_strval($s, 16));
|
||||
}
|
||||
}
|
||||
// 标准的asn1 base64签名验签
|
||||
public function verify($document, $publicKey, $sign, $userId = null){
|
||||
list($hexR,$hexS) = Sm2Asn1::asn1_2_rs($sign);
|
||||
return $this->verifty_sign_raw($document, $publicKey, $hexR, $hexS, $userId);
|
||||
|
||||
}
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $document bin
|
||||
* @param string $publicKey hex
|
||||
* @param string $r hex
|
||||
* @param string $s hex
|
||||
* @param string $userId
|
||||
* @return bool
|
||||
*/
|
||||
public function verifty_sign_raw($document, $publicKey, $hexR, $hexS, $userId = null)
|
||||
{
|
||||
$plen = strlen($publicKey);
|
||||
if ($plen == 130 && substr($publicKey, 0, 2) == '04') {
|
||||
$pubX = substr($publicKey, 2, 64);
|
||||
$pubY = substr($publicKey, -64);
|
||||
} else if ($plen == 128) {
|
||||
$pubX = substr($publicKey, 0, 64);
|
||||
$pubY = substr($publicKey, -64);
|
||||
} else {
|
||||
throw new Exception("bad publickey $publicKey");
|
||||
}
|
||||
// 1.2.3.4 sm3 取msg,userid的 hash值,
|
||||
$hash = gmp_init($this->get_sm2withsm3_hash($document, $publicKey, $userId), 16);
|
||||
|
||||
$r = gmp_init($hexR, 16);
|
||||
$s = gmp_init($hexS, 16);
|
||||
$n = $this->n;
|
||||
|
||||
$one = gmp_init(1, 10);
|
||||
if (gmp_cmp($r, $one) < 0 || gmp_cmp($r, gmp_sub($n, $one)) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gmp_cmp($s, $one) < 0 || gmp_cmp($s, gmp_sub($n, $one)) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 第五步 计算t=(r'+s')mod n
|
||||
$t = gmp_mod(gmp_add($r, $s), $n);
|
||||
// // 第六步 计算(x1,y1) = [s]G + [t]P
|
||||
$pointG = new Sm2Point($this->gx, $this->gy); //生成基准点
|
||||
$p1 = $pointG->mul($s, false); // p1 = sG
|
||||
$pointPub = new Sm2Point(gmp_init($pubX, 16), gmp_init($pubY, 16)); //生成公钥的基准点
|
||||
$p2 = $pointPub->mul($t, false); // p2 = tP
|
||||
$xy = $p1->add($p2);
|
||||
// // 第七步 vR=(hash' + x1')
|
||||
$v = gmp_mod(gmp_add($hash, $xy->getX()), $n);
|
||||
|
||||
// 最后结果 比较 $v和$r是否一致
|
||||
// var_dump(gmp_strval($v,16),$hexR);
|
||||
return gmp_strval($v, 16) == $hexR;
|
||||
}
|
||||
|
||||
|
||||
public function encrypt_raw($publicKey, $data)
|
||||
{
|
||||
list($pubX, $pubY) = $this->_get_pub_xy($publicKey);
|
||||
$point = new Sm2Point($pubX,$pubY);
|
||||
$t = '';
|
||||
$count = 0;
|
||||
while (!$t) {
|
||||
$count++;
|
||||
if($count>5){
|
||||
throw new Exception('bad kdf '); // 这处一般是生成的$k问题,5次都有问题,这运气差的可以买双色球了
|
||||
}
|
||||
|
||||
if($this->fixForeignKey) { //使用固定的第中间椭圆
|
||||
list($x1,$y1) = $this->_get_pub_xy($this->foreignKey[1],false);
|
||||
$k = gmp_init($this->foreignKey[0],16);
|
||||
|
||||
$x1 = $this->format_hex($x1,64);// 不足前面补0
|
||||
$y1 = $this->format_hex($y1,64);// 不足前面补0
|
||||
} else {
|
||||
$k = $this->_get_forign_prikey($data.'_'.$count);
|
||||
//dump($k);
|
||||
//$k = gmp_init('104953050056413721046883757640585885959005820148174417356964987920496726278110',10);
|
||||
$kG = $point->mul($k);
|
||||
$x1 = $this->decHex($kG->getX(), 64);
|
||||
$y1 = $this->decHex($kG->getY(), 64);
|
||||
}
|
||||
$c1 = $x1 . $y1;
|
||||
$kPb = $point->mul($k, false);
|
||||
$x2 = gmp_strval($kPb->getX(), 16);
|
||||
$y2 = gmp_strval($kPb->getY(), 16);
|
||||
$x2 = pack('H*', str_pad($x2, 64, 0, STR_PAD_LEFT));
|
||||
$y2 = pack('H*', str_pad($y2, 64, 0, STR_PAD_LEFT));
|
||||
$t = $this->kdf($x2 . $y2, strlen($data));
|
||||
}
|
||||
$c2 = gmp_xor(gmp_init($t, 16), $this->str2gmp($data));
|
||||
$c2 = $this->decHex($c2, strlen($data) * 2);
|
||||
$c3 = $this->hash_sm3($x2 . $data . $y2);
|
||||
return array($c1, $c3, $c2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sm2非对称解密
|
||||
*
|
||||
* @param string $prikey 私钥明文 hex
|
||||
* @param string $c1 hex
|
||||
* @param string $c3 hex
|
||||
* @param string $c2 hex
|
||||
* @return string decode($c2) 解密结果
|
||||
*/
|
||||
public function decrypt_raw($prikey, $c1,$c3,$c2)
|
||||
{
|
||||
list($x1, $y1) = $this->_get_pub_xy($c1);
|
||||
$point = new Sm2Point($x1,$y1);
|
||||
$dbC1 = $point->mul(gmp_init($prikey,16), false);
|
||||
$x2 = gmp_strval($dbC1->getX(), 16);
|
||||
$y2 = gmp_strval($dbC1->getY(), 16);
|
||||
$x2 = pack('H*', str_pad($x2, 64, 0, STR_PAD_LEFT));
|
||||
$y2 = pack('H*', str_pad($y2, 64, 0, STR_PAD_LEFT));
|
||||
$len = strlen($c2);
|
||||
$t = $this->kdf($x2 . $y2, $len / 2); // 转成16进制后 字符长度要除以2
|
||||
$m1 = gmp_strval(gmp_xor(gmp_init($t, 16), gmp_init($c2, 16)), 16);
|
||||
$m1 = pack("H*", $m1);
|
||||
$u = $this->hash_sm3($x2 . $m1 . $y2);
|
||||
|
||||
if (strtoupper($u) != strtoupper($c3)) {
|
||||
throw new \Exception("error decrypt data");
|
||||
}
|
||||
|
||||
return $m1;
|
||||
}
|
||||
protected function kdf($z, $klen)
|
||||
{
|
||||
$res = '';
|
||||
$ct = 1;
|
||||
$j = ceil($klen / 32);
|
||||
for ($i = 0; $i < $j; $i++) {
|
||||
$ctStr = str_pad(chr($ct), 4, chr(0), STR_PAD_LEFT);
|
||||
$hex = $this->hash_sm3($z . $ctStr);
|
||||
if ($i + 1 == $j && $klen % 32 != 0) { // 最后一个 且 $klen/$v 不是整数
|
||||
$res .= substr($hex, 0, ($klen % 32) * 2); // 16进制比byte长度少一半 要乘2
|
||||
} else {
|
||||
$res .= $hex;
|
||||
}
|
||||
$ct++;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $message
|
||||
* @param boolean $raw
|
||||
* @return string
|
||||
*/
|
||||
public function hash_sm3($message, $raw = false)
|
||||
{
|
||||
// return $this->sm3->digest($message, $raw);
|
||||
// 有些版本的PHP直接支持sm3
|
||||
return openssl_digest($message,'sm3',$raw);
|
||||
}
|
||||
/**
|
||||
* hex 用0补齐一定的位置
|
||||
*
|
||||
* @param string $hex
|
||||
* @param integer $count
|
||||
* @return string
|
||||
*/
|
||||
public function format_hex($hex, $count = 64)
|
||||
{
|
||||
return str_pad($hex, $count, "0", STR_PAD_LEFT);
|
||||
}
|
||||
/**
|
||||
* 采用gmp自带的函数随机生成私钥,gmp_random_bits需要5.6.3才有
|
||||
* 也可其他随机函数生成
|
||||
*
|
||||
* @param integer $numBits
|
||||
* @return \GMP
|
||||
*/
|
||||
public function rand_prikey($numBits = 256)
|
||||
{
|
||||
if (!function_exists('gmp_random_bits')) {
|
||||
return $this->_get_forign_prikey('loveyou');
|
||||
}
|
||||
$value = gmp_random_bits($numBits);
|
||||
$mask = gmp_sub(gmp_pow(2, $numBits), 1);
|
||||
$integer = gmp_and($value, $mask);
|
||||
|
||||
return $integer;
|
||||
}
|
||||
/**
|
||||
* gmp 转 hex,并用0补齐位数
|
||||
*
|
||||
* @param GMP|int $dec
|
||||
* @param integer $len
|
||||
* @return string
|
||||
*/
|
||||
public function decHex($dec, $len = 0)
|
||||
{
|
||||
if (!$dec instanceof \GMP) {
|
||||
$dec = gmp_init($dec, 10);
|
||||
}
|
||||
if (gmp_cmp($dec, 0) < 0) {
|
||||
throw new \Exception('Unable to convert negative integer to string');
|
||||
}
|
||||
|
||||
$hex = gmp_strval($dec, 16);
|
||||
|
||||
if (strlen($hex) % 2 != 0) {
|
||||
$hex = '0' . $hex;
|
||||
}
|
||||
if ($len && strlen($hex) < $len) { // point x y 要补齐 64 位
|
||||
$hex = str_pad($hex, $len, "0", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
return $hex;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param string $document
|
||||
* @param string $publicKey
|
||||
* @param string $userId
|
||||
* @return string
|
||||
*/
|
||||
public function get_sm2withsm3_hash($document, $publicKey, $userId)
|
||||
{
|
||||
// 置M’=ZA∥M;ZA= Hv(ENTLA||IDA||a||b||Gx||Gy||Ax||Ay); IDA==>userId
|
||||
// ENTLA为IDA的比特长度,2字节;IDA用户标识默认值见上节;a,b,Gx,Gy见曲线参数;Ax,Ay为公钥坐标
|
||||
$len = strlen($publicKey);
|
||||
if ($len == 130) {
|
||||
$publicKey = substr($publicKey, 2);
|
||||
} else if ($len == 128) {
|
||||
//OK
|
||||
} else {
|
||||
throw new \Exception('bad pulickey');
|
||||
}
|
||||
$px = gmp_init(substr($publicKey, 0, 64), 16);
|
||||
$py = gmp_init(substr($publicKey, 64, 64), 16);
|
||||
$zStr = $this->_get_entla($userId);
|
||||
$zStr .= $userId;
|
||||
$zStr .= hex2bin(gmp_strval($this->a, 16));
|
||||
$zStr .= hex2bin(gmp_strval($this->b, 16));
|
||||
$zStr .= hex2bin(gmp_strval($this->gx, 16));
|
||||
$zStr .= hex2bin(gmp_strval($this->gy, 16));
|
||||
$zStr .= hex2bin(gmp_strval($px, 16));
|
||||
$zStr .= hex2bin(gmp_strval($py, 16));
|
||||
$hashStr = $this->hash_sm3($zStr);
|
||||
$hash = $this->hash_sm3(hex2bin($hashStr) . $document);
|
||||
return $hash;
|
||||
}
|
||||
/**
|
||||
* 生成随机私钥
|
||||
*
|
||||
* @param string $document
|
||||
* @return \GMP
|
||||
*/
|
||||
protected function _get_forign_prikey($document = '')
|
||||
{
|
||||
// 要支持php5的话,没有什么好函数了,如果是php7或以上或以使用
|
||||
// $s = random_bytes(64) 或 this->rand_prikey(int bits=256) 代替
|
||||
if ($this->randSign || $this->randEnc) { // 从document ==>k 变化
|
||||
$s = substr(openssl_digest('S1' . $document . microtime(), 'sha1'), 1, 32) . md5($document . microtime() . 'S2');
|
||||
} else {
|
||||
$s = substr(openssl_digest('S1' . $document, 'sha1'), 1, 32) . md5($document . 'S2');
|
||||
}
|
||||
|
||||
$s = strtolower($s);
|
||||
if (substr($s, 0, 1) == 'f') { //私钥不要太大了,超过 n值就不好了,
|
||||
$s = 'e' . substr($s, 1);
|
||||
}
|
||||
return gmp_init($s, 16);
|
||||
}
|
||||
protected function _get_forign_pubkey_x($k)
|
||||
{
|
||||
$pointG = new Sm2Point($this->gx, $this->gy);
|
||||
$kG = $pointG->mul($k, false);
|
||||
return $kG->getX();
|
||||
}
|
||||
protected function _get_entla($userId)
|
||||
{
|
||||
$len = strlen($userId) * 8;
|
||||
$l1 = $len >> 8 & 0x00ff;
|
||||
$l2 = $len & 0x00ff;
|
||||
return chr($l1) . chr($l2);
|
||||
}
|
||||
protected function _gmp_to_bin($gmp)
|
||||
{
|
||||
return hex2bin(gmp_strval($gmp, 16));
|
||||
}
|
||||
|
||||
public function set_private_key($privateKey)
|
||||
{
|
||||
$this->privateKey = $privateKey;
|
||||
}
|
||||
public function set_public_key($publicKey)
|
||||
{
|
||||
$this->publicKey = $publicKey;
|
||||
}
|
||||
|
||||
public function set_userid($userId)
|
||||
{
|
||||
if (empty($userId) || strlen($userId) != 16) {
|
||||
throw new Exception(" userid 格式不对");
|
||||
}
|
||||
$this->userId = $userId;
|
||||
}
|
||||
public function set_rand_sign_flag($flag = false)
|
||||
{
|
||||
$this->randSign = $flag;
|
||||
}
|
||||
public function set_rand_enc_flag($flag = false)
|
||||
{
|
||||
$this->randEnc = $flag;
|
||||
}
|
||||
|
||||
public function set_fix_foreignkey_flag($flag = true){
|
||||
$this->fixForeignKey = $flag;
|
||||
}
|
||||
public function str2gmp($string)
|
||||
{
|
||||
$hex = unpack('H*', $string);
|
||||
|
||||
return gmp_init($hex[1], 16);
|
||||
}
|
||||
|
||||
protected function _get_pub_xy($publicKey,$rtGmp = true){
|
||||
$plen = strlen($publicKey);
|
||||
if ($plen == 130 && substr($publicKey, 0, 2) == '04') {
|
||||
$pubX = substr($publicKey, 2, 64);
|
||||
$pubY = substr($publicKey, -64);
|
||||
} else if ($plen == 128) {
|
||||
$pubX = substr($publicKey, 0, 64);
|
||||
$pubY = substr($publicKey, -64);
|
||||
} else {
|
||||
throw new Exception("bad publickey $publicKey");
|
||||
}
|
||||
if($rtGmp){
|
||||
return array(gmp_init($pubX,16),gmp_init($pubY,16));
|
||||
}
|
||||
// var_dump($publicKey,$pubX, $pubY,'==============');
|
||||
return array($pubX, $pubY);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
namespace Rtgm\smecc\SPLSM2;
|
||||
/**
|
||||
*
|
||||
* 针对签名,加解密只有一层 asn1的解析,不做其他类型的解析,
|
||||
*/
|
||||
define('MAXLEVEL', 2); // 简单解析,只解析两层就够了
|
||||
class Sm2Asn1
|
||||
{
|
||||
const CLASS_UNIVERSAL = 0;
|
||||
const CLASS_APPLICATION = 1;
|
||||
const CLASS_CONTEXT_SPECIFIC = 2;
|
||||
const CLASS_PRIVATE = 3;
|
||||
const TYPE_BOOLEAN = 1;
|
||||
const TYPE_INTEGER = 2;
|
||||
const TYPE_BIT_STRING = 3;
|
||||
const TYPE_OCTET_STRING = 4;
|
||||
const TYPE_NULL = 5;
|
||||
const TYPE_OBJECT_IDENTIFIER = 6;
|
||||
const TYPE_OBJECT_DESCRIPTOR = 7;
|
||||
const TYPE_INSTANCE_OF = 8; // EXTERNAL
|
||||
const TYPE_REAL = 9;
|
||||
const TYPE_ENUMERATED = 10;
|
||||
const TYPE_EMBEDDED = 11;
|
||||
const TYPE_UTF8_STRING = 12;
|
||||
const TYPE_RELATIVE_OID = 13;
|
||||
const TYPE_SEQUENCE = 16; // SEQUENCE OF
|
||||
const TYPE_SET = 17; // SET OF
|
||||
const TYPE_NUMERIC_STRING = 18;
|
||||
const TYPE_PRINTABLE_STRING = 19;
|
||||
const TYPE_TELETEX_STRING = 20; // T61String
|
||||
const TYPE_VIDEOTEX_STRING = 21;
|
||||
const TYPE_IA5_STRING = 22;
|
||||
const TYPE_UTC_TIME = 23;
|
||||
const TYPE_GENERALIZED_TIME = 24;
|
||||
const TYPE_GRAPHIC_STRING = 25;
|
||||
const TYPE_VISIBLE_STRING = 26; // ISO646String
|
||||
const TYPE_GENERAL_STRING = 27;
|
||||
const TYPE_UNIVERSAL_STRING = 28;
|
||||
const TYPE_CHARACTER_STRING = 29;
|
||||
const TYPE_BMP_STRING = 30;
|
||||
const TYPE_BIG_SEQUENCE = 48;
|
||||
const TYPE_BIG_SET = 49;
|
||||
const TYPE_CHOICE = -1;
|
||||
const TYPE_ANY = -2;
|
||||
const TYPE_ANY_RAW = -3;
|
||||
const TYPE_ANY_SKIP = -4;
|
||||
const TYPE_ANY_DER = -5;
|
||||
|
||||
/**
|
||||
* 解析简单的asn1
|
||||
*
|
||||
* @param string bin $data
|
||||
* @param integer $level
|
||||
* @return array <string>
|
||||
*/
|
||||
public static function decode($data, $level = 0)
|
||||
{
|
||||
$result = array();
|
||||
$pos = 0;
|
||||
while (abs($pos) < strlen($data)) {
|
||||
$octets = 0;
|
||||
$length = 0;
|
||||
$tag = ord($data[$pos]);
|
||||
$pos++;
|
||||
if ($tag == 0) {
|
||||
$result[] = '00';
|
||||
continue;
|
||||
}
|
||||
$temp = ord($data[$pos]);
|
||||
// echo "temp = $temp\n";
|
||||
if ($temp == 128) {
|
||||
$length = 0;
|
||||
} else if ($temp > 128) {
|
||||
$octets = $temp & 127;
|
||||
$length = 0;
|
||||
// echo $octets."====\n";
|
||||
for ($i = 0; $i < $octets; $i++) {
|
||||
$pos++;
|
||||
$length <<= 8;
|
||||
$length |= ord($data[$pos]);
|
||||
}
|
||||
} else {
|
||||
$length = $temp;
|
||||
}
|
||||
$content = substr($data, ++$pos, $length);
|
||||
$pos += $length;
|
||||
$res = self::_do_decode($content, $tag, $level);
|
||||
$result[] = $res;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
protected static function _do_decode($content, $tag, $level)
|
||||
{
|
||||
$level++;
|
||||
if ($level > MAXLEVEL) {
|
||||
return bin2hex($content);
|
||||
}
|
||||
switch ($tag) {
|
||||
case self::TYPE_BOOLEAN:
|
||||
return (bool)ord($content[0]);
|
||||
case self::TYPE_INTEGER:
|
||||
return bin2hex($content);
|
||||
case self::TYPE_OCTET_STRING:
|
||||
return bin2hex($content);
|
||||
case self::TYPE_BIT_STRING:
|
||||
$padByte = bin2hex($content[0]);
|
||||
$contentText = bin2hex(substr($content, 1));
|
||||
return array($padByte, $contentText);
|
||||
case self::TYPE_SEQUENCE:
|
||||
case self::TYPE_BIG_SEQUENCE:
|
||||
case self::TYPE_BIG_SET:
|
||||
return self::decode($content, $level);
|
||||
case self::TYPE_UTF8_STRING:
|
||||
return $content;
|
||||
case self::TYPE_BMP_STRING:
|
||||
return extension_loaded("iconv") ? iconv('UCS-2BE', 'UTF-8', $content) : $content;
|
||||
case self::TYPE_UNIVERSAL_STRING:
|
||||
return extension_loaded("iconv") ? iconv('UCS-4BE', 'UTF-8', $content) : $content;
|
||||
case self::TYPE_NULL:
|
||||
return null;
|
||||
default: // 其他复杂的不处理了,如有复杂需要,请使用其他的 asn1库处理
|
||||
return bin2hex($content);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param string hex bigint $r
|
||||
* @param string hex bigint $s
|
||||
* @return string base64 一般约定签名用bas64, 加解密用hex
|
||||
*/
|
||||
public static function rs_2_asn1($r, $s, $outFormat = 'base64')
|
||||
{
|
||||
$binR = self::_format_int_pad(hex2bin($r));
|
||||
$binS = self::_format_int_pad(hex2bin($s));
|
||||
$lenR = strlen($binR);
|
||||
$lenS = strlen($binS);
|
||||
$result = chr(48) . chr(2 + $lenR + 2 + $lenS) . chr(2) . chr($lenR) . $binR . chr(2) . chr($lenS) . $binS;
|
||||
if ($outFormat == 'base64') {
|
||||
return base64_encode($result);
|
||||
} else {
|
||||
return bin2hex($result);
|
||||
}
|
||||
}
|
||||
public static function asn1_2_rs($asn1Str,$inFormat='base64'){
|
||||
|
||||
if($inFormat=='base64'){
|
||||
$bin = base64_decode($asn1Str);
|
||||
} else {
|
||||
$bin = hex2bin($asn1Str);
|
||||
}
|
||||
$data = self::decode($bin);
|
||||
$r = gmp_strval(gmp_init($data[0][0],16),16);
|
||||
$s = gmp_strval(gmp_init($data[0][1],16),16);
|
||||
return array($r, $s);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param string hex bigint $c1x
|
||||
* @param string hex bigint $c1y
|
||||
* @param string hex bin $c3
|
||||
* @param string hex bin $c2
|
||||
* @return string hex 一般约定签名用bas64, 加解密用hex
|
||||
*/
|
||||
public static function asn1_cccc($c1x, $c1y, $c3, $c2, $outFormat = 'hex')
|
||||
{
|
||||
$binc1x = self::_format_int_pad($c1x); // c1为椭圆点,得是bigint
|
||||
$binc1y = self::_format_int_pad($c1y);
|
||||
$binc3 = hex2bin($c3);
|
||||
$binc2 = hex2bin($c2);
|
||||
$c1xEncoded = chr(2) . strlen($binc1x) . $binc1x; // c1x 64 hex
|
||||
$c1yEncoded = chr(2) . strlen($binc1y) . $binc1y; // c1y 64 hex
|
||||
$c3Encoded = chr(4) . self::_encode_length(strlen($binc3)) . $binc3; // c3的长度是固定的,可不用长宽度的方式求宽度,但有些就要c2 放前面呢,兼容下
|
||||
$c2Encoded = chr(4) . self::_encode_length(strlen($binc2)) . $binc2;
|
||||
$cccc = $c1xEncoded . $c1yEncoded . $c3Encoded . $c2Encoded;
|
||||
$lenAll = strlen($cccc);
|
||||
$result = chr(48) . self::_encode_length($lenAll) . $cccc;
|
||||
if ($outFormat == 'hex') {
|
||||
return bin2hex($result);
|
||||
} else {
|
||||
return base64_encode($result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rs要固定长度,经测试会有小概率出现长度短的,要补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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 去掉多余的0, int 的话补上必发
|
||||
*
|
||||
* @param string $binStr
|
||||
* @return string
|
||||
*/
|
||||
protected static function _format_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;
|
||||
}
|
||||
|
||||
protected static function _encode_length($length)
|
||||
{
|
||||
|
||||
if ($length <= 0x7F) {
|
||||
return chr($length);
|
||||
}
|
||||
$temp = ltrim(pack('N', $length), chr(0));
|
||||
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
namespace Rtgm\smecc\SPLSM2;
|
||||
|
||||
class Sm2Ecc {
|
||||
static function get_params(){
|
||||
return array(
|
||||
'p' => gmp_init("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16),
|
||||
'a' => gmp_init("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16),
|
||||
'b' => gmp_init("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16),
|
||||
'n' => gmp_init("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16),
|
||||
'gx' => gmp_init("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16),
|
||||
'gy' => gmp_init("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16),
|
||||
'size'=>256
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
namespace Rtgm\smecc\SPLSM2;
|
||||
|
||||
/**
|
||||
* from https://github.com/lat751608899/sm2/blob/main/src/Point.php
|
||||
* @author zlq <751608899@qq.com>
|
||||
* modify by lpilp
|
||||
* point 类 ,使用zlq童鞋 修改至 ECC的 point 类 Mdanter\Ecc\Primitives\Point
|
||||
*/
|
||||
class Sm2Point
|
||||
{
|
||||
protected $eccParams;
|
||||
protected $x;
|
||||
protected $y;
|
||||
|
||||
public function __construct(\GMP $x, \GMP $y)
|
||||
{
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
$this->init();
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
|
||||
$eccParams = Sm2Ecc::get_params();
|
||||
$this->eccParams= $eccParams;
|
||||
}
|
||||
|
||||
public function mul(\GMP $n, $isBase = true)
|
||||
{
|
||||
$zero = gmp_init(0, 10);
|
||||
$n = gmp_mod($n, $this->eccParams['p']);
|
||||
if (gmp_cmp($n, $zero) === 0) {
|
||||
return $this->getInfinity();
|
||||
}
|
||||
$p = $isBase ? new self($this->eccParams['gx'], $this->eccParams['gy']) : clone $this;
|
||||
/** @var Point[] $r */
|
||||
$r = [
|
||||
$this->getInfinity(), // Q
|
||||
$p// P
|
||||
];
|
||||
$base = gmp_strval(gmp_init(gmp_strval($n), 10), 2);
|
||||
$n = strrev(str_pad($base, $this->eccParams['size'], '0', STR_PAD_LEFT));
|
||||
for ($i = 0; $i < $this->eccParams['size']; $i++) {
|
||||
$j = $n[$i];
|
||||
if($j == 1){
|
||||
$r[0] = $r[0]->add($r[1]); // r0 + r1 => p + 0 = p
|
||||
}
|
||||
$r[1] = $r[1]->getDouble();
|
||||
}
|
||||
$r[0]->checkOnLine();
|
||||
|
||||
return $r[0];
|
||||
}
|
||||
|
||||
public function add(Sm2Point $addend)
|
||||
{
|
||||
if ($addend->isInfinity()) {
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
if ($this->isInfinity()) { // 是否是无穷远点
|
||||
return clone $addend;
|
||||
}
|
||||
|
||||
// x 相等
|
||||
if (gmp_cmp($addend->getX(), $this->x) === 0) {
|
||||
// y 也相等 = 倍点
|
||||
if (gmp_cmp($addend->getY(), $this->y) === 0) {
|
||||
return $this->getDouble();
|
||||
} else { // y 不相等 无穷远点
|
||||
return $this->getInfinity();
|
||||
}
|
||||
}
|
||||
|
||||
$slope = $this->divMod(// λ = (y2 - y1) / (x2 - x1) (mod p)
|
||||
gmp_sub($addend->getY(), $this->y), // y2 - y1
|
||||
gmp_sub($addend->getX(), $this->x) // x2 - x1
|
||||
);
|
||||
// λ² - x1 - x2
|
||||
$xR = $this->subMod(gmp_sub(gmp_pow($slope, 2), $this->x), $addend->getX());
|
||||
// (λ(x1 - x3)-y1)
|
||||
$yR = $this->subMod(gmp_mul($slope, gmp_sub($this->x, $xR)), $this->y);
|
||||
|
||||
return new self($xR, $yR);
|
||||
}
|
||||
|
||||
public function getDouble()
|
||||
{
|
||||
if ($this->isInfinity()) {
|
||||
return $this->getInfinity();
|
||||
}
|
||||
$threeX2 = gmp_mul(gmp_init(3, 10), gmp_pow($this->x, 2)); // 3x²
|
||||
$tangent = $this->divMod( // λ = (3x² + a) / 2y (mod p)
|
||||
gmp_add($threeX2, $this->eccParams['a']), // 3x² + a
|
||||
gmp_mul(gmp_init(2, 10), $this->y) // 2y
|
||||
);
|
||||
$x3 = $this->subMod( // λ² - 2x (mod p)
|
||||
gmp_pow($tangent, 2), // λ²
|
||||
gmp_mul(gmp_init(2, 10), $this->x) // 2x
|
||||
);
|
||||
$y3 = $this->subMod( // λ(x - x3)-y (mod p)
|
||||
gmp_mul($tangent, gmp_sub($this->x, $x3)), // λ(x - x3)
|
||||
$this->y
|
||||
);
|
||||
|
||||
return new self($x3, $y3);
|
||||
}
|
||||
|
||||
public function getInfinity()
|
||||
{
|
||||
return new self(gmp_init(0,10), gmp_init(0,10));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \GMP
|
||||
*/
|
||||
public function getX()
|
||||
{
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \GMP
|
||||
*/
|
||||
public function getY()
|
||||
{
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
public function isInfinity()
|
||||
{
|
||||
return gmp_cmp($this->x, gmp_init(0,10)) === 0
|
||||
&& gmp_cmp($this->y, gmp_init(0,10)) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* // k ≡ (x/y) (mod n) => ky ≡ x (mod n) => k y/x ≡ 1 (mod n)
|
||||
* @param $x
|
||||
* @param $y
|
||||
* @param null $n
|
||||
* @return \GMP|resource
|
||||
*/
|
||||
protected function divMod($x, $y, $n = null)
|
||||
{
|
||||
$n = $n?:$this->eccParams['p'];
|
||||
// y k ≡ 1 (mod n) => k ≡ 1/y (mod n)
|
||||
$k = gmp_invert($y, $n);
|
||||
// kx ≡ x/y (mod n)
|
||||
$kx = gmp_mul($x, $k);
|
||||
|
||||
return gmp_mod($kx, $n);
|
||||
}
|
||||
|
||||
protected function subMod($x, $y, $n = null)
|
||||
{
|
||||
return gmp_mod(gmp_sub($x, $y), $n?:$this->eccParams['p']);
|
||||
}
|
||||
|
||||
public function contains(\GMP $x, \GMP $y)
|
||||
{
|
||||
$eq_zero = gmp_cmp(
|
||||
$this->subMod(
|
||||
gmp_pow($y, 2),
|
||||
gmp_add(
|
||||
gmp_add(
|
||||
gmp_pow($x, 3),
|
||||
gmp_mul($this->eccParams['a'], $x)
|
||||
),
|
||||
$this->eccParams['b']
|
||||
)
|
||||
),
|
||||
gmp_init(0, 10)
|
||||
);
|
||||
|
||||
return $eq_zero;
|
||||
}
|
||||
|
||||
public function checkOnLine()
|
||||
{
|
||||
if($this->contains($this->x, $this->y) !== 0){
|
||||
throw new \Exception('Invalid point');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
namespace Rtgm\smecc\SPLSM2;
|
||||
|
||||
/**
|
||||
* 在5.x的版本中不支持openssl系列的sm3 使用lizhichao童鞋的sm3
|
||||
*
|
||||
* https://github.com/lizhichao/sm/blob/master/src/Sm3.php
|
||||
* @auth lizhichao
|
||||
*/
|
||||
|
||||
class Sm3
|
||||
{
|
||||
private $IV = '7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e';
|
||||
private $LEN = 512;
|
||||
private $STR_LEN = 64;
|
||||
|
||||
public function digest($str,$raw = false)
|
||||
{
|
||||
$l = strlen($str) * 8;
|
||||
$k = $this->getK($l);
|
||||
$bt = $this->getB($k);
|
||||
$str = $str . $bt . pack('J', $l);
|
||||
|
||||
$count = strlen($str);
|
||||
$l = $count / $this->STR_LEN;
|
||||
$vr = hex2bin($this->IV);
|
||||
for ($i = 0; $i < $l; $i++) {
|
||||
$vr = $this->cf($vr, substr($str, $i * $this->STR_LEN, $this->STR_LEN));
|
||||
}
|
||||
if($raw){
|
||||
return $vr;
|
||||
}
|
||||
return bin2hex($vr);
|
||||
|
||||
}
|
||||
|
||||
private function getK($l)
|
||||
{
|
||||
$v = $l % $this->LEN;
|
||||
return $v + $this->STR_LEN < $this->LEN
|
||||
? $this->LEN - $this->STR_LEN - $v - 1
|
||||
: ($this->LEN * 2) - $this->STR_LEN - $v - 1;
|
||||
}
|
||||
|
||||
private function getB($k)
|
||||
{
|
||||
$arg = [128];
|
||||
$arg = array_merge($arg, array_fill(0, intval($k / 8), 0));
|
||||
return pack('C*', ...$arg);
|
||||
}
|
||||
|
||||
public function signFile($file)
|
||||
{
|
||||
$l = filesize($file) * 8;
|
||||
$k = $this->getK($l);
|
||||
$bt = $this->getB($k) . pack('J', $l);
|
||||
|
||||
$hd = fopen($file, 'r');
|
||||
$vr = hex2bin($this->IV);
|
||||
$str = fread($hd, $this->STR_LEN);
|
||||
if ($l > $this->LEN - $this->STR_LEN - 1) {
|
||||
do {
|
||||
$vr = $this->cf($vr, $str);
|
||||
$str = fread($hd, $this->STR_LEN);
|
||||
} while (!feof($hd));
|
||||
}
|
||||
|
||||
$str = $str . $bt;
|
||||
$count = strlen($str) * 8;
|
||||
$l = $count / $this->LEN;
|
||||
for ($i = 0; $i < $l; $i++) {
|
||||
$vr = $this->cf($vr, substr($str, $i * $this->STR_LEN, $this->STR_LEN));
|
||||
}
|
||||
return bin2hex($vr);
|
||||
}
|
||||
|
||||
|
||||
private function t($i)
|
||||
{
|
||||
return $i < 16 ? 0x79cc4519 : 0x7a879d8a;
|
||||
}
|
||||
|
||||
private function cf($ai, $bi)
|
||||
{
|
||||
$wr = array_values(unpack('N*', $bi));
|
||||
for ($i = 16; $i < 68; $i++) {
|
||||
$wr[$i] = $this->p1($wr[$i - 16]
|
||||
^
|
||||
$wr[$i - 9]
|
||||
^
|
||||
$this->lm($wr[$i - 3], 15))
|
||||
^
|
||||
$this->lm($wr[$i - 13], 7)
|
||||
^
|
||||
$wr[$i - 6];
|
||||
}
|
||||
$wr1 = [];
|
||||
for ($i = 0; $i < 64; $i++) {
|
||||
$wr1[] = $wr[$i] ^ $wr[$i + 4];
|
||||
}
|
||||
|
||||
list($a, $b, $c, $d, $e, $f, $g, $h) = array_values(unpack('N*', $ai));
|
||||
|
||||
for ($i = 0; $i < 64; $i++) {
|
||||
$ss1 = $this->lm(
|
||||
($this->lm($a, 12) + $e + $this->lm($this->t($i), $i % 32) & 0xffffffff),
|
||||
7);
|
||||
$ss2 = $ss1 ^ $this->lm($a, 12);
|
||||
$tt1 = ($this->ff($i, $a, $b, $c) + $d + $ss2 + $wr1[$i]) & 0xffffffff;
|
||||
$tt2 = ($this->gg($i, $e, $f, $g) + $h + $ss1 + $wr[$i]) & 0xffffffff;
|
||||
$d = $c;
|
||||
$c = $this->lm($b, 9);
|
||||
$b = $a;
|
||||
$a = $tt1;
|
||||
$h = $g;
|
||||
$g = $this->lm($f, 19);
|
||||
$f = $e;
|
||||
$e = $this->p0($tt2);
|
||||
}
|
||||
|
||||
return pack('N*', $a, $b, $c, $d, $e, $f, $g, $h) ^ $ai;
|
||||
}
|
||||
|
||||
|
||||
private function ff($j, $x, $y, $z)
|
||||
{
|
||||
return $j < 16 ? $x ^ $y ^ $z : ($x & $y) | ($x & $z) | ($y & $z);
|
||||
}
|
||||
|
||||
private function gg($j, $x, $y, $z)
|
||||
{
|
||||
return $j < 16 ? $x ^ $y ^ $z : ($x & $y) | (~$x & $z);
|
||||
}
|
||||
|
||||
|
||||
private function lm($a, $n)
|
||||
{
|
||||
return ($a >> (32 - $n) | (($a << $n) & 0xffffffff));
|
||||
}
|
||||
|
||||
private function p0($x)
|
||||
{
|
||||
return $x ^ $this->lm($x, 9) ^ $this->lm($x, 17);
|
||||
}
|
||||
|
||||
private function p1($x)
|
||||
{
|
||||
return $x ^ $this->lm($x, 15) ^ $this->lm($x, 23);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
namespace Rtgm\util;
|
||||
|
||||
class FormatSign
|
||||
{
|
||||
public function run($sign)
|
||||
{
|
||||
list($binR, $binS) = $this->_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];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
namespace Rtgm\util;
|
||||
|
||||
class KeyCompress {
|
||||
/**
|
||||
* sm2压缩公钥计算全公钥
|
||||
*
|
||||
* @param string $compressedKey
|
||||
* @return string
|
||||
*/
|
||||
public static function decompressPublicKey($compressedKey)
|
||||
{
|
||||
// 获取压缩标志和X坐标
|
||||
$flag = substr($compressedKey, 0, 2);
|
||||
$x = substr($compressedKey, 2);
|
||||
|
||||
// 将16进制字符串转换为大整数
|
||||
$p = gmp_init('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 16);
|
||||
$a = gmp_init('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 16);
|
||||
$b = gmp_init('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 16);
|
||||
|
||||
// 计算Y坐标
|
||||
// y2 = x3 + ax + b
|
||||
$x = gmp_init($x, 16);
|
||||
$alpha = gmp_powm($x, 3, $p);
|
||||
$beta = gmp_add(gmp_mod(gmp_mul($a, $x), $p), $b);
|
||||
$y2 = gmp_mod(gmp_add($alpha, $beta), $p);
|
||||
$y = gmp_powm($y2, gmp_div_q(gmp_add($p, 1), 4), $p);
|
||||
|
||||
|
||||
// y2 的值开方有两个值,根据奇偶判定取哪一个
|
||||
if ($flag == "02") {
|
||||
// 如果压缩标志为“02”,则Y坐标为偶数
|
||||
if (gmp_strval(gmp_mod($y, 2)) == "0") {
|
||||
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
|
||||
} else {
|
||||
$y = gmp_sub($p, $y);
|
||||
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
|
||||
}
|
||||
} elseif ($flag == "03") {
|
||||
// 如果压缩标志为“03”,则Y坐标为奇数
|
||||
if (gmp_strval(gmp_mod($y, 2)) == "1") {
|
||||
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
|
||||
} else {
|
||||
$y = gmp_sub($p, $y);
|
||||
return "04" . gmp_strval($x, 16) . str_pad(gmp_strval($y, 16), 64, "0", STR_PAD_LEFT);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 压缩公钥
|
||||
*
|
||||
* @param string $publicKey
|
||||
* @return string
|
||||
*/
|
||||
public static function compressPublicKey($publicKey)
|
||||
{
|
||||
if (strlen($publicKey) == 130) {
|
||||
$publicKey = substr($publicKey, 2);
|
||||
}
|
||||
// 将16进制字符串转换为GMP数值
|
||||
$x = gmp_init(substr($publicKey, 0, 64), 16);
|
||||
$y = gmp_init(substr($publicKey, 64, 64), 16);
|
||||
|
||||
// 判断Y坐标奇偶性
|
||||
if (gmp_strval(gmp_mod($y, 2)) == "0") {
|
||||
$flag = "02";
|
||||
} else {
|
||||
$flag = "03";
|
||||
}
|
||||
|
||||
// 拼接压缩后的公钥
|
||||
$compressedPublicKey = $flag . str_pad(gmp_strval($x, 16), 64, "0", STR_PAD_LEFT);
|
||||
|
||||
return $compressedPublicKey;
|
||||
}
|
||||
}
|
||||
+647
@@ -0,0 +1,647 @@
|
||||
<?php
|
||||
|
||||
namespace Rtgm\util;
|
||||
|
||||
use FG\ASN1\ASNObject;
|
||||
use FG\ASN1\Identifier;
|
||||
|
||||
|
||||
class MyAsn1
|
||||
{
|
||||
const CLASS_UNIVERSAL = 0;
|
||||
const CLASS_APPLICATION = 1;
|
||||
const CLASS_CONTEXT_SPECIFIC = 2;
|
||||
const CLASS_PRIVATE = 3;
|
||||
const TYPE_BOOLEAN = 1;
|
||||
const TYPE_INTEGER = 2;
|
||||
const TYPE_BIT_STRING = 3;
|
||||
const TYPE_OCTET_STRING = 4;
|
||||
const TYPE_NULL = 5;
|
||||
const TYPE_OBJECT_IDENTIFIER = 6;
|
||||
const TYPE_OBJECT_DESCRIPTOR = 7;
|
||||
const TYPE_INSTANCE_OF = 8; // EXTERNAL
|
||||
const TYPE_REAL = 9;
|
||||
const TYPE_ENUMERATED = 10;
|
||||
const TYPE_EMBEDDED = 11;
|
||||
const TYPE_UTF8_STRING = 12;
|
||||
const TYPE_RELATIVE_OID = 13;
|
||||
const TYPE_SEQUENCE = 16; // SEQUENCE OF
|
||||
const TYPE_SET = 17; // SET OF
|
||||
const TYPE_NUMERIC_STRING = 18;
|
||||
const TYPE_PRINTABLE_STRING = 19;
|
||||
const TYPE_TELETEX_STRING = 20; // T61String
|
||||
const TYPE_VIDEOTEX_STRING = 21;
|
||||
const TYPE_IA5_STRING = 22;
|
||||
const TYPE_UTC_TIME = 23;
|
||||
const TYPE_GENERALIZED_TIME = 24;
|
||||
const TYPE_GRAPHIC_STRING = 25;
|
||||
const TYPE_VISIBLE_STRING = 26; // ISO646String
|
||||
const TYPE_GENERAL_STRING = 27;
|
||||
const TYPE_UNIVERSAL_STRING = 28;
|
||||
const TYPE_CHARACTER_STRING = 29;
|
||||
const TYPE_BMP_STRING = 30;
|
||||
const TYPE_CHOICE = -1;
|
||||
const TYPE_ANY = -2;
|
||||
const TYPE_ANY_RAW = -3;
|
||||
const TYPE_ANY_SKIP = -4;
|
||||
const TYPE_ANY_DER = -5;
|
||||
|
||||
public static function decode_file($pemfile)
|
||||
{
|
||||
$data = self::pem2der(file_get_contents($pemfile));
|
||||
// var_dump($data);
|
||||
return self::decode($data);
|
||||
}
|
||||
|
||||
public static function decode($data, $format = 'bin')
|
||||
{
|
||||
if ($format == 'base64') {
|
||||
$data = base64_decode($data);
|
||||
} else if ($format == 'hex') {
|
||||
$data = hex2bin($data);
|
||||
}
|
||||
$asnObject = ASNObject::fromBinary($data);
|
||||
return self::printObject($asnObject);
|
||||
}
|
||||
public static function printObject(ASNObject $object, $depth = 0)
|
||||
{
|
||||
$content = $object->getContent();
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
namespace Rtgm\util;
|
||||
|
||||
class SmSignFormatRS
|
||||
{
|
||||
public static function asn1_to_rs($str, $format = 'base64')
|
||||
{
|
||||
if ($format == 'base64') {
|
||||
$str = base64_decode($str);
|
||||
} else if ($format == 'hex') {
|
||||
$str = hex2bin($str);
|
||||
}
|
||||
$arr = \FG\ASN1\ASNObject::fromBinary($str);
|
||||
// var_dump($arr[0]->getContent());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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user