Git Product home page Git Product logo

phpsm2sm3sm4's Introduction

php sm2 sm3 sm4 国密算法整理

  • 本项目支持php版本的国密sm2的签名算法,非对称加解密算法,sm3的hash, sm4的对称加解密,要求PHP7,打开gmp支持
  • 目前如果服务器配套的使用的是openssl 1.1.1x, 目前到1.1.1.l(w) ,sm3,sm4都可以直接用openssl_xxx系列函数直接实现,不必大量的代码,不支持sm2的签名,sm2的加解密
  • 该版本是基于PHP-ECC,也支持其他的椭圆算法的,依赖比较多,如果只想要简单的 sm2相关的签名,加密,可以使用本版本的简化版 https://github.com/lpilp/simplesm2

安装

composer require lpilp/guomi

请确保你升级到 composer 2 及以上版本。PHP >=7.2,打开gmp组件支持。

如需要使用php5.6 请使用wzhih童鞋fork修改的 https://github.com/wzhih/guomi ;

composer require wzhih/guomi

或是使用该项目的简化版本 https://github.com/lpilp/simplesm2

使用

SM2

  • 签名验签算法主体基于PHPECC算法架构,添加了sm2的椭圆参数,
  • 参考了 https://github.com/ToAnyWhere/phpsm2 童鞋的sm2验签算法,密钥生成算法
  • 添加了签名算法, 支持sm2的16进制,base64公私钥的签名,验签算法
  • 支持从文件中读取pem文件的签名,验签算法
  • 由于 openssl没有实现sm2withsm3算法,用系统函数无法实现签名及证书的自签名分发

SM2非对称加密

  • 添加了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;
    }
}

phpsm2sm3sm4's People

Contributors

gokure avatar lpilp avatar tinywan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

phpsm2sm3sm4's Issues

验签的性能是否可以优化

生成签名的性能看着比较差,是否可以进行优化。
还有,RtSm2.php文件中 _dosign 方法 这段代码应该是可以去掉的吧 $publickey = $key->getPublicKey(); 看着比较耗性能。

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() );

用RtSm2报错:ASN.1 Parser Exception at offset 4: Integer not minimally encoded

     * 银行回复:
     * 支付回调中的签名的编码
     * 支付回调的签名的 ASN.1 编码中的 integer 编码没有省略开头多余的 0 字节
     * 比如:MEYCIQDWveKrtx6VrosnYQHNBnRjolrlmi/mHwMWKU4bDxakQwIhAH0l9tLPgotUrxUAYMfpETFN2dcWx7U9JKWXwF1R/KaH
     * 其中的正整数编码: 02 21 00 7D...., 00 7D 前9位全是0,其中的 00 字节应该被省略

大佬大佬有SM2对字符串加密解密的例子吗

找了好多资料都没有php的,官方手册也没个例子,根本看不懂哇。。大佬救救孩子吧!
需要一个用公钥将明文信息加密,然后使用私钥解密成明文的例子,不胜感激

关于招行某些接口的数字信封加密 sm2解密失败问题

你好大佬,最近有个问题卡了好久,招行的一些接口的返回数据进行了数字信封加密,就是自定义key通过sm2 加密,,我们拿到加密的key ,解出key ,再key用sm4解出对应的加密数据,现在问题是解不出这个key。不懂哪里出问题,能帮我看一下不
我这边的代码

$privateKey ='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
$encryptKey = 'yyyyyyyyyyyyyyyyyyyyyyyy';
        $sm2 = new RtSm2('base64');
        $encryptKey = bin2hex(base64_decode($encryptKey));
       // $key = $sm2->doDecrypt($encryptKey,$privateKey);
       $key = $sm2->doDecrypt($encryptKey,$privateKey,true,C1C2C3);

接口一直报错

Curve curve(115792089210356248756420345214020892766250353991924191454421193933289684991996, 18505919022281880113072981827955639221458448578012075254857346196103069175443, 115792089210356248756420345214020892766250353991924191454421193933289684991999) does not contain point (21923053047652226176961851790060037222566785743409165246174894147982436287639, 39907748959544104344143362640424285560854604783498473140463705333263725731102)

