验签代码示例
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))
}