gmsm icon indicating copy to clipboard operation
gmsm copied to clipboard

JAVA对GO生成的签名,验证失败.

Open aomirun opened this issue 2 years ago • 44 comments

aomirun avatar Jun 09 '22 06:06 aomirun

fork代码修改后,可以正常做 SM2WITHSM3了,但是对方是JAVA服务端,验证签名失败. 正常的PKCS1祼签JAVA方也不能验证. 查看了一下ASN1的数据 GO生成的签名,R,S长度32,JAVA长度33

GO可以验证JAVA和GO自己的签名 JAVA不能验证GO生成的签名

GO

ASN.1 Sequence (70字节)
    ASN.1 Integer (32字节)
    49953602798973186633919026302796227754575575121265967941549104619692819388197
    ASN.1 Integer (32字节)
    6323159028519601678585446620409841784998903456586007702140898792008835206132

JAVA

ASN.1 Sequence (72字节)
    ASN.1 Integer (33字节)
    70468025293370294943352223829577765421262310906429137293791810763219733692696
    ASN.1 Integer (33字节)
    98640631558403820175130960459496903133090903563226543449918394768633700812864

aomirun avatar Jun 25 '22 05:06 aomirun

请问是否有解决方案了?我看java和go在生成密钥时候就不一样,java的公钥是获取的Q,但是golang是获取的X、Y,还请有大佬解答下

jiuerzhange avatar Jul 21 '22 11:07 jiuerzhange

@aomirun 请教下 SM2WITHSM3是怎么实现的啊

sax1412 avatar Jul 25 '22 10:07 sax1412

@sax1412 因国密PKCS7各服务端验证有所区别,根据对方pkcs7签名的ASN1结构,来修改PKCS7生成的参数.

aomirun avatar Jul 26 '22 03:07 aomirun

@jiuerzhange 目前还没有,主要是国密签名机好像对C 系的uin8没有做支持,使得最终签名验证失败.

aomirun avatar Jul 26 '22 03:07 aomirun

感觉某些地方不严谨, 没有与其它语言C、java做关联性验证。 导致自己加密解密,不能与其它语言兼容使用。 算法是正确的,就是细节问题。

lala0257 avatar Sep 23 '22 07:09 lala0257

sm2的加解密我拿java互通了,可签名验签没搞了,有大佬整一下吗

liuhaichaogithub avatar Oct 15 '22 06:10 liuhaichaogithub

sm2的加解密我拿java互通了,可签名验签没搞了,有大佬整一下吗

求一下,java与go互通这块的资料。我java是用hutool生成的,在go这里一直通不了。

4color avatar Oct 19 '22 00:10 4color

golang

大佬,有go的demo吗?我这边跟java的老是互通不了

jqtong avatar Nov 11 '22 09:11 jqtong

解决了吗?我这也不通

jqtong avatar Nov 11 '22 09:11 jqtong

解决了吗?我这也不通

我只是加解密可以了,签名没试过,你可以参考一下。https://blog.csdn.net/4color/article/details/127305555

4color avatar Nov 14 '22 00:11 4color

解决了吗?我这也不通

我解决了、具体参考我写的博客https://blog.csdn.net/hahawangzi520/article/details/126187783

jiuerzhange avatar Dec 13 '22 01:12 jiuerzhange

sm2的加解密我拿java互通了,可签名验签没搞了,有大佬整一下吗

我解决了、具体参考我写的博客https://blog.csdn.net/hahawangzi520/article/details/126187783

jiuerzhange avatar Dec 13 '22 01:12 jiuerzhange

对接过招行,所以看了一下招行的java使用demo,使用的是hutool的加密库,签名曲线用的sm2p256v1,对SM2Signer生成的签名进行了自定义解析 我自己使用本库gm2的默认签名和验签进行了简单修改,以下仅包含签名的简单示例代码

// gmsm库的sm2签名
r, s, err := Sm2Sign(priv, msg, nil, random)
	if err != nil {
		return nil, err
	}
	return asn1.Marshal(sm2Signature{r, s})

最终返回的是asn1的结构体序列化,可以将r,s的[]byte添加到bytes.Buffer,[]byte长度为32不足前面补0

// 修改后的签名
        rByte := r.Bytes()
	sByte := s.Bytes()
        if len(rByte) < 32 {
		rByte = append([]byte{0}, rByte...)
	}
	if len(sByte) < 32 {
		sByte = append([]byte{0}, sByte...)
	}
        var buffer bytes.Buffer
	buffer.Write(rByte)
	buffer.Write(sByte)