我补充下对方提供的java demo


    /**
     * 数字信封解密(SM4+SM2)
     * @param wDigEvp
     * @param encContents
     * @return
     */
    public static String[] decrypt(String privateKey, String wDigEvp, String... encContents) throws Exception {
        BCECPrivateKey bcecPrivateKey = GmUtil.getPrivatekeyFromD(new BigInteger(privateKey, 16));

        //SM2解密对称密钥
        byte[] wDigEvpByt = org.bouncycastle.util.encoders.Base64.decode(wDigEvp);
        System.out.println("HEX DEBUG:" + new String(Hex.encode(wDigEvpByt)));
        byte[] wOriKeyByt = sm2DecryptOld(cipherAsn1ToRaw(wDigEvpByt), bcecPrivateKey);


        System.out.println("解密出来的明文SM4密钥:" + new String(wOriKeyByt));
        System.out.println("解密出来的明文SM4密钥长度:" + wOriKeyByt.length);

        String[] contents = new String[encContents.length];
        for (int i = 0; i < encContents.length; i ++) {
            String wEcnTxt2 = encContents[i];
            byte wEncByt2[] = org.bouncycastle.util.encoders.Base64.decode(wEcnTxt2);

            byte[] bs = new byte[16];
            System.arraycopy(wOriKeyByt, 0, bs, 0, 16);
            System.out.println("解密出来的明文SM4密钥:" + new String(bs));
            //SM4解密
            byte[] wOriTxtByt = sm4DecryptCBC(bs, wEncByt2, SM4_CBC_IV);
            System.out.println("解密出来的明文:" + new String(wOriTxtByt));
        }
        return contents;
    }


 public static BCECPrivateKey getPrivatekeyFromD(BigInteger d) {
        ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(d,
                ecParameterSpec);
        return new BCECPrivateKey("EC", ecPrivateKeySpec,
                BouncyCastleProvider.CONFIGURATION);
    }

   /**
     * c1||c2||c3
     *
     * @param data
     * @param key
     * @return
     */
    public static byte[] sm2DecryptOld(byte[] data, PrivateKey key) {
        BCECPrivateKey localECPrivateKey = (BCECPrivateKey) key;
        ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(
                localECPrivateKey.getD(), ecDomainParameters);
        SM2Engine sm2Engine = new SM2Engine();
        sm2Engine.init(false, ecPrivateKeyParameters);
        try {
            return sm2Engine.processBlock(data, 0, data.length);
        } catch (InvalidCipherTextException e) {
            throw new RuntimeException(e);
        }
    }


SM2解密求助 | PHP对接Java

1. 背景

@lpilp 浏览了本项目所有的 issues ,测试无果后才来求助,先行感谢!

需要用 PHP 对接某行提供的 Java 接口,但是目前 SM2 解密后返回值为空字符串。

2. 步骤

先用 SM2 解密出 SM4 的秘钥,再进行 SM4 解密,得到数据明文。

3. 测试数据

// SM2私钥
$privateKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// SM4秘钥|SM2加密后
$skey = 'dddddddddddddddddddd';
// 加密数据|SM4加密后
$body = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy';
//
$privateKey = bin2hex(base64_decode($privateKey));
$skey = bin2hex(base64_decode($skey));
var_dump($skey);
// SM2解密|获取SM4秘钥
$key = (new RtSm2())->doDecrypt($skey, $privateKey);
var_dump($key);
// SM4解密
$data = (new RtSm4($key))->decrypt($body, 'sm4-ecb', '', 'hex');
var_dump($data);

4. Java 代码

// SM2 相关代码
public class SM2Util {
    private SM2Engine sm2Engine;
    private Signature signature;
    private static final String EC_VALUE = "EC";
    private static final String SM3SM2_VALUE = "SM3WITHSM2";
    private static final String CURVE_NAME = "sm2p256v1";
    private static final X9ECParameters X_9_EC_PARAMETERS = GMNamedCurves.getByName("sm2p256v1");
    private static final ECDomainParameters EC_DOMAIN_PARAMETERS;
    private static final ECParameterSpec PARAMETER_SPEC;
    private static KeyPairGenerator generator;

    public SM2Util() throws NoSuchProviderException, NoSuchAlgorithmException {
        this.sm2Engine = new SM2Engine(Mode.C1C3C2);
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        this.signature = Signature.getInstance("SM3WITHSM2", "BC");
        generator = KeyPairGenerator.getInstance("EC", "BC");
    }

    public byte[] encrypt(PublicKey publicKey, byte[] message) throws InvalidCipherTextException {
        synchronized(this) {
            BCECPublicKey localECPublicKey = (BCECPublicKey)publicKey;
            ECPublicKeyParameters ecPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), EC_DOMAIN_PARAMETERS);
            this.sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
            return this.sm2Engine.processBlock(message, 0, message.length);
        }
    }

    public byte[] decrypt(PrivateKey privateKey, byte[] message) throws InvalidCipherTextException {
        synchronized(this) {
            BCECPrivateKey localECPrivateKey = (BCECPrivateKey)privateKey;
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(localECPrivateKey.getD(), EC_DOMAIN_PARAMETERS);
            this.sm2Engine.init(false, ecPrivateKeyParameters);
            return this.sm2Engine.processBlock(message, 0, message.length);
        }
    }
}

// SM4相关代码
public class Sm4Util {
    private static final String ENCODING = "utf-8";
    public static final String ALGORITHM_NAME = "SM4";
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
    public static final int DEFAULT_KEY_SIZE = 128;

    public Sm4Util() {
    }

