验签代码示例

MYKEY使用账号的Reserved Key签名。服务端验签,需要先从链上找出Reserved Key,再验证。

ETH:

查询用的AccountStorage合约文件为:

第三方应用传递timestamp, account, uuID, ref给MYKEY,MYKEY按如下规则进行签名: let message = hex(timestamp + account + uuID + ref)

let hashedMessage = crypto.Keccak256Hash(common.FromHex(unsignData)).Bytes()

let unsignedData = "\x19Ethereum Signed Message:\n" + hashedMessage.length + hashedMessage

认证时,MYKEY还会返回mykeyUID和mykeyUIDSignature字段,其签名规则如下:

let messageForMykeyUID = hex(timestamp + account + uuID + ref + mykeyUID)

let unsignedDataForMykeyUID = "\x19Ethereum Signed Message:\n" + message.length + message

package main

import (
	"encoding/hex"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/crypto"
	"log"
	"strings"
	"testing"
)

const (
	signFormat = "\x19Ethereum Signed Message:\n%d%s"
)

func TestVerifty(t *testing.T)  {
	ETHPrv := "87f9bc3c6cd57f18a0143b6863d6b47d6364f1a1ba86eae0ce411097704d5d0d"
	ETHAdd := "0x296Fd341F90508B6742701F4341D2027CdF5c86d"
	//待签名的数据
	data := "0x1234"

	prvKey, _ := hex.DecodeString(ETHPrv)
	sig, _ := SignWithEthWeb3(data, prvKey)
	log.Println("sig:", sig)

	unsignDataHashByte := crypto.Keccak256Hash(common.FromHex(data)).Bytes()
	// 开始服务端签名验证
	log.Println("verify sign:", verifySig(strings.ToLower(ETHAdd), sig, unsignDataHashByte))
}

func SignWithEthWeb3(unsignData string, privateByte []byte) (signature string, err error) {
	// 需要先做一次Hash
	unsignDataHashByte := crypto.Keccak256Hash(common.FromHex(unsignData)).Bytes()
	return SignWithEth(unsignDataHashByte, privateByte)
}

func SignWithEth(unsignData, privateKeyByte []byte) (signature string, err error) {
	// web3签名需要加盐后做Hash,对hash数据进行签名
	newUnsignData := fmt.Sprintf(signFormat, len(unsignData), unsignData)
	unsignDataHash := crypto.Keccak256([]byte(newUnsignData))
	key, err := crypto.ToECDSA(privateKeyByte)
	if err != nil {
		log.Println("sign ToECDSA err:", err.Error())
		return "", err
	}
	signatureByte, err := crypto.Sign(unsignDataHash, key)
	if err != nil {
		log.Println("sign Sign err:", err.Error())
		return "", err
	}
	// web逻辑
	signatureByte[64] += 27
	return hexutil.Encode(signatureByte), nil
}

// 验证签名
func verifySig(from, sigHex string, msg []byte) bool {
	fromAddr := common.HexToAddress(from)

	sig := hexutil.MustDecode(sigHex)
	if sig[64] != 1 && sig[64] != 0 && sig[64] != 27 && sig[64] != 28 {
		log.Println("in hexutil.MustDecode error.")
		return false
	}

	if sig[64] != 1 && sig[64] != 0 {
		sig[64] -= 27
	}
	pubKey, err := crypto.SigToPub(createSignHash(msg), sig)
	if err != nil {
		log.Println("in crypto.SigToPub error:", err.Error())
		return false
	}

	recoveredAddr := crypto.PubkeyToAddress(*pubKey)
	log.Println("recoveredAddr:", recoveredAddr.String())
	return fromAddr == recoveredAddr
}

// 待签名数据生成符合格式的hash
func createSignHash(data []byte) []byte {
	msg := fmt.Sprintf(signFormat, len(data), data)
	return crypto.Keccak256([]byte(msg))
}

EOS:

第三方应用传递timestamp, account, uuID, ref给MYKEY,MYKEY按如下规则进行签名: let unsignedData = timestamp + account + uuID + ref

认证时,MYKEY还会返回mykeyUID和mykeyUIDSignature字段,其签名规则如下:

let unsignedDataForMykeyUID = timestamp + account + uuID + ref + mykeyUID

package main

import (
   "crypto/sha256"
   "fmt"
   "github.com/eoscanada/eos-go/ecc"
   "testing"
)

func TestSignWithEOS(t *testing.T) {
      EOSPrv := "5JrAtoHd6uQnX4nowRzEzuykb81uaLDzwvAvkgV61ACk1tam5K8"
      EOSPub := "EOS5f7NU3vMKt2mSrZtDpiJKRPFXNKZfjsP1V79eEXdZKf62LfvhU"
 
      sig, _ := SignWithEos(EOSPrv, []byte("hello"))
      fmt.Println("sig:", sig)

      publicTest, _ := ecc.NewPublicKey(EOSPub)
      fmt.Println("content:", len(publicTest.Content))
      signature, err := ecc.NewSignature(sig)
      if err != nil {
         return
      }
      verifyResult := signature.Verify(sigDigest([]byte("hello")), publicTest)
      fmt.Println("verify result:", verifyResult)
   }

   func SignWithEos(privateKeyHex string, unsignData []byte) (signedData string, err error) {
      privatekey, err := ecc.NewPrivateKey(privateKeyHex)
      if err != nil {
         return "", err
      }
      signature, err := privatekey.Sign(sigDigest(unsignData))
      if err != nil {
         return "", err
      }
      return signature.String(), nil
   }

   func sigDigest(contextFreeData []byte) []byte {
      h := sha256.New()
      if len(contextFreeData) > 0 {
         h2 := sha256.New()
         _, _ = h2.Write(contextFreeData)
         _, _ = h.Write(h2.Sum(nil)) 
      } else {
         _, _ = h.Write(make([]byte, 32, 32))
      }
      return h.Sum(nil)
   }

Last updated