java的demo中的签名

        ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(),spec.getH(),spec.getSeed());
        ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(1, key), domainParameters);
        ParametersWithID parameters = new ParametersWithID(privateKey, "1234567812345678".getBytes());
        byte[] data = msg.getBytes();
        SM2Signer signer = new SM2Signer();
        signer.init(true, parameters);
        signer.update(data, 0, data.length);
        public byte[] signature=signer.generateSignature();
        ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));
        try {
            ASN1Sequence primitive = (ASN1Sequence)stream.readObject();
            Enumeration enumeration = primitive.getObjects();
            BigInteger R = ((ASN1Integer)enumeration.nextElement()).getValue();
            BigInteger S = ((ASN1Integer)enumeration.nextElement()).getValue();
            byte[] bytes = new byte[64];
            byte[] r = format(R.toByteArray());
            byte[] s = format(S.toByteArray());
            System.arraycopy(r, 0, bytes, 0, 32);
            System.arraycopy(s, 0, bytes, 32, 32);
            return bytes;
        } catch (Exception e) {
            throw new Exception();
        }

lish96 avatar Jan 26 '23 14:01 lish96

对接过招行,所以看了一下招行的java使用demo,使用的是hutool的加密库,签名曲线用的sm2p256v1,对SM2Signer生成的签名进行了自定义解析 我自己使用本库gm2的默认签名和验签进行了简单修改,以下仅包含签名的简单示例代码

// gmsm库的sm2签名
r, s, err := Sm2Sign(priv, msg, nil, random)
	if err != nil {
		return nil, err
	}
	return asn1.Marshal(sm2Signature{r, s})

最终返回的是asn1的结构体序列化,可以将r,s的[]byte添加到bytes.Buffer,[]byte长度为32不足前面补0

// 修改后的签名
        rByte := r.Bytes()
	sByte := s.Bytes()
        if len(rByte) < 32 {
		rByte = append([]byte{0}, rByte...)
	}
	if len(sByte) < 32 {
		sByte = append([]byte{0}, sByte...)
	}
        var buffer bytes.Buffer
	buffer.Write(rByte)
	buffer.Write(sByte)

java的demo中的签名

        ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(),spec.getH(),spec.getSeed());
        ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(1, key), domainParameters);
        ParametersWithID parameters = new ParametersWithID(privateKey, "1234567812345678".getBytes());
        byte[] data = msg.getBytes();
        SM2Signer signer = new SM2Signer();
        signer.init(true, parameters);
        signer.update(data, 0, data.length);
        public byte[] signature=signer.generateSignature();
        ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));
        try {
            ASN1Sequence primitive = (ASN1Sequence)stream.readObject();
            Enumeration enumeration = primitive.getObjects();
            BigInteger R = ((ASN1Integer)enumeration.nextElement()).getValue();
            BigInteger S = ((ASN1Integer)enumeration.nextElement()).getValue();
            byte[] bytes = new byte[64];
            byte[] r = format(R.toByteArray());
            byte[] s = format(S.toByteArray());
            System.arraycopy(r, 0, bytes, 0, 32);
            System.arraycopy(s, 0, bytes, 32, 32);
            return bytes;
        } catch (Exception e) {
            throw new Exception();
        }

这是解决了吗,我看了 一下很多都是验签的问题,我现在也卡在这里

ahKevinXy avatar Feb 02 '23 08:02 ahKevinXy

对接过招行,所以看了一下招行的java使用demo,使用的是hutool的加密库,签名曲线用的sm2p256v1,对SM2Signer生成的签名进行了自定义解析 我自己使用本库gm2的默认签名和验签进行了简单修改,以下仅包含签名的简单示例代码

// gmsm库的sm2签名
r, s, err := Sm2Sign(priv, msg, nil, random)
	if err != nil {
		return nil, err
	}
	return asn1.Marshal(sm2Signature{r, s})

最终返回的是asn1的结构体序列化,可以将r,s的[]byte添加到bytes.Buffer,[]byte长度为32不足前面补0

// 修改后的签名
        rByte := r.Bytes()
	sByte := s.Bytes()
        if len(rByte) < 32 {
		rByte = append([]byte{0}, rByte...)
	}
	if len(sByte) < 32 {
		sByte = append([]byte{0}, sByte...)
	}
        var buffer bytes.Buffer
	buffer.Write(rByte)
	buffer.Write(sByte)