    private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
        Cipher cipher = Cipher.getInstance(algorithmName, "BC");
        Key sm4Key = new SecretKeySpec(key, algorithmName);
        cipher.init(mode, sm4Key);
        return cipher;
    }

    public static String encryptSm4(String hexKey, String paramStr) throws Exception {
        String cipherText = "";
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        byte[] srcData = paramStr.getBytes("utf-8");
        byte[] cipherArray = encryptSm4Padding(keyData, srcData);
        cipherText = ByteUtils.toHexString(cipherArray);
        return cipherText;
    }

    private static byte[] encryptSm4Padding(byte[] keyData, byte[] srcData) throws Exception {
        Cipher cipher = generateEcbCipher("SM4/ECB/PKCS7Padding", 1, keyData);
        return cipher.doFinal(srcData);
    }

    public static String decryptSm4(String hexKey, String cipherText) throws Exception {
        String decryptStr = "";
        byte[] keyData = ByteUtils.fromHexString(hexKey);
        byte[] cipherData = ByteUtils.fromHexString(cipherText);
        byte[] srcData = decryptSm4Padding(keyData, cipherData);
        decryptStr = new String(srcData, "utf-8");
        return decryptStr;
    }

    private static byte[] decryptSm4Padding(byte[] key, byte[] cipherData) throws Exception {
        Cipher cipher = generateEcbCipher("SM4/ECB/PKCS7Padding", 2, key);
        return cipher.doFinal(cipherData);
    }
}

SM2加密密文的排列方式的C1.C2.C3和C1.C3.C2区别

给我示例的java的代码排序方式是C1.C2.C3,而且加密完的密文会以04开头。调整PHP代码成C1.C2.C3并在前面加上04,java就能进行相应的解密。是我这边java的代码写的不标准吗?还是sm2有多种实现方式?

sm2对接java无法解密

如题:
1、java那边是c1c2c3标准
2、加密串前面存在04
3、密钥前面存在00
遇到问题:
1、如果解密是$trim=false,去除密文前面的04,则报错如下:
"Curve curve(115792089210356248756420345214020892766250353991924191454421193933289684991996, 18505919022281880113072981827955639221458448578012075254857346196103069175443, 115792089210356248756420345214020892766250353991924191454421193933289684991999) does not contain point (2220918082519640839271715907941306834420976183340709641538589670659070624315, 2317117560351423785808682426051180236027355204224107987385986039750006104008)"
2、我对c2,c3的取值顺序进行了调整,则$document的结果全是乱码
还请大佬帮忙解答一下 @lpilp

useDerandomizedSignatures属性设置

你好,使用中遇到如下问题:

RtSm2 类中 这个属性的作用 $useDerandomizedSignatures = true;

目前测试 true时 请求招行有sign失败的概率, 改成false 反而可以通过;

sm2签名里算出的z值跟java的不一样

感觉是我们这的java写的国密算法没按照标准来,感觉逻辑差不多,但是具体实现有区别,大佬可以的话帮忙看下。

感觉差别就是php用的是原码来算的,java用的是补码。java的BigInteger.toByteArray()试了下,在数字不大的情况下可以用unpack("c*", pack("L", $bigInt));实现,但是变成大数后就不知道怎么算了,求指点指点。

public byte[] sm2GetZ(byte[] userId, ECPoint userKey) {
        SM3Digest sm3 = new SM3Digest();
        int len = userId.length * 8;
        sm3.update((byte)(len >> 8 & 255));
        sm3.update((byte)(len & 255));
        sm3.update(userId, 0, userId.length);
        byte[] p = bigInteger2Bytes(this.ecc_a);
        sm3.update(p, 0, p.length);
        p = bigInteger2Bytes(this.ecc_b);
        sm3.update(p, 0, p.length);
        p = bigInteger2Bytes(this.ecc_gx);
        sm3.update(p, 0, p.length);
        p = bigInteger2Bytes(this.ecc_gy);
        sm3.update(p, 0, p.length);
        p = bigInteger2Bytes(userKey.getX().toBigInteger());
        sm3.update(p, 0, p.length);
        p = bigInteger2Bytes(userKey.getY().toBigInteger());
        sm3.update(p, 0, p.length);
        byte[] md = new byte[sm3.getDigestSize()];
        sm3.doFinal(md, 0);
        return md;
    }

public static byte[] bigInteger2Bytes(BigInteger value) {
        if (null == value) {
            return null;
        } else {
            byte[] valueBytes = value.toByteArray();
            byte[] result;
            if (valueBytes.length > 32) {
                result = new byte[32];
                System.arraycopy(valueBytes, valueBytes.length - 32, result, 0, 32);
                return result;
            } else if (valueBytes.length == 32) {
                return valueBytes;
            } else {
                result = new byte[32];
                Arrays.fill(result, (byte)0);
                System.arraycopy(valueBytes, 0, result, 32 - valueBytes.length, valueBytes.length);
                return result;
            }
        }
    }

