基于crypto的跨语言签名验签实现

以下面这对公私钥为例:

priKeyStr := "55331231652752707450534414287730188629145955228891758798201450763340552825166"
pubKeyStr := "11798277315441798127238305597212517654332197982978466864717364245859439644690363141941628373531488122609933560694747426926865495896421628851963848417303440"

此次项目需求为在go中签名,java中实现验签。此过程坑较多,下面直接给出结果。

1、在go中实现签名验签,此过程较为丝滑,同语言实现难度较为简单,直接贴源码,如下:

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/btcsuite/btcd/btcec/v2"
	"github.com/btcsuite/btcd/btcec/v2/ecdsa"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/ethereum/go-ethereum/crypto/secp256k1"
	"math/big"
)

func Secp256k1SignTest() {
	priKeyStr := "55331231652752707450534414287730188629145955228891758798201450763340552825166"
	pubKeyStr := "11798277315441798127238305597212517654332197982978466864717364245859439644690363141941628373531488122609933560694747426926865495896421628851963848417303440"
	//将10进制的大数转换成bigint
	priKey10Bigint := new(big.Int)
	priKey10Bigint.SetString(priKeyStr, 10)
	fmt.Printf("prikey Decoded Byte Array: %v \n", priKey10Bigint.Bytes())
	fmt.Printf("prikey hex: %x \n", priKey10Bigint.Bytes())

	hashmsg := sha256.Sum256([]byte("Abby is beautiful and smart!"))
	//需要注意这里生成的是 signature is in the 65-byte [R || S || V] format where V is 0 or 1. 与weid的是保持一致的,也就是我们需要的格式
	sign, _ := secp256k1.Sign(hashmsg[:], priKey10Bigint.Bytes())
	fmt.Printf("sign hex: %x \n", sign)
	fmt.Printf("sign hex: %v \n", sign)

	//将16进制的大数转换成bigint
	pubKey10Bigint := new(big.Int)
	pubKey10Bigint.SetString(pubKeyStr, 10)
	pubKeyHex := hex.EncodeToString(pubKey10Bigint.Bytes())
	fmt.Printf("pubkey hex: %v\n", pubKeyHex)
	pubKeyHexStr := "04" + pubKeyHex
	//需要注意的是,公钥一定要加04,表示是非压缩公钥
	pubKey10Bigint.SetString(pubKeyHexStr, 16)
	fmt.Printf("pubkey Decoded Byte Array: %v \n", pubKey10Bigint.Bytes())
	fmt.Printf("pubkey hex: %x \n", pubKey10Bigint.Bytes())

	fmt.Printf("%d %d %d\n", len(hashmsg[:]), len(sign[:64]), len(pubKey10Bigint.Bytes()))
	//需要注意这里的The signature should be in [R || S] format,也就是最后一个字节的V不需要
	if secp256k1.VerifySignature(pubKey10Bigint.Bytes(), hashmsg[:], sign[:64]) == false {
		fmt.Printf("%s\n", "验证失败")
	} else {
		fmt.Printf("%s\n", "验证成功")
	}
}

2、剥离签名算法

func Secp256k1Sign(reqBody json.RawMessage, priKeyStr string) (string, error) {
	//将10进制的大数转换成bigint
	priKey10Bigint := new(big.Int)
	priKey10Bigint.SetString(priKeyStr, 10)
	fmt.Printf("prikey Decoded Byte Array: %v \n", priKey10Bigint.Bytes())
	fmt.Printf("prikey hex: %x \n", priKey10Bigint.Bytes())
	hashmsg := sha256.Sum256(reqBody)
	fmt.Printf("hashmsg: %x \n", hashmsg)
	//需要注意这里生成的是 signature is in the 65-byte [R || S || V] format where V is 0 or 1. 与weid的是保持一致的,也就是我们需要的格式
	sign, err := secp256k1.Sign(hashmsg[:], priKey10Bigint.Bytes())
	fmt.Printf("sign R Byte Array: %v \n", sign[0:32])
	fmt.Printf("sign S Byte Array: %v \n", sign[32:64])
	if err != nil {
		return "", err
	}
	fmt.Printf("sign hex: %x \n", sign)
	signHex := hex.EncodeToString(sign)
	return signHex, nil
}

