You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
6.8 KiB
300 lines
6.8 KiB
package wallet_sdk
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"encoding/pem"
|
|
"fmt"
|
|
hds "git.yuanzoo.cn/zhangzhengqiang/popi-zxl/third_party/official/gosdk_demo/zxsdk/wallet_sdk/hdsignature"
|
|
"git.yuanzoo.cn/zhangzhengqiang/popi-zxl/third_party/official/gosdk_demo/zxsdk/wallet_sdk/mnemonics"
|
|
"math/big"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
defaultEntropy = 128
|
|
)
|
|
|
|
var (
|
|
defaultIndexPathPrefix = []uint32{66, 0, 0, 0}
|
|
)
|
|
|
|
// Mnemonics
|
|
|
|
func CreateMnemonic() (string, error) {
|
|
entropy, err := mnemonics.NewEntropy(defaultEntropy)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return mnemonics.NewMnemonic(entropy)
|
|
}
|
|
|
|
// HD Signature
|
|
|
|
// DeriveKeyPair derives key pair strings for the node m/66/0/0/0/index
|
|
func DeriveKeyPair(mnemonic string, index uint32) (string, string, error) {
|
|
return DeriveKeyPairEncrypted(mnemonic, index, nil)
|
|
}
|
|
|
|
func DeriveKeyPairEncrypted(mnemonic string, index uint32, password []byte) (string, string, error) {
|
|
msk, _, err := hds.CreateMasterKey(mnemonic)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
psk, err := msk.DeriveKeyPairObjFromFullPath(defaultIndexPathPrefix)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
sk, err := psk.DeriveChildPrivateKey(index)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
skPEM, err := sk.GetPrunedPEM(password)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
pkPEM, err := sk.GetPublicKey().GetPrunedPEM()
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return skPEM, pkPEM, nil
|
|
}
|
|
|
|
// DeriveKeyPairFullPath derives key pair strings for the node m/path[0]/...
|
|
func DeriveKeyPairFullPath(mnemonic string, path []uint32) (string, string, error) {
|
|
return DeriveKeyPairFullPathEncrypted(mnemonic, path, nil)
|
|
}
|
|
func DeriveKeyPairFullPathEncrypted(mnemonic string, path []uint32, password []byte) (string, string, error) {
|
|
msk, _, err := hds.CreateMasterKey(mnemonic)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
sk, err := msk.DeriveKeyPairObjFromFullPath(path)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
skPEM, err := sk.GetPrunedPEM(password)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
pkPEM, err := sk.GetPublicKey().GetPrunedPEM()
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return skPEM, pkPEM, nil
|
|
}
|
|
|
|
func PriKey2PubKey(pri string) (string, error) {
|
|
return EncryptedPriKey2PubKey(pri, nil)
|
|
}
|
|
|
|
func EncryptedPriKey2PubKey(pri string, password []byte) (string, error) {
|
|
sk, err := hds.ParsePrivateKey([]byte(pri), password)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return sk.GetPublicKey().GetPrunedPEM()
|
|
}
|
|
|
|
func PubKey2Address(pubKey string) (string, error) {
|
|
pk, err := hds.ParsePublicKey([]byte(pubKey))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return pk.GetAddress()
|
|
}
|
|
|
|
func PriKey2Address(priKey string) (string, error) {
|
|
return EncryptedPriKey2Address(priKey, nil)
|
|
}
|
|
|
|
func EncryptedPriKey2Address(priKey string, password []byte) (string, error) {
|
|
sk, err := hds.ParsePrivateKey([]byte(priKey), password)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return sk.GetAddress()
|
|
}
|
|
|
|
func SignByPriKey(priKey string, data string) (string, error) {
|
|
return SignByEncryptedPriKey(priKey, data, nil)
|
|
}
|
|
|
|
func SignByEncryptedPriKey(priKey string, data string, password []byte) (string, error) {
|
|
sk, err := hds.ParsePrivateKey([]byte(priKey), password)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
sig, err := sk.Sign(data)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
sigHex := hex.EncodeToString(sig)
|
|
return sigHex, nil
|
|
}
|
|
|
|
func VerifyByPubKey(pubKey string, signedData string, data string) (bool, error) {
|
|
pk, err := hds.ParsePublicKey([]byte(pubKey))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
sig, err := hex.DecodeString(signedData)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return pk.Verify(data, sig)
|
|
}
|
|
|
|
func GetBase64PrivateKey(priKey string) (string, error) {
|
|
return GetBase64EncryptedPrivateKey(priKey, nil)
|
|
}
|
|
|
|
func GetBase64EncryptedPrivateKey(priKey string, password []byte) (string, error) {
|
|
sk, err := hds.ParsePrivateKey([]byte(priKey), password)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return sk.GetBase64String(password)
|
|
}
|
|
|
|
func GetBase64PublicKey(pubKey string) (string, error) {
|
|
pk, err := hds.ParsePublicKey([]byte(pubKey))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return pk.GetBase64String()
|
|
}
|
|
|
|
// Certificate with SM2 public key
|
|
|
|
// Create certificate request (csr)
|
|
func CreateCSR(priKey string, templateStr string) (string, error) {
|
|
return CreateCSRFromEncryptedPrivateKey(priKey, templateStr, nil)
|
|
}
|
|
|
|
func CreateCSRFromEncryptedPrivateKey(priKey string, templateStr string, password []byte) (string, error) {
|
|
sk, err := hds.ParsePrivateKey([]byte(priKey), password)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
csr, err := sk.CreateCSRFromTemplatePEM(templateStr)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(csr), nil
|
|
}
|
|
|
|
func CheckSignatureValidity(sig string) (bool, error) {
|
|
sigBytes, err := hex.DecodeString(sig)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if len(sigBytes) < hds.SigMinLength || len(sigBytes) > hds.SigMaxLength {
|
|
return false, fmt.Errorf("invalid signature length (%d)", len(sig))
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func CheckPublicKeyValidity(pubKey string) (bool, error) {
|
|
pubKeyBlock, _ := pem.Decode([]byte(pubKey))
|
|
if pubKeyBlock == nil {
|
|
return false, fmt.Errorf("invalid public key encoding")
|
|
}
|
|
|
|
if len(pubKeyBlock.Bytes) < hds.PubKeyMinLength || len(pubKeyBlock.Bytes) > hds.PubKeyMaxLength {
|
|
return false, fmt.Errorf("invalid public key length (%d)", len(pubKeyBlock.Bytes))
|
|
}
|
|
|
|
return true, nil
|
|
}
|
|
|
|
func CheckAddressValidity(address string) (bool, error) {
|
|
addressBytes := []byte(address)
|
|
prefix := string(addressBytes[:2])
|
|
pkHash := addressBytes[2:]
|
|
|
|
if len(pkHash) != hds.HDWAddressLength*2 {
|
|
return false, fmt.Errorf("hash part should be %d bytes", hds.HDWAddressLength*2)
|
|
}
|
|
|
|
_, err := hex.DecodeString(string(pkHash))
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
switch prefix {
|
|
case hds.ZXAddrPrefix, hds.ZXAddrPrefixV1, hds.ZXAddrPrefixV2, hds.ZXAddrPrefixV3:
|
|
return true, nil
|
|
default:
|
|
return false, fmt.Errorf("invalid prefix")
|
|
}
|
|
}
|
|
|
|
type SignData struct {
|
|
Signature string
|
|
SignatureTime string
|
|
Nonce int
|
|
}
|
|
|
|
const (
|
|
MaxRandNum = 1000000
|
|
MinRandNum = 100000
|
|
)
|
|
|
|
func GenerateApiSign(appId, appKey string) (signData *SignData, err error) {
|
|
now := time.Now()
|
|
signTime := strconv.FormatInt(now.UnixNano()/1e6, 10)
|
|
nonce, err := generateNonce()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
signData = &SignData{}
|
|
|
|
signStr := ""
|
|
if appId != "" && appKey != "" {
|
|
signStr = appId + "&" + appKey + "&" + signTime + "&" + strconv.Itoa(nonce)
|
|
} else {
|
|
signStr = signTime + "&" + strconv.Itoa(nonce)
|
|
}
|
|
|
|
sign, err := hds.SM3HMAC([]byte(appKey), []byte(signStr))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
signData.Signature = hex.EncodeToString(sign)
|
|
signData.SignatureTime = signTime
|
|
signData.Nonce = nonce
|
|
return signData, nil
|
|
}
|
|
|
|
func generateNonce() (int, error) {
|
|
b := new(big.Int).SetInt64(MaxRandNum)
|
|
randNum, err := rand.Int(rand.Reader, b)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
nonce := int(randNum.Int64())
|
|
if nonce < MinRandNum {
|
|
nonce = nonce + MinRandNum
|
|
}
|
|
return nonce, nil
|
|
}
|
|
|