sm4 cbc 解密失败

密文:(base64)L1R0VmZsY0wrazVXdjJnSUNETDJybHZyc2t6WUt5QVE4U21XK0hKTXBuVXhnVUg5aVlmNWg5NEJSdU42aVkzUUMzQmxJekcycXhZc1duYzAydnQvZXc9PQ==

ErrorException in Sm4.php line 299 未定义数组下标: 2

使用自带tsm2_encrypt.php有极低概率解密失败抛出异常

用的就是test目录下的tsm2_encrypt.php,密钥和字符串都没改。有极低概率会在第二个字符串解密的时候出现异常

加密后: 04223eeb12b1932812c63fa4b8c3666960a5a197e9edd39c9ec042f1c50a2d8e65b8c16d8f1e5bba2fd1a24cfb366eac34d16a829bd7efa16b81d7d1dc905e48feab153332508c70993ac2b235b39e1481b2bad8c8bc856c735ff742ac63f4e302787668634d7907529ae065cded3f9c9cec
Fatal error: Uncaught Mdanter\Ecc\Exception\PointNotOnCurveException: Curve curve(115792089210356248756420345214020892766250353991924191454421193933289684991996, 18505919022281880113072981827955639221458448578012075254857346196103069175443, 115792089210356248756420345214020892766250353991924191454421193933289684991999) does not contain point (1869758440365169714186716832290710150786431124184013618421006632868895141262, 46010032557580391633438832132725706206560994461458522435651677310790484909640) in D:\wwwroot\sm\vendor\mdanter\ecc\src\Primitives\Point.php:102
Stack trace:
#0 D:\wwwroot\sm\vendor\lpilp\guomi\src\sm\RtSm2.php(141): Mdanter\Ecc\Primitives\Point->__construct(Object(Mdanter\Ecc\Math\GmpMath), Object(Mdanter\Ecc\Curves\NamedCurveFp), Object(GMP), Object(GMP))
#1 D:\wwwroot\sm\tsm2_encrypt.php(19): Rtgm\sm\RtSm2->doDecrypt('04223eeb12b1932...', 'a7763cd4fe7db2a...')
#2 {main}
thrown in D:\wwwroot\sm\vendor\mdanter\ecc\src\Primitives\Point.php on line 102

对接招行CBS8,Invalid Sign

直接上代码

对方给到的Java demo

package com.cmbyc.security.util;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.*;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Enumeration;

/**
 * @author: KeXue
 * @time: 2022/8/25
 * @description: SM2加解密工具类
 */
@Slf4j
public class SM2Util {

    private SM2Util() {
        throw new IllegalStateException("Utility class");
    }

    private static final String STD_NAME = "sm2p256v1";