java的demo中的签名

        ECParameterSpec spec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(),spec.getH(),spec.getSeed());
        ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(1, key), domainParameters);
        ParametersWithID parameters = new ParametersWithID(privateKey, "1234567812345678".getBytes());
        byte[] data = msg.getBytes();
        SM2Signer signer = new SM2Signer();
        signer.init(true, parameters);
        signer.update(data, 0, data.length);
        public byte[] signature=signer.generateSignature();
        ASN1InputStream stream = new ASN1InputStream(new ByteArrayInputStream(signature));
        try {
            ASN1Sequence primitive = (ASN1Sequence)stream.readObject();
            Enumeration enumeration = primitive.getObjects();
            BigInteger R = ((ASN1Integer)enumeration.nextElement()).getValue();
            BigInteger S = ((ASN1Integer)enumeration.nextElement()).getValue();
            byte[] bytes = new byte[64];
            byte[] r = format(R.toByteArray());
            byte[] s = format(S.toByteArray());
            System.arraycopy(r, 0, bytes, 0, 32);
            System.arraycopy(s, 0, bytes, 32, 32);
            return bytes;
        } catch (Exception e) {
            throw new Exception();
        }

这是解决了吗,我看了 一下很多都是验签的问题,我现在也卡在这里

我这边是验签通过了的,Java端验签,具体得看Java端对签名值的解析方式,像我这边对接的他是要求128位长度的hex,但是本库的签名返回对象是ASN1的结构体,得到的一般是144位,偶尔长度不够,所以需要补0,单从长度上就不一致,看hutool工具类的验签实现,他是利用解析的两个大数,R和S来做的验证,所以他转成[]byte后直接截取[]byte的前32位 和后32位分别做R和S就通过了,所以我这边做了一下转换,两边统一了序列化对象应该没什么问题

lish96 avatar Feb 03 '23 01:02 lish96

我解决了java和go之间的国密算法签名问题、具体参考我写的博客、花了很多精力攻克的、虽然是付费的、也希望大佬能支持下原创。

https://blog.csdn.net/hahawangzi520/article/details/126187783

jiuerzhange avatar Feb 03 '23 01:02 jiuerzhange

@ahKevinXy 我解决了java和go之间的国密算法签名问题、具体参考我写的博客、花了很多精力攻克的、虽然是付费的、也希望大佬能支持下原创。

https://blog.csdn.net/hahawangzi520/article/details/126187783

jiuerzhange avatar Feb 03 '23 01:02 jiuerzhange

@ahKevinXy 我解决了java和go之间的国密算法签名问题、具体参考我写的博客、花了很多精力攻克的、虽然是付费的、也希望大佬能支持下原创。

https://blog.csdn.net/hahawangzi520/article/details/126187783

没事 我写了一个 Java 的sdk 解决了,付费就没有必要看了

ahKevinXy avatar Feb 06 '23 02:02 ahKevinXy

这边 可以提供一下源码吗,最近我也是对接招商银行,就是验签不通

ahKevinXy avatar Feb 06 '23 02:02 ahKevinXy

这边 可以提供一下源码吗,最近我也是对接招商银行,就是验签不通

上面的示例代码就可以,修改后的签名就是(验签同理),健壮性你自己保证

lish96 avatar Feb 06 '23 03:02 lish96

我用 Java 写了一个单独的验签了

ahKevinXy avatar Mar 07 '23 06:03 ahKevinXy

我解决了java和go之间的国密算法签名问题、具体参考我写的博客、花了很多精力攻克的、虽然是付费的、也希望大佬能支持下原创。

https://blog.csdn.net/hahawangzi520/article/details/126187783

我就去看了,然而什么内容都没讲到,引用他的原文“(4)golang golang的sm2解密有时候成功,有时候失败,经过我反复测试,是testing依赖模块导致的,但是底层原因未知,我把代码放到run.go的main方法里,都是正常执行。如果有小伙伴懂的话,可以私信我。” 下面例子也是普通的例子,这就叫解决了?!

jinigithub avatar Mar 09 '23 08:03 jinigithub

我解决了java和go之间的国密算法签名问题、具体参考我写的博客、花了很多精力攻克的、虽然是付费的、也希望大佬能支持下原创。 https://blog.csdn.net/hahawangzi520/article/details/126187783

我就去看了,然而什么内容都没讲到,引用他的原文“(4)golang golang的sm2解密有时候成功,有时候失败,经过我反复测试,是testing依赖模块导致的,但是底层原因未知,我把代码放到run.go的main方法里,都是正常执行。如果有小伙伴懂的话,可以私信我。” 下面例子也是普通的例子,这就叫解决了?!

源码发一下

ahKevinXy avatar Mar 10 '23 05:03 ahKevinXy

@ahKevinXy 用 Golang 写了一个完整的示例 https://github.com/hxkjason/cmb_SM3withSM2_sign_demo, FYI。

hxkjason avatar Apr 06 '23 03:04 hxkjason

@ahKevinXy 用 Golang 写了一个完整的示例 https://github.com/hxkjason/cmb_SM3withSM2_sign_demo, FYI。

试一下看看,我的java的一直不稳定

ahKevinXy avatar Apr 06 '23 08:04 ahKevinXy

