非对称加密的RSA算法如何通过golang来实现?

2022-04-25 09:22:03 浏览数 (1)

上一篇文章我们讲了golang实现AES的方式,这里我们来讲一下RSA算法如何通过golang实现。需要注意的是rsa本身不支持大文件的加密,我们需要分段切割进行加解密。下面我们来看下代码。

代码语言:javascript复制
package main

import (
  "bytes"
  "crypto/rand"
  "crypto/rsa"
  "crypto/x509"
  "encoding/base64"
  "encoding/hex"
  "encoding/pem"
  "fmt"
  "log"
)

func main() {
  data3, err := PublicEncrypt("sdfsdf")
  fmt.Println(data3, err)
  data4, err := PrivateDecrypt(data3)
  fmt.Println(data4, err)

  data, err := RsaEncrypt("zxxx")
  fmt.Println(data, err)
  data2, err := RsaDecrypt(data)
  fmt.Println(data2, err)
}

var privateKeyData = "-----BEGIN RSA PRIVATE KEY-----nMIICXAIBAAKBgQC11jirOpqCVTH0hNQJMwFZ9v6winoar8gUsZIHYyKhe3lmD/Mqn nfXIPhrQqd uzEWKu4td3kqzhAKB h L8bpq2y6o5p6 Fvn7pGgiu8P4qB8tZM8nnMN5SqK3vht0qcgjZ4XqiwdDEisG owTHyguIzHTDvJa7ryQ0Cbibb3GUQIDAQABnAoGAUEKI6tNIJaTzEsmaSaEwxIPn8QZ VM8n0jJ6kTYpr/svH2SE4YCCavtLixR1nl9OKHA3A6WKlocYogDTzYtc1xWkJMXsfQq9VK0EunBxTpOgSsUW1eVjgW26 xgCfnPSqaE/M9JTwRXHLIT3SEonS9GE5sOTpZcrK6L/obCRA74BECQQDnr4qaG dSElEcnuWm4pHFpEZcmCC1fcSB nR4sL7ZzuetwBNWOluvtkQwvoFuVb4JG9KoRw40l bKun7uWFr3SNAkEAyOtw X8FXXRR5xgkmaMG8O2/GsD4703LmLMfE1bRwwyltg8DC6fDnNRdGH8yMRss4YfkttbJNtRtOl1r81VJB1QJAFHcYGibO1xwRGCV0pj 4WNyZ6l0cnjOq0QRrl2GdaiXxpxJpYtuCz9Gc0mVxj2p5f9p6UCz nzyvwUa1 jsGB3QJATn4EnZcQk0Wy27oQ1EDxrYsZOqWIIHl0TE/WuRzzct8mCF4zn0K7aiSwtfhDIIIQV49iXn7erZhs5DNsgaDDCVfQJBAIavhMTuGVsq5ZISPYLgiqWbL2PI0kpQqWAdjgCA02XInHy1PtTmKCR3YHytmsDDZOlNMcaVFd/epzPxGriOpHIU=n-----END RSA PRIVATE KEY-----"
var publicKeyData = "-----BEGIN PUBLIC KEY-----nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC11jirOpqCVTH0hNQJMwFZ9v6wninoar8gUsZIHYyKhe3lmD/Mq nfXIPhrQqd uzEWKu4td3kqzhAKB h L8bpq2y6no5p6 Fvn7pGgiu8P4qB8tZM8nMN5SqK3vht0qcgjZ4XqiwdDEisG owTHyguIzHTnDvJa7ryQ0Cbibb3GUQIDAQABn-----END PUBLIC KEY-----"

//大文件切割函数
func split(buf []byte, lim int) [][]byte {
  var chunk []byte
  chunks := make([][]byte, 0, len(buf)/lim 1)
  for len(buf) >= lim {
    chunk, buf = buf[:lim], buf[lim:]
    chunks = append(chunks, chunk)
  }
  if len(buf) > 0 {
    chunks = append(chunks, buf[:len(buf)])
  }
  return chunks
}