    /**
     * SM2加密算法
     *
     * @param publicKey 公钥
     * @param data      明文数据
     * @return
     */
    public static byte[] encrypt(String publicKey, byte[] data) {
        ECPublicKeyParameters ecPublicKeyParameters = encodePublicKey(Hex.decode(publicKey));
        SM2Engine engine = new SM2Engine();
        engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));

        byte[] bytes = null;
        try {
            byte[] cipherText = engine.processBlock(data, 0, data.length);
            bytes = C1C2C3ToC1C3C2(cipherText);
        } catch (Exception e) {
            log.warn("SM2加密时出现异常:" + e.getMessage());
        }
        return bytes;
    }

    /**
     * SM2解密算法
     *
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return
     */
    public static byte[] decrypt(String privateKey, byte[] cipherData) {
        ECPrivateKeyParameters ecPrivateKeyParameters = encodePrivateKey(Hex.decode(privateKey));
        SM2Engine engine = new SM2Engine();
        engine.init(false, ecPrivateKeyParameters);

        byte[] bytes = null;
        try {
            cipherData = C1C3C2ToC1C2C3(cipherData);
            bytes = engine.processBlock(cipherData, 0, cipherData.length);
        } catch (Exception e) {
            log.warn("SM2解密时出现异常:" + e.getMessage());
        }
        return bytes;
    }

    /**
     * 签名算法
     *
     * @param privateKey 私钥
     * @param data       明文数据
     * @return
     */
    public static byte[] sign(String privateKey, byte[] data) {
        ECPrivateKeyParameters ecPrivateKeyParameters = encodePrivateKey(hexToByte(privateKey));
        SM2Signer signer = new SM2Signer();
        ParametersWithID parameters = new ParametersWithID(ecPrivateKeyParameters, "1234567812345678".getBytes());
        signer.init(true, parameters);
        signer.update(data, 0, data.length);

        byte[] signature = null;
        try {
            signature = decodeDERSignature(signer.generateSignature());
        } catch (Exception e) {
            log.warn("SM2签名时出现异常:" + e.getMessage());
        }
        return signature;
    }

    private static byte[] hexToByte(String hex)
            throws IllegalArgumentException {
        if (hex.length() % 2 != 0) {
            throw new IllegalArgumentException();
        }
        char[] arr = hex.toCharArray();
        byte[] b = new byte[hex.length() / 2];
        for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
            String swap = "" + arr[i++] + arr[i];
            int byteInt = Integer.parseInt(swap, 16) & 0xFF;
            b[j] = BigInteger.valueOf(byteInt).byteValue();
        }
        return b;
    }

    private static byte[] C1C2C3ToC1C3C2(byte[] cipherText) throws Exception {
        if (cipherText != null && cipherText.length >= 97) {
            byte[] bytes = new byte[cipherText.length];
            System.arraycopy(cipherText, 0, bytes, 0, 65);
            System.arraycopy(cipherText, cipherText.length - 32, bytes, 65, 32);
            System.arraycopy(cipherText, 65, bytes, 97, cipherText.length - 97);
            return bytes;
        } else {
            throw new Exception("SM2 cipher text error, must be more than 96 bytes and in the format C1||C3||C2.");
        }
    }

    private static byte[] C1C3C2ToC1C2C3(byte[] cipherText) throws Exception {
        if (cipherText != null && cipherText.length >= 97) {
            byte[] bytes = new byte[cipherText.length];
            System.arraycopy(cipherText, 0, bytes, 0, 65);
            System.arraycopy(cipherText, 97, bytes, 65, cipherText.length - 97);
            System.arraycopy(cipherText, 65, bytes, cipherText.length - 32, 32);
            return bytes;
        } else {
            throw new Exception("SM2 cipher text error, must be more than 96 bytes and in the format C1||C3||C2.");
        }
    }

    private static ECPublicKeyParameters encodePublicKey(byte[] value) {
        byte[] x = new byte[32];
        byte[] y = new byte[32];
        System.arraycopy(value, 1, x, 0, 32);
        System.arraycopy(value, 33, y, 0, 32);
        BigInteger X = new BigInteger(1, x);
        BigInteger Y = new BigInteger(1, y);
        ECPoint Q = getSM2Curve().createPoint(X, Y);
        return new ECPublicKeyParameters(Q, getECDomainParameters());
    }

    private static ECCurve getSM2Curve() {
        ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(STD_NAME);
        return spec.getCurve();
    }

    private static ECPrivateKeyParameters encodePrivateKey(byte[] value) {
        BigInteger d = new BigInteger(1, value);
        return new ECPrivateKeyParameters(d, getECDomainParameters());
    }

    private static ECDomainParameters getECDomainParameters() {
        ECParameterSpec spec = ECNamedCurveTable.getParameterSpec(STD_NAME);
        return new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH(), spec.getSeed());
    }

    private static byte[] decodeDERSignature(byte[] signature) {
        ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));

        byte[] bytes = new byte[64];
        try {
            ASN1Sequence primitive = (ASN1Sequence) stream.readObject();
            Enumeration enumeration = primitive.getObjects();
            BigInteger R = ((ASN1Integer) enumeration.nextElement()).getValue();
            BigInteger S = ((ASN1Integer) enumeration.nextElement()).getValue();
            byte[] r = format(R.toByteArray());
            byte[] s = format(S.toByteArray());
            System.arraycopy(r, 0, bytes, 0, 32);
            System.arraycopy(s, 0, bytes, 32, 32);
        } catch (Exception e) {
            log.warn("decodeDERSignature时出现异常:" + e.getMessage());
        }
        return bytes;
    }

    public static byte[] encodeDERSignature(byte[] signature) {
        byte[] r = new byte[32];
        byte[] s = new byte[32];
        System.arraycopy(signature, 0, r, 0, 32);
        System.arraycopy(signature, 32, s, 0, 32);
        ASN1EncodableVector vector = new ASN1EncodableVector();
        vector.add(new ASN1Integer(new BigInteger(1, r)));
        vector.add(new ASN1Integer(new BigInteger(1, s)));

        byte[] encoded = null;
        try {
            encoded = (new DERSequence(vector)).getEncoded();
        } catch (Exception e) {
            log.warn("encodeDERSignature时出现异常:" + e.getMessage());
        }
        return encoded;
    }

    private static byte[] format(byte[] value) {
        if (value.length == 32) {
            return value;
        } else {
            byte[] bytes = new byte[32];
            if (value.length > 32) {
                System.arraycopy(value, value.length - 32, bytes, 0, 32);
            } else {
                System.arraycopy(value, 0, bytes, 32 - value.length, value.length);
            }
            return bytes;
        }
    }
}

PHP对接

<?php

use Rtgm\sm\RtSm2;

require 'vendor/autoload.php';

//密钥皆为明文
$privateKey = 'xxx';
$publicKey = 'xxxx';
$userId = '1234567812345678';