3、go中封装sig到header请求

我们在go中发起请求,将签名封装在signature中

func (weid *WeIdentityRest) InvokeFunction(reqBody Request, priKeyStr string) (string, error) {
	url := fmt.Sprintf("http://%s/weid/api/invoke", config.GlobalCfg.WeIDRestConfig.Addr)
	requestJSON, err := json.Marshal(reqBody)
	if err != nil {
		return "", err
	}

	// 创建客户端
	client := &http.Client{}
	req, errReq := http.NewRequest("POST", url, bytes.NewBuffer(requestJSON))
	if err != nil {
		fmt.Println("Error creating HTTP request:", err)
		return "", errReq
	}
	signature, errInfo := custom_util.Secp256k1Sign(requestJSON, priKeyStr)
	if signature == "" {
		fmt.Println("Sig err:", errInfo)
		return "", errInfo
	}
	req.Header.Add("signature", signature)
	req.Header.Add("Content-Type", "application/json")

	// 发送请求
	resp, errDo := client.Do(req)
	if err != nil {
		fmt.Println("Error sending HTTP request:", err)
		return "", errDo
	}

	defer resp.Body.Close()

	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// 处理错误
		variable.ZapLog.Error("调用微众响应出错:", zap.Any("err", err))
	}
	bodyString := string(bodyBytes)

	variable.ZapLog.Info("调用微众:", zap.Any("微众返回", bodyString),
		zap.Any("调微众url", url),
		zap.Any("调微众请求体", reqBody))

	return bodyString, nil
}

4、java项目中采用微众封装的密码库 org.fisco.bcos.sdk.crypto.signature.Signature

   public static boolean checkSigValid(String publicKey, String rawData) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request1 = attributes.getRequest();
        String hexSignStr=request1.getHeader("signature" +
                "");
        //签名编码转换
        try{
            System.out.println("publicKey===================="+publicKey);
            BigInteger bigInteger = new BigInteger(publicKey, 10);
            String hexPublicKey = bigInteger.toString(16);
            System.out.println("hexPublicKey===================="+hexPublicKey);
            String rawDataHash = getHash(rawData);
            System.out.println("rawDataHash = " +rawDataHash);
            byte[] sigBytes = Hex.decodeHex(hexSignStr);
            RsvSignature rsvSignature = new RsvSignature();
            byte[] r = new byte[32];
            byte[] s = new byte[32];
            System.arraycopy(sigBytes, 0, r, 0, 32);
            System.arraycopy(sigBytes, 32, s, 0, 32);
            rsvSignature.setR(new Bytes32(r));
            System.out.println("JAVA-R: "+ Arrays.toString(r));
            rsvSignature.setS(new Bytes32(s));
            System.out.println("JAVA-S: "+Arrays.toString(s));
            rsvSignature.setV(new Uint8(sigBytes[64]));
            boolean res = DataToolUtils.verifySignature(hexPublicKey, rawDataHash, rsvSignature);
            System.out.println(res);
            return res;
        } catch (Exception e){
            System.out.println(e.getMessage());
        }
       return false;
    }

里面坑巨多,不同的处理器架构(如x86和ARM)可能支持不同的端序,在进行数据传输或存储时,需要考虑使用的端序,以确保数据的正确解析。不同语言字节数组表示范围也不同,例如:JAVA-R: [111, -42, 100, -104, 114, 1, -11, -112, 62, -95, 24, 77, -102, 59, 0, -76, -1, 88, -74, 16, -42, 76, 21, 51, -44, -71, -63, 73, 88, -39, 15, 60]

JAVA-S: [42, -26, -39, 10, 43, -2, 113, 19, -12, -128, 93, -115, -121, 55, 50, 22, -37, -43, 119, 43, -60, -20, -30, 122, 24, -100, 21, 97, 10, -20, 15, 23]

sign R Byte Array: [111 214 100 152 114 1 245 144 62 161 24 77 154 59 0 180 255 88 182 16 214 76 21 51 212 185 193 73 88 217 15 60]

sign S Byte Array: [42 230 217 10 43 254 113 19 244 128 93 141 135 55 50 22 219 213 119 43 196 236 226 122 24 156 21 97 10 236 15 23]

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值