tjfoc / gmsm

GM SM2/3/4 library based on Golang (基于Go语言的国密SM2/SM3/SM4算法库)
http://www.wutongchain.com
Apache License 2.0
1.78k stars 589 forks source link

请问SM2签名方法中的 random io.Reader 参数应该传什么? #208

Open xpsuper opened 2 months ago

xpsuper commented 2 months ago

请问 func Sm2Sign(priv PrivateKey, msg, uid []byte, random io.Reader) (r, s big.Int, err error) 中的 random io.Reader 参数应该传什么?

然后好心人帮忙看下应该怎么翻译 java 中的 SM2加签验签,我写的 go 加签验签一直对不上,头大

JAVA:

package com.allinpay.sign;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
import com.alibaba.fastjson.JSONObject;

public class DemoSM2Utils
{
    /** 算法常量:SM3withSM2 */
    public static final String ALGORITHM_SM3SM2_BCPROV = "SM3withSM2";

    static
    {
        Security.addProvider(new BouncyCastleProvider());
    }

    /** 从字符串读取私钥-目前支持PKCS8(keystr为BASE64格式) */
    public static PrivateKey privKeySM2FromBase64Str(String keystr) throws Exception
    {
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decode(keystr)));
    }

    /** 从字符串读取RSA公钥(keystr为BASE64格式) */
    public static PublicKey pubKeySM2FromBase64Str(String keystr) throws Exception
    {
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decode(keystr)));
    }

    public static String sign(PrivateKey privateKey, String text) throws Exception
    {
        Signature signature = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC");
        signature.initSign(privateKey);
        byte[] plainText = text.getBytes(StandardCharsets.UTF_8);
        signature.update(plainText);
        byte[] signatureValue = signature.sign();
        return Base64.toBase64String(signatureValue);
    }

    public static boolean verify(PublicKey publicKey, String text, String sign) throws Exception
    {
        if (isEmpty(sign))
        {
            return false;
        }
        Signature signature = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC");
        signature.initVerify(publicKey);
        signature.update(text.getBytes(StandardCharsets.UTF_8));
        byte[] signed = Base64.decode(sign);
        return signature.verify(signed);
    }

    public static boolean isEmpty(String str)
    {
        return str == null || "".equals(str) || "".equals(str.trim());
    }
}

Golang :

package allinpay2

import (
    "bytes"
    "crypto/rand"
    "encoding/base64"
    "encoding/pem"
    "fmt"
    "github.com/tjfoc/gmsm/sm2"
    "github.com/tjfoc/gmsm/x509"
    "math/big"
)

func Sign(privateKey string, text string) (string, error) {
    key, err := privateKeyFromBase64Str(privateKey)
    if err != nil {
        return "", err
    }

    r, s, err := sm2.Sm2Sign(key, stl.StringToBytes(text), default_uid, rand.Reader)
    if err != nil {
        return "", err
    }

    var buffer bytes.Buffer
    buffer.Write(r.Bytes())
    buffer.Write(s.Bytes())

    signature := base64.StdEncoding.EncodeToString(buffer.Bytes())
    return signature, nil
}

// Verify signature using SM2 public key
func Verify(publicKey string, text, signBase64 string) (bool, error) {
    if stl.IsEmpty(signBase64) {
        return false, nil
    }

    key, err := publicKeySM2FromBase64Str(publicKey)
    if err != nil {
        return false, err
    }

    signature, err := base64.StdEncoding.DecodeString(signBase64)
    if err != nil {
        return false, err
    }

    l := len(signature)
    br := signature[:l/2]
    bs := signature[l/2:]

    var ri, si big.Int
    r := ri.SetBytes(br)
    s := si.SetBytes(bs)

    return sm2.Sm2Verify(key, []byte(text), default_uid, r, s), nil
}

/***** Below are the helper functions *****/
var (
    default_uid = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
)

func privateKeyFromBase64Str(keyStr string) (*sm2.PrivateKey, error) {
    pemBytes, err := base64.StdEncoding.DecodeString(keyStr)
    if err != nil {
        return nil, err
    }
    //block, _ := pem.Decode(pemBytes)
    //if block == nil {
    //  return nil, fmt.Errorf("failed to parse PEM block containing the key")
    //}
    return x509.ParsePKCS8UnecryptedPrivateKey(pemBytes)
}

// Decode base64 string to SM2 public key
func publicKeySM2FromBase64Str(keyStr string) (*sm2.PublicKey, error) {
    pemBytes, err := base64.StdEncoding.DecodeString(keyStr)
    if err != nil {
        return nil, err
    }
    block, _ := pem.Decode(pemBytes)
    if block == nil {
        return nil, fmt.Errorf("failed to parse PEM block containing the key")
    }
    genericPublicKey, err := x509.ParsePKIXPublicKey(pemBytes)
    if err != nil {
        return nil, err
    }
    return genericPublicKey.(*sm2.PublicKey), nil
}