go sign签名验签 和 sm4 加密

发布时间 2023-11-29 09:40:07作者: 求路问道

sign 方法类

package common

import (
    "Ganzhou/config"
    "Ganzhou/pkg/log"
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/base64"
    "encoding/pem"
    "errors"
)

var AppPriKey = config.GZQAppPriKey
var AppPubKey = config.GZQCloudPubKey

// Rsa2Sign RSA2私钥签名
func Rsa2Sign(str string, hash crypto.Hash) string {
    rs := FormateKey(AppPriKey, 1, false)
    shaNew := hash.New()
    shaNew.Write([]byte(str))
    hashed := shaNew.Sum(nil)
    priKey, err := ParsePrivateKey(rs)
    if err != nil {
        return ""
    }

    signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, hashed)
    if err != nil {
        return ""
    }
    return base64.StdEncoding.EncodeToString(signature)

}

// 解析私钥
func ParsePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
    block, _ := pem.Decode([]byte(privateKey))
    if block == nil {
        return nil, errors.New("私钥信息错误!")
    }
    privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err == nil {
        return privKey, nil
    }

    privKeyInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
    if err == nil {
        if priKey, ok := privKeyInterface.(*rsa.PrivateKey); ok {
            return priKey, nil
        }
    }
    return nil, errors.New("parse private key error")
}

// RSAVerifySign RSA验证签名
func RSAVerifySign(text []byte, publicKey string, hashType crypto.Hash, sig []byte) error {
    block, _ := pem.Decode([]byte(publicKey))
    if block == nil {
        log.Errorf("pem.Decode error")
        return errors.New("public key error")
    }
    pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        log.Errorf("x509.ParsePKIXPublicKey error: %s", err)
        return err
    }
    pub := pubInterface.(*rsa.PublicKey)
    hashInstance := hashType.New()
    hashInstance.Write(text)
    hashed := hashInstance.Sum(nil)
    return rsa.VerifyPKCS1v15(pub, hashType, hashed, sig)

}

// RSAVerifySignBase64 RSA验证Base64签名
func RSAVerifySignBase64(b64Cipher string, hashType crypto.Hash, text []byte) error {
    publicKey := FormateKey(AppPubKey, 1, true)
    cipherText, err := base64.StdEncoding.DecodeString(b64Cipher)
    if err != nil {
        cipherText, err = base64.RawURLEncoding.DecodeString(b64Cipher)
        if err != nil {
            log.Errorf("base64.StdEncoding.DecodeString error! b64Cipher:%s, err:%s", b64Cipher, err)
            return err
        }
    }

    return RSAVerifySign(text, publicKey, hashType, cipherText)
}

func RSAVerify(data []byte, base64Sig string) error {
    // 1、对base64编码的签名内容进行解码,返回签名字节
    bytes, err := base64.StdEncoding.DecodeString(base64Sig)
    if err != nil {
        return err
    }
    // 2、选择hash算法,对需要签名的数据进行hash运算
    myhash := crypto.SHA256
    hashInstance := myhash.New()
    hashInstance.Write(data)
    hashed := hashInstance.Sum(nil)
    // 3、读取公钥文件,解析出公钥对象
    publicKey, err := ReadParsePublicKey()
    if err != nil {
        return err
    }
    // 4、RSA验证数字签名(参数是公钥对象、哈希类型、签名文件的哈希串、签名后的字节)
    return rsa.VerifyPKCS1v15(publicKey, myhash, hashed, bytes)
}

// 读取公钥文件,解析出公钥对象
func ReadParsePublicKey() (*rsa.PublicKey, error) {
    publicKeyStr := FormateKey(AppPubKey, 1, true)
    // 2、解码公钥字节,生成加密块对象
    block, _ := pem.Decode([]byte(publicKeyStr))
    if block == nil {
        return nil, errors.New("公钥信息错误!")
    }
    // 3、解析DER编码的公钥,生成公钥接口
    publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    // 4、公钥接口转型成公钥对象
    publicKey := publicKeyInterface.(*rsa.PublicKey)
    return publicKey, nil
}

//key是否具有头尾换行不交由程序判断
//keyType=1,为key增加头尾,并每间隔64位换行
//ifPublic true 为公钥, false为私钥
//keyType=0,不变
func FormateKey(key string, keyType int, ifPublic bool) string {
    if keyType == 0 {
        return key
    }
    if ifPublic {
        var publicHeader = "\n-----BEGIN PUBLIC KEY-----\n"
        var publicTail = "-----END PUBLIC KEY-----\n"
        var temp string
        Split(key, &temp)
        return publicHeader + temp + publicTail
    } else {
        var publicHeader = "\n-----BEGIN RSA PRIVATE KEY-----\n"
        var publicTail = "-----END RSA PRIVATE KEY-----\n"
        var temp string
        Split(key, &temp)
        return publicHeader + temp + publicTail
    }
}

func Split(key string, temp *string) {
    if len(key) <= 64 {
        *temp = *temp + key + "\n"
    }
    for i := 0; i < len(key); i++ {
        if (i+1)%64 == 0 {
            *temp = *temp + key[:i+1] + "\n"
            key = key[i+1:]
            Split(key, temp)
            break
        }
    }
}
sign基础方法

sm4方法类

package common

import (
    "Ganzhou/config"
    "bytes"
    "encoding/hex"
    "fmt"
    "github.com/tjfoc/gmsm/sm4"
)

var SM4Key = config.GZQCloudDataKey
var SM4Ivstr = config.GZQUserSecKey