$requestParam = [
    'startDate' => '2023-05-01',
    'endDate' => date('Y-m-d'),
    'dateType' => 0,
];
$requestJson = json_encode($requestParam);
$timestamp = time(). '000';
$document = $requestJson. '&timestamp='. $timestamp;

$sm2 = new RtSm2('base64');

$sign = $sm2->doSign($document, $privateKey, $userId);




//加密
$sm2 = new RtSm2();

$m2EncryptData = $sm2 ->doEncrypt($requestJson, $publicKey);


$header[] = 'Content-Type: application/json';
$header[] = 'X-MBCLOUD-API-SIGN: '. trim($sign);
$header[] = 'Authorization: Bearer xxx';
$header[] = 'X-MBCLOUD-TIMESTAMP: '. $timestamp;

请求接口一直返回{"code":"500","msg":"Invalid Sign","data":null}

Java的demo可以跑通,打印出来的sign与PHP生成的sign基本一致,请大佬看看Java生成的sign和PHP的生成有何不同之处,感激!

请教关于掌上生活 Sm3WithSm2 签名问题

招行在线测试

https://open.cmbchina.com/Platform/#/test/tools/signProtocol

测试密钥

Private Key

af6443adfe00684f1cc646661877db7b9cc2f85979e1f60f1f081d61a1397a8b

Publick Key

04dc02516a229e0c19ff78e75a3943c0c877cf41f7fac1f89b921f0bf98a197b4adf180be8c30b02b8cbd13bf7a70f1a6ca626a0b63fec11c8256b5e2c925d3453

测试 MSG

cmblife://approval?aid=1234567890&clientType=h5&date=20221010111302&mid=1234567890&random=217395f3019a4613aacd5e363068a2a7&callback=javascript%3AcallbackApproval&responseType=code&scope=defaultScope&state=1234567890

尝试

我使用 测试 MSG 在掌上生活在线进行签名,然后在线验证签名是可以验证通过。

但使用本库生成出来的 sign 结果验证失败。

由于我不是很了解国密,所以做了以下相关尝试都不正确。

参数

$str = 'cmblife://approval?aid=1234567890&clientType=h5&date=20221010111302&mid=1234567890&random=217395f3019a4613aacd5e363068a2a7&callback=javascript%3AcallbackApproval&responseType=code&scope=defaultScope&state=1234567890';

$privateKey='af6443adfe00684f1cc646661877db7b9cc2f85979e1f60f1f081d61a1397a8b';

第一种,直接 SM2->Sign

        $privateKey = config('zssh.privateKey');
        $key = bin2hex(base64_decode($privateKey));
        $sm2 = new RtSm2('base64', false);
        $doSign = $sm2->doSign($str, $key);
        var_dump($doSign);

第二种,SM2->Sign(SM3->sign,privateKey)

        $sm3 = new RtSm3();
        $digest = $sm3->digest($str);

        $privateKey = config('zssh.privateKey');
        $key = bin2hex(base64_decode($privateKey));

        $sm2 = new RtSm2('base64', false);
        $doSign = $sm2->doSign($digest, $key);

        var_dump($doSign);

第三种,不对 privateKey 做任何处理

        $privateKey = config('zssh.privateKey');
        $sm2 = new RtSm2('base64', false);
        $doSign = $sm2->doSign($str, $privateKey);
        var_dump($doSign);

问题

我也看了 Readme 里所提到的关于招行补 0 的问题,使用 src/util/FormatSign->format_cmbc 过滤 Sign,比如上述代码,我把 $doSign 结果放入 format_cmbc 里执行,其结果和未 format 的base64 一致。

所以这个情况该怎么使用本库?谢谢~

sm2加密公钥

在跟银行做对接时,对方提供的 sm2 加密公钥长度为 66 位,03 开头。

查了下资料说是公钥分 x、y 两部分,x 为 02 开头,y 为 03 开头,04 表示完整公钥未压缩。

想问下大佬有方法将 x 或 y 还原成完整的公钥吗?或者是 sm2 支持下压缩密钥的加解密?

招行SM2解密失败

请教一下为什么使用招行的SM2解密不出来数据,调用doDecrypt 方法报错 PPHP Fatal error: Uncaught Mdanter\Ecc\Exception\PointNotOnCurveException: Curve curve(115792089210356248756420345214020892766250353991924191454421193933289684991996, 18505919022281880113072981827955639221458448578012075254857346196103069175443, 115792089210356248756420345214020892766250353991924191454421193933289684991999) does not contain point (21923053050521176574017647783284950498893389114667304193717803804932173814757, 56509344826246672192550335824034926620678438138637932737988965091437702175940) in /Users/flying/.composer/vendor/mdanter/ecc/src/Primitives/Point.php:104

SM2密文如下:
042b1c1eff060f1ad922fd0af05e4c613f436f799c9c96e0de8ca15be57cef27de5287a0703fdec5404d7c08e08a89049d23267892fbfa7c925cc453f2c1ca30a643426f3068e98f4ebf945d57f12b479fb2f91e7ce683c56c8d05478e2d58b9650ee886229b5599befb29d71d802a47b7

