Golang RSA 加密 解密 簽名 驗簽

非對稱加密 RSA

  • 優點

    與對稱加密相比,安全性更好,加解密需要不同的密鑰,公鑰和私鑰都可進行相互的加解密。

  • 缺點

    加密和解密花費時間長、速度慢,只適合對少量數據進行加密。

  • 應用場景

    適合于對安全性要求很高的場景,適合加密少量數據,比如支付數據、登錄數據等。

package helpers
import (
    "bytes"
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/asn1"
    "encoding/pem"
    "strings"
)

type Rsa struct {
    privateKey    string
    publicKey     string
    rsaPrivateKey *rsa.PrivateKey
    rsaPublicKey  *rsa.PublicKey
}

func NewRsa(publicKey, privateKey string) *Rsa {
    rsaObj := &Rsa{
        privateKey: privateKey,
        publicKey:  publicKey,
    }
    rsaObj.init() //初始化,如果存在公鑰私鑰,將其解析
    return rsaObj
}

//初始化
func (r *Rsa) init() {
    if r.privateKey != "" {
        //將私鑰解碼
        block, _ := pem.Decode([]byte(r.privateKey))
        //pkcs1   //判斷是否包含 BEGIN RSA 字符串,這個是由下面生成的時候定義的
        if strings.Index(r.privateKey, "BEGIN RSA") > 0 {
            //解析私鑰
            r.rsaPrivateKey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
        } else { //pkcs8
            //解析私鑰
            privateKey, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
            //轉換格式  類型斷言
            r.rsaPrivateKey = privateKey.(*rsa.PrivateKey)
        }
    }

    if r.publicKey != "" {
        //將公鑰解碼 解析 轉換格式
        block, _ := pem.Decode([]byte(r.publicKey))
        publicKey, _ := x509.ParsePKIXPublicKey(block.Bytes)
        r.rsaPublicKey = publicKey.(*rsa.PublicKey)
    }
}

//Encrypt 加密
func (r *Rsa) Encrypt(data []byte) ([]byte, error) {
    // blockLength = 密鑰長度 = 一次能加密的明文長度
    // "/8" 將bit轉為bytes
    // "-11" 為 PKCS#1 建議的 padding 占用了 11 個字節
    blockLength := r.rsaPublicKey.N.BitLen()/8 - 11
    //如果明文長度不大于密鑰長度,可以直接加密
    if len(data) <= blockLength {
        //對明文進行加密
        return rsa.EncryptPKCS1v15(rand.Reader, r.rsaPublicKey, []byte(data))
    }
    //否則分段加密
    //創建一個新的緩沖區
    buffer := bytes.NewBufferString("")
    pages := len(data) / blockLength //切分為多少塊
    //循環加密
    for i := 0; i <= pages; i++ {
        start := i * blockLength
        end := (i + 1) * blockLength
        if i == pages {//最后一頁的判斷
            if start == len(data) {
                continue
            }
            end = len(data)
        }
        //分段加密
        chunk, err := rsa.EncryptPKCS1v15(rand.Reader, r.rsaPublicKey, data[start:end])
        if err != nil {
            return nil, err
        }
        //寫入緩沖區
        buffer.Write(chunk)
    }
    //讀取緩沖區內容并返回,即返回加密結果
    return buffer.Bytes(), nil
}

//Decrypt 解密
func (r *Rsa) Decrypt(data []byte) ([]byte, error) {
    //加密后的密文長度=密鑰長度。如果密文長度大于密鑰長度,說明密文非一次加密形成
    //1、獲取密鑰長度
    blockLength := r.rsaPublicKey.N.BitLen() / 8
    if len(data) <= blockLength {//一次形成的密文直接解密
        return rsa.DecryptPKCS1v15(rand.Reader, r.rsaPrivateKey, data)
    }

    buffer := bytes.NewBufferString("")
    pages := len(data) / blockLength
    for i := 0; i <= pages; i++ {//循環解密
        start := i * blockLength
        end := (i + 1) * blockLength
        if i == pages {
            if start == len(data) {
                continue
            }
            end = len(data)
        }
        chunk, err := rsa.DecryptPKCS1v15(rand.Reader, r.rsaPrivateKey, data[start:end])
        if err != nil {
            return nil, err
        }
        buffer.Write(chunk)
    }
    return buffer.Bytes(), nil
}