// 公钥加密,支持大文件方法
func PublicEncrypt(data string) (string, error) {
  // 解码部分
  block, rest := pem.Decode([]byte(publicKeyData))
  fmt.Println("------", block, string(rest))
  publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
  if err != nil {
    log.Fatal("RsaEncrypt ParsePKIXPublicKey fail", err)
    return "", err
  }
  //断言格式
  publicKey := publicKeyInterface.(*rsa.PublicKey)
  partLen := publicKey.N.BitLen()/8 - 11
  //按照固定切割
  chunks := split([]byte(data), partLen)
  buffer := bytes.NewBufferString("")
  for _, chunk := range chunks {
    //加密方法
    bytes, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, chunk)
    if err != nil {
      return "", err
    }
    buffer.Write(bytes)
  }
  return base64.RawURLEncoding.EncodeToString(buffer.Bytes()), nil
}

// 私钥解密,支持大文件方法
func PrivateDecrypt(encrypted string) (string, error) {
  block, _ := pem.Decode([]byte(privateKeyData))
  privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  if err != nil {
    log.Fatal("RsaDecrypt parse private key fail", err)
    return "", err
  }
  partLen := privateKey.N.BitLen() / 8
  raw, err := base64.RawURLEncoding.DecodeString(encrypted)
  if err != nil {
    log.Fatal("DecodeString", err)
    return "", err
  }
  chunks := split([]byte(raw), partLen)
  buffer := bytes.NewBufferString("")
  for _, chunk := range chunks {
    //解密方法
    decrypted, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, chunk)
    if err != nil {
      log.Fatal("err", err)
      return "", err
    }
    buffer.Write(decrypted)
  }

  return buffer.String(), err
}

// rsa加密,不支持大文件
func RsaEncrypt(content string) (string, error) {
  plainText := []byte(content)
  // 解码部分
  block, _ := pem.Decode([]byte(publicKeyData))
  publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
  if err != nil {
    log.Fatal("RsaEncrypt ParsePKIXPublicKey fail", err)
    return "", err
  }
  publicKey := publicKeyInterface.(*rsa.PublicKey)
  cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
  if err != nil {
    log.Fatal("RsaEncrypt EncryptPKCS1v15 fail", err)
    return "", err
  }
  return hex.EncodeToString(cipherText), nil
}

// rsa解密,不支持大文件
func RsaDecrypt(cryptContent string) (string, error) {
  // 私匙解密
  block, _ := pem.Decode([]byte(privateKeyData))
  privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  if err != nil {
    log.Fatal("RsaDecrypt parse private key fail", err)
    return "", err
  }
  cryptText, err := hex.DecodeString(cryptContent)
  if err != nil {
    log.Fatal("RsaDecrypt cryptContent decode string fail", err)
    return "", err
  }
  plainText, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cryptText)
  if err != nil {
    log.Fatal("RsaDecrypt DecryptPKCS1v15 fail", err)
    return "", err
  }
  return string(plainText), nil
}

上面的代码是可以直接执行生成结果的,如果对公钥和私钥的生成,我们看这段代码:

代码语言:javascript复制
package main

import (
  "crypto/rand"
  "crypto/rsa"
  "crypto/x509"
  "encoding/pem"
  "fmt"
)

func main() {
  privateKey, publickKey := GenRsaKey()
  fmt.Println(string(privateKey), string(publickKey))
}

//RSA公钥私钥产生
func GenRsaKey() (prvkey, pubkey []byte) {
  // 生成私钥文件
  privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
  if err != nil {
    panic(err)
  }
  derStream := x509.MarshalPKCS1PrivateKey(privateKey)
  block := &pem.Block{
    Type:  "RSA PRIVATE KEY",
    Bytes: derStream,
  }
  prvkey = pem.EncodeToMemory(block)
  publicKey := &privateKey.PublicKey
  derPkix, err := x509.MarshalPKIXPublicKey(publicKey)
  if err != nil {
    panic(err)
  }
  block = &pem.Block{
    Type:  "PUBLIC KEY",
    Bytes: derPkix,
  }
  pubkey = pem.EncodeToMemory(block)
  return
}

总结:

RSA加密算法是我们常用的加密方式之一,学习掌握是很重要的。

关于RSA加解密大文件需要分段加密,分段解密。

0 人点赞