是否可以加个qq(90)或者微信(LittlMo)

你好大佬 我用你的验证包 和https://const.net.cn/tool/sm2/verify/ 这个网站相互验签总是失败怎么回事

你好大佬 我用你的验证包 和https://const.net.cn/tool/sm2/verify/ 这个网站相互验签总是失败怎么回事
大佬我说的是sm2 签名和验签
我先doSing 生成了签名
因为没有R值和S值 我需要
导出R值和S值
$sm2 = new RtSm2();
$sign = $sm2->doSign($data, $key, $userid);
$signData= hex2bin($sign);
$a = \FG\ASN1\ASNObject::fromBinary($signData)->getChildren();

$rr= formatHex($a[0]->getContent());
$ss= formatHex($a[1]->getContent());
$sign = $rr. $ss;
$sign = hex2bin($sign); //这个是R/S签名

以下是验签
$signHex = bin2hex($sign);
$r = substr($signHex, 0, 64);
$s = substr($signHex, 64, 64);

$r = gmp_init($r, 16);
$s = gmp_init($s, 16);

$signature = new Signature( $r, $s );
$serializer = new DerSignatureSerializer();
$serializedSig = $serializer->serialize($signature);
$sign = bin2hex($serializedSig) ;

$b = $sm2->verifySign($data, $sign, $publicKey, $userid);

function formatHex($dec)
{

$hex = gmp_strval(gmp_init($dec, 10), 16);
$len = strlen($hex);
if ($len == 64) {
    return $hex;
}
if ($len < 64){
    $hex = str_pad($hex, 64, "0", STR_PAD_LEFT);
}else {
    $hex = substr($hex, $len - 64, 64);
}

return $hex;

}

这样是自己是可以验证签名的 但是和别的网站却不能互签互验
求大佬帮帮忙 解决以下到底什么原因 我都快崩溃了

关于招行的验签

你好,我现在在用这个库处理业务,也成功处理了几个项目,很有帮助,首先感谢。
然后最近我在对接招行,目前验签的部分一直失败,我的代码如下
$fs = new FormatSign(); $newSign = $fs->run($badSign); echo $newSign."\n"; $sm2 = new RtSm2('base64'); $ret = $sm2->verifySign($data, $newSign, $publicKey, '1234567812345678');

这样返回false,而用招行的demo是返回true。
如果不做FormatSign::run,直接验签则会异常。
我有看到readme中关于招行验签的说明,可能我没看懂,希望得到指点,谢谢

composer安装不了 使用的框架是laravel

Problem 1
- lpilp/guomi[v1.0.0, ..., v1.0.2] require mdanter/ecc 0.5.2 -> satisfiable by mdanter/ecc[v0.5.2].
- lpilp/guomi 1.0.3 requires mdanter/ecc ^1.0 -> satisfiable by mdanter/ecc[v1.0.0].
- mdanter/ecc v0.5.2 requires php ^7.0 -> your php version (8.0.3) does not satisfy that requirement.
- mdanter/ecc v1.0.0 requires ext-gmp * -> it is missing from your system. Install or enable PHP's gmp extension.
- Root composer.json requires lpilp/guomi ^1.0 -> satisfiable by lpilp/guomi[v1.0.0, v1.0.1, v1.0.2, 1.0.3].

To enable extensions, verify that they are enabled in your .ini files:
- D:\phpstudy_pro\Extensions\php\php8.0.3nts\php.ini
You can also run php --ini inside terminal to see which files are used by PHP in CLI mode.

还是招行问题,看完了issue没有理解,求大佬解答,感谢

编辑下方便后来者们捡个现成
招行云直联,直接用大佬的sdk
加密完
\Rtgm\util\SmSignFormatRS::asn1_to_rs 过一下丢给招行
招行的返回,
\Rtgm\util\SmSignFormatRS::rs_to_asn1 过一下再验签就行

重点:
验签公钥要用招行公钥,不是用户公钥 !!!!
验签公钥要用招行公钥,不是用户公钥 !!!!
验签公钥要用招行公钥,不是用户公钥 !!!!

1、关于加密,
大佬在其它issue和样例代码提到需要先format_cmbc,但我实测不行,用别人的代码加密可以过

   //标准处理sm2 sign
    $key = base64_decode($this->_priKey);
    $key = bin2hex($key);//转为16进制
    $sm2 = new RtSm2("base64");
    $sm2_sign = $sm2->doSign($data_str, $key, $iv);
    $sm2_sign = trim($sm2_sign);
    //招行单独处理-大佬您的
    $fs = new \Rtgm\util\FormatSign();
    $final_sign = $fs->format_cmbc($sm2_sign);
    //招行单独处理-别人
    $tmp = base64_decode($sm2_sign);
    $a = \FG\ASN1\ASNObject::fromBinary($tmp)->getChildren();
    $aa = $this->_formatHex($a[0]->getContent());
    $bb = $this->_formatHex($a[1]->getContent());
    $cc = $aa . $bb;
    $final_sign = base64_encode(hex2bin($cc));
    //最终别人的可以过招行,但是大佬的不行       