@ahKevinXy 用 Golang 写了一个完整的示例 https://github.com/hxkjason/cmb_SM3withSM2_sign_demo, FYI。

感谢啊,折腾了快一天,从你这搞定了

yidashi avatar Apr 22 '23 08:04 yidashi

@yidashi 不谢~ 很高兴能够给你带来一点帮助~

hxkjason avatar Apr 23 '23 08:04 hxkjason

@ahKevinXy 用 Golang 写了一个完整的示例 https://github.com/hxkjason/cmb_SM3withSM2_sign_demo, FYI。

感谢啊,折腾了快一天,从你这搞定了

你怎么成功的,为啥我的不行

package sm2

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"math/big"
	"strings"

	"github.com/tjfoc/gmsm/sm2"
)

func Sign(signContent, privateKey, userId string) string {
	signContent = strings.ReplaceAll(signContent, `"`, `\"`)

	priKey := TransHexToSm2PrivateKey(privateKey)
	r, s, err := sm2.Sm2Sign(priKey, []byte(signContent), []byte(userId), rand.Reader)

	if err != nil {
		return ""
	}

	rBytes, sBytes := r.Bytes(), s.Bytes()
	rLen, sLen := len(rBytes), len(sBytes)
	regularSize := 32

	if rLen < regularSize {
		for i := 0; i < regularSize-rLen; i++ {
			rBytes = append(rBytes, 0)
		}
	}
	if sLen < regularSize {
		for i := 0; i < regularSize-sLen; i++ {
			sBytes = append(sBytes, 0)
		}
	}

	var buffer bytes.Buffer
	buffer.Write(rBytes)
	buffer.Write(sBytes)

	return strings.ToUpper(hex.EncodeToString(buffer.Bytes()))

}

// TransHexToSm2PrivateKey 将16进制私钥转换成sm2私钥实例
func TransHexToSm2PrivateKey(HexPrivateKey string) *sm2.PrivateKey {

	d := new(big.Int)
	d.SetString(HexPrivateKey, 16)
	privateKey := new(sm2.PrivateKey)
	privateKey.D = d
	curve := sm2.P256Sm2()
	privateKey.PublicKey.Curve = curve
	privateKey.PublicKey.X, privateKey.PublicKey.Y = curve.ScalarBaseMult(d.Bytes())

	return privateKey
}


ahKevinXy avatar Apr 26 '23 01:04 ahKevinXy

@ahKevinXy 用 Golang 写了一个完整的示例 https://github.com/hxkjason/cmb_SM3withSM2_sign_demo, FYI。

感谢啊,折腾了快一天,从你这搞定了

你怎么成功的,为啥我的不行

package sm2

import (
	"bytes"
	"crypto/rand"
	"encoding/hex"
	"math/big"
	"strings"

	"github.com/tjfoc/gmsm/sm2"
)

func Sign(signContent, privateKey, userId string) string {
	signContent = strings.ReplaceAll(signContent, `"`, `\"`)

	priKey := TransHexToSm2PrivateKey(privateKey)
	r, s, err := sm2.Sm2Sign(priKey, []byte(signContent), []byte(userId), rand.Reader)

	if err != nil {
		return ""
	}

	rBytes, sBytes := r.Bytes(), s.Bytes()
	rLen, sLen := len(rBytes), len(sBytes)
	regularSize := 32

	if rLen < regularSize {
		for i := 0; i < regularSize-rLen; i++ {
			rBytes = append(rBytes, 0)
		}
	}
	if sLen < regularSize {
		for i := 0; i < regularSize-sLen; i++ {
			sBytes = append(sBytes, 0)
		}
	}

	var buffer bytes.Buffer
	buffer.Write(rBytes)
	buffer.Write(sBytes)

	return strings.ToUpper(hex.EncodeToString(buffer.Bytes()))

}

// TransHexToSm2PrivateKey 将16进制私钥转换成sm2私钥实例
func TransHexToSm2PrivateKey(HexPrivateKey string) *sm2.PrivateKey {

	d := new(big.Int)
	d.SetString(HexPrivateKey, 16)
	privateKey := new(sm2.PrivateKey)
	privateKey.D = d
	curve := sm2.P256Sm2()
	privateKey.PublicKey.Curve = curve
	privateKey.PublicKey.X, privateKey.PublicKey.Y = curve.ScalarBaseMult(d.Bytes())

	return privateKey
}

这个确实可以通过招行java的验签,有个大坑,如果是非saas模式,不能加那个平台签 “paltsigdat”, 否则一直会提示 “签名信息无效” 大坑 最无语的是用官方提供的java demo ,同一套key, 加上平台签名是可以通过的,golang版本死活通过不了,去掉又可以

colornote avatar May 15 '23 09:05 colornote