// SM4加密
func SM4Encrypt(data string) (result string, err error) {
    test, err := sm4.Sm4Ecb([]byte(SM4Key), []byte(data), true)
    return hex.EncodeToString(test), err
    ////字符串转byte切片
    //plainText := []byte(data)
    ////建议从配置文件中读取秘钥,进行统一管理
    ////todo 注意:iv需要是随机的,进一步保证加密的安全性,将iv的值和加密后的数据一起返回给外部
    //SM4Iv := SM4Ivstr
    //iv := []byte(SM4Iv)
    //key := []byte(SM4Key)
    ////实例化sm4加密对象
    //block, err := sm4.NewCipher(key)
    //if err != nil {
    //    panic(err)
    //}
    ////明文数据填充
    //paddingData := paddingLastGroup(plainText, block.BlockSize())
    ////声明SM4的加密工作模式
    //blockMode := cipher.NewCBCEncrypter(block, iv)
    ////为填充后的数据进行加密处理
    //cipherText := make([]byte, len(paddingData))
    ////使用CryptBlocks这个核心方法,将paddingData进行加密处理,将加密处理后的值赋值到cipherText中
    //blockMode.CryptBlocks(cipherText, paddingData)
    ////加密结果使用hex转成字符串,方便外部调用
    //cipherString := hex.EncodeToString(cipherText)
    //return cipherString, nil
}

// SM4解密 传入string 输出string
func SM4Decrypt(data string) (res string, err error) {
    decodeString, err := hex.DecodeString(data)
    if err != nil {
        return "", err
    }
    test, err := sm4.Sm4Ecb([]byte(SM4Key), decodeString, false)
    return string(test), err
    ////iv是Initialization Vector,初始向量,
    //SM4Iv := SM4Ivstr
    //iv := []byte(SM4Iv)
    //key := []byte(SM4Key)
    //block, err := sm4.NewCipher(key)
    //if err != nil {
    //    panic(err)
    //}
    ////使用hex解码
    //decodeString, err := hex.DecodeString(data)
    //if err != nil {
    //    return "", err
    //}
    ////CBC模式 优点:具有较好的安全性,能够隐藏明文的模式和重复性。 缺点:加密过程是串行的,不适合并行处理。
    //blockMode := cipher.NewCBCDecrypter(block, iv)
    ////下文有详解这段代码的含义
    //blockMode.CryptBlocks(decodeString, decodeString)
    ////去掉明文后面的填充数据
    //plainText := unPaddingLastGroup(decodeString)
    ////直接返回字符串类型,方便外部调用
    //return string(plainText), nil
}

// 明文数据填充
func paddingLastGroup(plainText []byte, blockSize int) []byte {
    //1.计算最后一个分组中明文后需要填充的字节数
    padNum := blockSize - len(plainText)%blockSize
    //2.将字节数转换为byte类型
    char := []byte{byte(padNum)}
    //3.创建切片并初始化
    newPlain := bytes.Repeat(char, padNum)
    //4.将填充数据追加到原始数据后
    newText := append(plainText, newPlain...)
    return newText
}

// 去掉明文后面的填充数据
func unPaddingLastGroup(plainText []byte) []byte {
    //1.拿到切片中的最后一个字节
    length := len(plainText)
    lastChar := plainText[length-1]
    //2.将最后一个数据转换为整数
    number := int(lastChar)
    return plainText[:length-number]
}

func main() {
    key := []byte("1234567890abcdef")
    fmt.Printf("key = %v\n", key)
    data := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}
    fmt.Printf("key = %v\n", key)
    fmt.Printf("data = %x\n", data)
    //iv := []byte("0000000000000000")
    //err = SetIV(iv)//设置SM4算法实现的IV值,不设置则使用默认值
    ecbMsg, err := sm4.Sm4Ecb(key, data, true) //sm4Ecb模式pksc7填充加密
    if err != nil {
        //t.Errorf("sm4 enc error:%s", err)
        return
    }
    fmt.Printf("ecbMsg = %x\n", ecbMsg)
    ecbDec, err := sm4.Sm4Ecb(key, ecbMsg, false) //sm4Ecb模式pksc7填充解密
    if err != nil {
        //t.Errorf("sm4 dec error:%s", err)
        return
    }
    fmt.Printf("ecbDec = %x\n", ecbDec)
}
sm4基础方法

sign 签名加密方法调用

func PutPostRdoteFun(p model2.PutRequest) (Pdate model2.PutRequestJson) {

    str, err := json.Marshal(p)
    if err != nil {
        fmt.Println(err)
    }
    sign, decrypt := cm.GetSignAndRequest(string(str))
    //sign := cm.Rsa2Sign(string(str), crypto.SHA256)
    //fmt.Println(sign)
    //fmt.Println(url.QueryEscape(sign))
    //decrypt, err := cm.SM4Encrypt(string(str))
    //if err != nil {
    //    return
    //}
    //fmt.Printf("sm4加密结果:%s\n", decrypt)
    Pdate.Sign = sign
    Pdate.Request = decrypt
    Pdate.UserCode = config.GZQUserCode
    return Pdate
}
调用sign方法
// 请求数据签名和sm4加密
func GetSignAndRequest(str string) (sign, Request string) {
    fmt.Println(str)
    sig := Rsa2Sign(str, crypto.SHA256)
    fmt.Println(sign)
    fmt.Println(url.QueryEscape(sign))
    decrypt, err := SM4Encrypt(str)
    if err != nil {
        return
    }
    fmt.Printf("sm4加密结果:%s\n", decrypt)
    return sig, decrypt
}
数据签名和sm4加密

sign 签名验签