想了解是为什么呢,别人的代码我是learnku看的(地址/articles/68557)

2、关于解密
我收到招行response后

    $bak_sign = $array["signature"]["sigdat"];
    $fs = new \Rtgm\util\FormatSign();
    $bak_sign2 = $fs->run($bak_sign);

会卡死,无法解密

但是如果不用大佬的代码,直接

    $array["signature"]["sigdat"] = '__signature_sigdat__';
    $array = $this->_dataSort($array);

    $sm2 = new RtSm2("base64");
    $json = json_encode($array, JSON_UNESCAPED_UNICODE);
    $signHex = bin2hex(base64_decode($bak_sign));
    $r = substr($signHex, 0, 64);
    $s = substr($signHex, 64, 64);
    $r = gmp_init($r, 16);
    $s = gmp_init($s, 16);
    $signature = new \Mdanter\Ecc\Crypto\Signature\Signature($r, $s);
    $serializer = new DerSignatureSerializer();
    $serializedSig = $serializer->serialize($signature);
    $sign = base64_encode($serializedSig);
    $publicKey = bin2hex(base64_decode($this->_pubKey));
    $b = $sm2->verifySign($json, $sign, $publicKey, $userId);

必定校验不过
运行大佬的demo是没问题的,没有思路,求大佬赐教,感谢感谢

和java对接,SM2无法解密数据

发送过来的加密数据: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
私钥:xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
php代码:
$sm2 = new RtSm2();
$originalData = $sm2->doDecrypt(bin2hex(base64_decode($encryptData)), $privateKey);
解出来的数据为空。
感觉和issues#33问题很像
如果,第3个参数改为,false,去掉前面的04,则报错
$originalData = $sm2->doDecrypt(bin2hex(base64_decode($encryptData)), $privateKey, false);
报错如下:
"message": "Curve curve(115792089210356248756420345214020892766250353991924191454421193933289684991996, 18505919022281880113072981827955639221458448578012075254857346196103069175443, 115792089210356248756420345214020892766250353991924191454421193933289684991999) does not contain point (2017088389800493414537223642471494436295912431580677090622203970508929808211, 46515205910672524411678083181661249619220354456023358688557825284463176619131)",
"exception": "Mdanter\Ecc\Exception\PointNotOnCurveException",
"file": "C:\phpstudy_pro\WWW\www.dianzibaohan.com.cn\dianzibaohan\vendor\mdanter\ecc\src\Primitives\Point.php",
"line": 102,
"trace": [
{
"file": "C:\phpstudy_pro\WWW\www.dianzibaohan.com.cn\dianzibaohan\vendor\lpilp\guomi\src\sm\RtSm2.php",
"line": 156,
"function": "__construct",
"class": "Mdanter\Ecc\Primitives\Point",
"type": "->"
},
{
"file": "C:\phpstudy_pro\WWW\www.dianzibaohan.com.cn\dianzibaohan\app\Http\Controllers\Api\LiaoningController.php",
"line": 968,
"function": "doDecrypt",
"class": "Rtgm\sm\RtSm2",
"type": "->"

麻烦问一下@lpilp,如果按照issues#33的方法,怎么使用asn1换成C1C3C2。。

报错 public key format error

我使用 sm2 生成了一对公私秘钥,然后用公钥加密,报错 public key format error

我看源码要求秘钥的长度必须是128位和130位,其他的都不对

请问服务器openssl版本需要多少能正常使用sm2加密解密呢?

目前如果服务器配套的使用的是openssl 1.1.1x, 目前到1.1.1.l(t) ,sm3,sm4都可以直接用openssl_xxx系列函数直接实现,不必大量的代码,但不支持sm2的签名,sm2的加解密

请问服务器openssl版本需要多少能正常使用sm2加密解密呢?
我服务器上的openssl是1.1.1f,加密后c#解密不了

sm2 解密失败

Curve curve(115792089210356248756420345214020892766250353991924191454421193933289684991996, 18505919022281880113072981827955639221458448578012075254857346196103069175443, 115792089210356248756420345214020892766250353991924191454421193933289684991999) does not contain point (2137854832359249130018667759494391183761873155309590729559322389203168722373, 111751830531928666539205041330488512151142167531666828532858683705993727777102)

您好,对接的是浦发的sm2

gmp_init(): Unable to convert variable to GMP - string is not an integer in file /Users/szh/laravel/nmydmall/vendor/lpilp/guomi/src/sm/RtSm2.php on line 170
解密的时候他的密文我得到的就是这个错误

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.