//Sign 簽名
func (r *Rsa) Sign(data []byte, sHash crypto.Hash) ([]byte, error) {
    hash := sHash.New()
    hash.Write(data)
    sign, err := rsa.SignPKCS1v15(rand.Reader, r.rsaPrivateKey, sHash, hash.Sum(nil))
    if err != nil {
        return nil, err
    }
    return sign, nil
}

//Verify 驗簽
func (r *Rsa) Verify(data []byte, sign []byte, sHash crypto.Hash) bool {
    h := sHash.New()
    h.Write(data)
    return rsa.VerifyPKCS1v15(r.rsaPublicKey, sHash, h.Sum(nil), sign) == nil
}

//CreateKeys 生成pkcs1 格式的公鑰私鑰
func (r *Rsa) CreateKeys(keyLength int) (privateKey, publicKey string) {
    //根據 隨機源 與 指定位數,生成密鑰對。rand.Reader = 密碼強大的偽隨機生成器的全球共享實例
    rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
    if err != nil {
        return
    }
    //編碼私鑰
    privateKey = string(pem.EncodeToMemory(&pem.Block{
        Type:  "RSA PRIVATE KEY",//自定義類型
        Bytes: x509.MarshalPKCS1PrivateKey(rsaPrivateKey),
    }))
    //編碼公鑰
    objPkix, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
    if err != nil {
        return
    }
    publicKey = string(pem.EncodeToMemory(&pem.Block{
        Type:  "PUBLIC KEY",
        Bytes: objPkix,
    }))
    return
}

//CreatePkcs8Keys 生成pkcs8 格式公鑰私鑰
func (r *Rsa) CreatePkcs8Keys(keyLength int) (privateKey, publicKey string) {
    rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
    if err != nil {
        return
    }
    //兩種方式
    //一:1、生成pkcs1格式的密鑰 2、將其轉化為pkcs8格式的密鑰(使用自定義方法)
    //  objPkcs1 := x509.MarshalPKCS1PrivateKey(rsaPrivateKey)
    //  objPkcs8 := r.Pkcs1ToPkcs8(objPkcs1)
    //二:直接使用 x509 包 MarshalPKCS8PrivateKey 生成pkcs8密鑰
    objPkcs8,_ := x509.MarshalPKCS8PrivateKey(rsaPrivateKey)
    //fmt.Println("對比兩種結果",strings.Compare(string(objPkcs8),string(rr)))

    privateKey = string(pem.EncodeToMemory(&pem.Block{
        Type:  "PRIVATE KEY",
        Bytes: objPkcs8,
    }))

    objPkix, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
    if err != nil {
        return
    }

    publicKey = string(pem.EncodeToMemory(&pem.Block{
        Type:  "PUBLIC KEY",
        Bytes: objPkix,
    }))
    return
}

//Pkcs1ToPkcs8 將pkcs1 轉到 pkcs8 自定義
func (r *Rsa) Pkcs1ToPkcs8(key []byte) []byte {
    info := struct {
        Version             int
        PrivateKeyAlgorithm []asn1.ObjectIdentifier
        PrivateKey          []byte
    }{}
    info.Version = 0
    info.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
    info.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
    info.PrivateKey = key
    k, _ := asn1.Marshal(info)
    return k
}

使用

func testRsa()  {
       // 生成一段string
    data := strings.Repeat("H", 245)+"q"

    //生成 公鑰 私鑰
    privateKey, publicKey := helpers.NewRsa("", "").CreatePkcs8Keys(2048)
    //privateKey, publicKey := helpers.NewRsa("", "").CreateKeys(1024)
    fmt.Printf("公鑰:%v \n 私鑰: %v \n", publicKey, privateKey)

    rsaObj := helpers.NewRsa(publicKey, privateKey)
    //加密
    sData, err := rsaObj.Encrypt([]byte(data))
    if err != nil {
        fmt.Println("加密失敗:", err)
    }
    //解密
    pData, err := rsaObj.Decrypt(sData)
    if err != nil {
        fmt.Println("解密失敗:", err)
    }
        //簽名
    sign, _ := rsaObj.Sign([]byte(data), crypto.SHA256)
        //驗簽
    verify := rsaObj.Verify([]byte(data), sign, crypto.SHA256)
    fmt.Printf(" 加密:%v\n 解密:%v\n 簽名:%v\n 驗簽結果:%v\n",
        hex.EncodeToString(sData),
        string(pData),
        hex.EncodeToString(sign),
        verify,
    )
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。