RSA加解密、签名/验签的实现

package main

import (
   "bytes"
   "crypto"
   "crypto/rand"
   "crypto/rsa"
   "crypto/sha512"
   "crypto/x509"
   "encoding/base64"
   "encoding/pem"
   "fmt"
   "os"
)

// getPublicKey 获取公钥
func getPublicKey() any {
   // 构造公钥文件硬盘路径
   rootPath, _ := os.Getwd()
   publicKeyFile := rootPath + "/conf/rsa/rsa_public_key.pem"

   // 打开公钥文件
   file, err := os.Open(publicKeyFile)
   if err != nil {
      panic("打开公钥文件失败,原因:" + err.Error())
   }

   // 关闭公钥文件
   defer func(file *os.File) {
      err := file.Close()
      if err != nil {
         panic("关闭公钥文件失败,原因:" + err.Error())
      }
   }(file)

   // 读取公钥文件
   contents, _ := file.Stat()
   buffers := make([]byte, contents.Size())
   _, err = file.Read(buffers)
   if err != nil {
      panic("读取公钥文件失败,原因:" + err.Error())
   }

   pemDecode, _ := pem.Decode(buffers)                                 // pem解码
   publicKeyInterface, err := x509.ParsePKIXPublicKey(pemDecode.Bytes) // x509解码
   if err != nil {
      panic("解析公钥文件失败,原因:" + err.Error())
   }

   return publicKeyInterface
}

// getPrivateKey 获取私钥
func getPrivateKey() *rsa.PrivateKey {
   // 构造私钥文件硬盘路径
   rootPath, _ := os.Getwd()
   privateKeyFile := rootPath + "/conf/rsa/rsa_private_key.pem"

   // 打开私钥文件
   file, err := os.Open(privateKeyFile)
   if err != nil {
      panic("打开私钥文件失败,原因:" + err.Error())
   }

   // 关闭私钥文件
   defer func(file *os.File) {
      err := file.Close()
      if err != nil {
         panic("关闭私钥文件失败,原因:" + err.Error())
      }
   }(file)

   // 读取私钥文件
   contents, _ := file.Stat()
   buffers := make([]byte, contents.Size())
   _, err = file.Read(buffers)
   if err != nil {
      panic("读取私钥文件失败,原因:" + err.Error())
   }

   pemDecode, _ := pem.Decode(buffers)                           // pem解码
   privateKey, err := x509.ParsePKCS1PrivateKey(pemDecode.Bytes) // x509解码
   if err != nil {
      panic("解析私钥文件失败,原因:" + err.Error())
   }

   return privateKey
}

// RSADecrypt 私钥解密
func RSADecrypt(ciphertext string) string {
   privateKey := getPrivateKey()
   ciphertextByte, _ := base64.StdEncoding.DecodeString(ciphertext)
   privateKeySize := privateKey.Size()   // 私钥文件长度
   ciphertextSize := len(ciphertextByte) // 消息密文长度
   var offset = 0
   var buffer = bytes.Buffer{}
   for offset < ciphertextSize {
      endIndex := offset + privateKeySize

      if endIndex > ciphertextSize {
         endIndex = ciphertextSize
      }

      decrypt, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, ciphertextByte[offset:endIndex])
      if err != nil {
         panic("解密失败,原因:" + err.Error())
      }

      buffer.Write(decrypt)

      offset = endIndex
   }

   return string(buffer.Bytes())
}

// RSAEncrypt 公钥加密(相同的消息每次加密产生的密文都不同)
func RSAEncrypt(plaintext string) string {
   publicKey := getPublicKey().(*rsa.PublicKey) // 类型断言
   plaintextByte := []byte(plaintext)
   publicKeySize := publicKey.Size()   // 公钥文件长度
   plaintextSize := len(plaintextByte) // 消息明文长度
   offset := 0
   buffer := bytes.Buffer{}

   // 开始加密操作(分段加密)
   for offset < plaintextSize {
      endIndex := offset + publicKeySize - 11

      if endIndex > plaintextSize {
         endIndex = plaintextSize
      }

      encrypt, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plaintextByte[offset:endIndex])
      if err != nil {
         panic("加密失败,原因:" + err.Error())
      }

      buffer.Write(encrypt)

      offset = endIndex
   }

   return base64.StdEncoding.EncodeToString(buffer.Bytes())
}

// RSASign 私钥签名(相同的消息每次生成的签名都相同)
func RSASign(plaintext string) string {
   privateKey := getPrivateKey()
   hash := sha512.New()
   hash.Write([]byte(plaintext))
   hashed := hash.Sum(nil)
   sign, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, hashed)
   if err != nil {
      panic("生成签名失败,原因:" + err.Error())
   }

   return base64.StdEncoding.EncodeToString(sign)
}

// RSAVerify 公钥验签
func RSAVerify(data string, sign string) bool {
   publicKey := getPublicKey().(*rsa.PublicKey) // 类型断言
   sum512 := sha512.Sum512([]byte(data))
   signByte, _ := base64.StdEncoding.DecodeString(sign)
   err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, sum512[:], signByte)
   if err == nil {
      return true
   }

   return false
}

func main() {
   // 消息明文
   message := "孩儿立志出乡关,学不成名誓不还。埋骨何须桑梓地,人生无处不青山。"

   //========== 加密 ==========//
   ciphertext := RSAEncrypt(message)
   fmt.Println("加密后的密文 ===> " + ciphertext) // 加密后的密文 ===> UwoKQ1aWvG+grf/NTrUlXcYxD2EniBMBtf2O++ymmzzQpm3GRHYcCS6S1sT...

   //========== 解密 ==========//
   plaintext := RSADecrypt(ciphertext)
   fmt.Println("解密后的明文 ===> " + plaintext) // 解密后的明文 ===> 孩儿立志出乡关,学不成名誓不还。埋骨何须桑梓地,人生无处不青山。

   //========== 签名 ==========//
   sign := RSASign(message)
   fmt.Println("生成签名 ===> " + sign) // 生成签名 ===> cntcA15sxnLTzZ6prvioC1A+dRxfcHT94O6KiS0RYay5j+Sk7Ciz27ux8C6UcYS/To1dFXjza...

   //========== 验签 ==========//
   verify := RSAVerify(message, sign)
   fmt.Printf("验证签名 ===> %+v \r\n", verify) // 验证签名 ===> true
}

Copyright © 2024 码农人生. All Rights Reserved