| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- package core
- import (
- "app/commons/model/entity"
- "crypto/ecdsa"
- "encoding/base64"
- "fmt"
- "github.com/btcsuite/btcd/btcutil/hdkeychain"
- "github.com/btcsuite/btcd/chaincfg"
- "github.com/demdxx/gocast"
- "github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/common/hexutil"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/tyler-smith/go-bip39"
- "strings"
- "time"
- )
- type Sign struct {
- SysName string `mapstructure:"sys-name" json:"sys-name" yaml:"sys-name"` // 本系统名
- SysSignPrefix string `mapstructure:"sys-sign-prefix" json:"sys-sign-prefix" yaml:"sys-sign-prefix"`
- SysAddress string `mapstructure:"sys-address" json:"sys-address" yaml:"sys-address"` // 本系统地址
- SysKey string `mapstructure:"sys-key" json:"sys-key" yaml:"sys-key"` // 本系统密钥 -- 使用本系统密码本加密
- Internals []*InternalSys `mapstructure:"internals" json:"internals" yaml:"internals"`
- }
- type InternalSys struct {
- SysName string `mapstructure:"sys-name" json:"sys-name" yaml:"sys-name"`
- SysUrl string `mapstructure:"sys-url" json:"sys-url" yaml:"sys-url"` // 系统地址
- SignPrefix string `mapstructure:"sign-prefix" json:"sign-prefix" yaml:"sign-prefix"` // 签名前缀
- SignExpSec int64 `mapstructure:"sign-exp-sec" json:"sign-exp-sec" yaml:"sign-exp-sec"` // 签名超时-S
- SysAddress string `mapstructure:"sys-address" json:"sys-address" yaml:"sys-address"` // 管理系统地址
- }
- var signConfer *Sign
- func GetSignSysName(signStr string) (string, error) {
- for _, item := range signConf().Internals {
- if strings.HasPrefix(signStr, item.SysName) {
- return item.SysName, nil
- }
- }
- return "", fmt.Errorf("not found")
- }
- func signConf() *Sign {
- if signConfer == nil {
- // 初始化
- rows := make([]*entity.SysSignConfig, 0)
- err := MainDb().
- Model(&entity.SysSignConfig{}).
- Where("1 = 1").
- Find(&rows).Error
- if err != nil {
- panic(err)
- }
- signConfer = new(Sign)
- for _, row := range rows {
- if row.IsSystemSign {
- signConfer.SysSignPrefix = row.SignName
- signConfer.SysKey = row.SignPriKey
- signConfer.SysAddress = row.SignAddress
- signConfer.SysName = row.SignName
- continue
- }
- if signConfer.Internals == nil {
- signConfer.Internals = make([]*InternalSys, 0)
- }
- signConfer.Internals = append(signConfer.Internals, &InternalSys{
- SysName: row.SignName,
- SysAddress: row.SignAddress,
- SysUrl: row.SysUrl,
- SignPrefix: row.SignName,
- SignExpSec: row.SignExpSec,
- })
- }
- }
- return signConfer
- }
- // 构建本系统签名信息
- func BuildSignMessage() (string, error) {
- sysPrivateKey, err := Base64Decode(signConf().SysKey)
- if err != nil {
- return "", err
- }
- msg := fmt.Sprintf("%s%d", signConf().SysSignPrefix, time.Now().Unix())
- sign, err := signMessage(msg, sysPrivateKey)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("%s%s", msg, sign), nil
- }
- type Signer struct {
- SignPrefix string `mapstructure:"sign-prefix" json:"sign-prefix" yaml:"sign-prefix"` // 签名前缀
- SignExpSec int64 `mapstructure:"sign-exp-sec" json:"sign-exp-sec" yaml:"sign-exp-sec"` // 签名超时-S
- SysAddress string `mapstructure:"sys-address" json:"sys-address" yaml:"sys-address"` // 管理系统地址
- }
- // 通过系统名获取外部系统签名器 用于签名验证
- var signerMap = make(map[string]*Signer)
- func SignerBySysName(sysName string) (*Signer, error) {
- v, ok := signerMap[sysName]
- if ok {
- return v, nil
- }
- for _, item := range signConf().Internals {
- if item.SysName == sysName {
- signerMap[sysName] = &Signer{
- SignPrefix: item.SignPrefix,
- SignExpSec: item.SignExpSec,
- SysAddress: item.SysAddress,
- }
- return signerMap[sysName], nil
- }
- }
- return nil, fmt.Errorf("sys name not found")
- }
- // 本系统地址 -- 暴露给其他系统使用
- func SysAddress() (string, error) {
- sysPrivateKey, err := Base64Decode(signConf().SysKey)
- if err != nil {
- return "", err
- }
- return ethPriKey2HexAddress(sysPrivateKey)
- }
- func SysSignPrefix() string {
- return signConf().SysSignPrefix
- }
- const (
- base64Table = "7PQX12RVW3YZaDEFGbcdeIJjkKLMNO56fghiABCHlSTUmnopqrxyz04stuvw89+/"
- )
- var coder = base64.NewEncoding(base64Table)
- func Base64Encode(src string) string { //编码
- return coder.EncodeToString([]byte(src))
- }
- func Base64Decode(src string) (string, error) { //解码
- bts, err := coder.DecodeString(src)
- if err != nil {
- return "", err
- }
- return fmt.Sprintf("%s", bts), nil
- }
- func signMessage(message, hexPri string) (string, error) {
- priKey, err := priHexKeyToECDSA(hexPri)
- if err != nil {
- return "", err
- }
- return signMessageWithEcdsa(message, priKey)
- }
- // signMessageWithEcdsa 使用私钥签名消息
- func signMessageWithEcdsa(message string, privateKey *ecdsa.PrivateKey) (string, error) {
- // 计算消息的Keccak256哈希
- hash := crypto.Keccak256Hash([]byte(message))
- // 签名
- signature, err := crypto.Sign(hash.Bytes(), privateKey)
- if err != nil {
- return "", err
- }
- // 添加恢复ID(以太坊要求)
- signature[64] += 27
- return hexutil.Encode(signature), nil
- }
- func (s *Signer) VerifySignature(message string) error {
- msg, signature, ok := s.checkMessage(message)
- if !ok {
- return fmt.Errorf("非法签名")
- }
- return verifySignature(msg, signature, common.HexToAddress(s.SysAddress))
- }
- // 消息格式
- // 1 去除消息头部信息
- // 2 获取前10位数字
- // 3 对比时间 不得相差3秒
- func (s *Signer) checkMessage(message string) (string, string, bool) {
- if !strings.HasPrefix(message, s.SignPrefix) {
- fmt.Println(fmt.Sprintf("签名未包含前缀:%s", s.SignPrefix))
- return "", "", false
- }
- removePrefix := strings.TrimPrefix(message, s.SignPrefix)
- timestamp := removePrefix[:10]
- notUnixTime := time.Now().Unix()
- if notUnixTime > gocast.ToInt64(timestamp)+s.SignExpSec || gocast.ToInt64(timestamp) > notUnixTime {
- return "", "", false
- }
- signature := removePrefix[10:]
- return s.SignPrefix + removePrefix[:10], signature, true
- }
- // verifySignature 验证签名
- func verifySignature(message, signature string, address common.Address) error {
- // 解码签名
- sig, err := hexutil.Decode(signature)
- if err != nil {
- return err
- }
- // 恢复ID必须为27或28
- if sig[64] != 27 && sig[64] != 28 {
- return fmt.Errorf("无效的恢复ID")
- }
- // 调整恢复ID为0或1(以太坊库要求)
- sig[64] -= 27
- // 计算消息哈希
- hash := crypto.Keccak256Hash([]byte(message))
- // 从签名恢复公钥
- publicKey, err := crypto.SigToPub(hash.Bytes(), sig)
- if err != nil {
- return err
- }
- // 从公钥生成地址
- recoveredAddr := crypto.PubkeyToAddress(*publicKey)
- // 验证地址是否匹配
- if recoveredAddr != address {
- return fmt.Errorf("签名验证失败: 地址不匹配")
- }
- return nil
- }
- // 生成助记词 使用标准:BIP39(i -128 /256)
- // 生成“128的熵”
- //1. 生成一个长度为 128 ~ 256 位的随机序列(后面称为熵);
- //- 熵的取值长度需要为 32 的整数倍的值。所以取值可能为:【128, 160, 192, 224, 256】。
- //2. 获取熵的校验和;
- //- 取熵哈希后的前 n 位作为校验和(n = 熵长度/32)。
- //- 校验和的理论值为【4,5,6,7,8】。
- //3. 生成新的序列;
- //- 新的序列方式为 = 熵 + 校验和
- //- 新序列的长度理论值可能为:【128+4,160+5,192+6,224+7,256+8】即【132,165,198,231,264】
- //4. 获得 m 个 11 位二进制数。
- //- 将新生成的序列,按照 11 位进行平分。
- //- m 的理论可能值为:【12,15,18,21,24】
- //- 为什么是 11 位?助记词库总共有 2048 个单词,2^11 正好是 2048。所以用 11 位二进制数刚好可以将所有的助记词定位。
- //5. 获得 m 个助记词;
- //- 根据第四步得到的 m 个 11位二进制数,去助记词表定位每一个助记词。
- //- 得到助记词个数的理论值为:【12,15,18,21,24】
- // 波场使用的熵长度为256 128生成12位单词助记词
- func GenerateMnemonicWords(i int) string {
- entropy, err := bip39.NewEntropy(i)
- if err != nil {
- return ""
- }
- mnemonic, _ := bip39.NewMnemonic(entropy)
- return mnemonic
- }
- func MnemonicToEthInfo(mnemonic string) (ethHexAddress string, subPriKey string, err error) {
- // 验证助记词有效性
- if !bip39.IsMnemonicValid(mnemonic) {
- return "", "", fmt.Errorf("invalid mnemonic phrase")
- }
- // 生成种子
- seed := bip39.NewSeed(mnemonic, "") // 第二个参数是密码,可以为空
- // 创建主密钥
- master, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
- if err != nil {
- return "", "", fmt.Errorf("failed to create master key: %v", err)
- }
- // 解析派生路径
- dp, err := accounts.ParseDerivationPath("m/44'/60'/0'/0/0")
- if err != nil {
- return "", "", fmt.Errorf("failed to parse derivation path: %v", err)
- }
- // 派生密钥
- for _, n := range dp {
- var child *hdkeychain.ExtendedKey
- if master.IsAffectedByIssue172() {
- child, err = master.Derive(n)
- } else {
- child, err = master.DeriveNonStandard(n)
- }
- if err != nil {
- return "", "", fmt.Errorf("failed to derive key: %v", err)
- }
- master = child
- }
- // 获取ECDSA私钥
- privateKey, err := master.ECPrivKey()
- if err != nil {
- return "", "", fmt.Errorf("failed to get EC private key: %v", err)
- }
- privateKeyECDSA := privateKey.ToECDSA()
- publicKey := privateKeyECDSA.Public().(*ecdsa.PublicKey)
- // 生成地址
- addr := crypto.PubkeyToAddress(*publicKey)
- ethHexAddress = addr.Hex()
- // 编码私钥
- privateKeyBytes := crypto.FromECDSA(privateKeyECDSA)
- subPriKey = hexutil.Encode(privateKeyBytes)
- return ethHexAddress, subPriKey, nil
- }
- func GenerateSysInfo() (string, string, error) {
- mn := GenerateMnemonicWords(128)
- addr, pri, err := MnemonicToEthInfo(mn)
- if err != nil {
- return "", "", err
- }
- pri = Base64Encode(pri)
- return addr, pri, nil
- }
- func EthAddressCheck(addr string) bool {
- return common.IsHexAddress(addr)
- }
- func priHexKeyToECDSA(hexPriKey string) (*ecdsa.PrivateKey, error) {
- return crypto.HexToECDSA(strings.TrimPrefix(hexPriKey, "0x"))
- }
- func ethPriKey2HexAddress(priKeyHash string) (string, error) {
- priKey, err := priHexKeyToECDSA(priKeyHash)
- if err != nil {
- return "", err
- }
- pubKey := priKey.Public().(*ecdsa.PublicKey)
- addr := crypto.PubkeyToAddress(*pubKey)
- return addr.Hex(), nil
- }
- func EthPriKey2HexAddress(priKeyHash string) (string, error) {
- return ethPriKey2HexAddress(priKeyHash)
- }
|