非对称加密的RSA算法如何通过golang来实现?
上一篇文章我们讲了golang实现AES的方式,这里我们来讲一下RSA算法如何通过golang实现。需要注意的是rsa本身不支持大文件的加密,我们需要分段切割进行加解密。下面我们来看下代码。
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/Mq\n+nfXIPhrQqd+uzEWKu4td3kqzhAKB+h+L8bpq2y6o5p6+Fvn7pGgiu8P4qB8tZM8\nnMN5SqK3vht0qcgjZ4XqiwdDEisG+owTHyguIzHTDvJa7ryQ0Cbibb3GUQIDAQAB\nAoGAUEKI6tNIJaTzEsmaSaEwxIPn8QZ+VM8n0jJ6kTYpr/svH2SE4YCCavtLixR1\nl9OKHA3A6WKlocYogDTzYtc1xWkJMXsfQq9VK0EunBxTpOgSsUW1eVjgW26+xgCf\nPSqaE/M9JTwRXHLIT3SEonS9GE5sOTpZcrK6L/obCRA74BECQQDnr4qaG+dSElEc\nuWm4pHFpEZcmCC1fcSB+nR4sL7ZzuetwBNWOluvtkQwvoFuVb4JG9KoRw40l+bKu\n7uWFr3SNAkEAyOtw+X8FXXRR5xgkmaMG8O2/GsD4703LmLMfE1bRwwyltg8DC6fD\nNRdGH8yMRss4YfkttbJNtRtOl1r81VJB1QJAFHcYGibO1xwRGCV0pj+4WNyZ6l0c\njOq0QRrl2GdaiXxpxJpYtuCz9Gc0mVxj2p5f9p6UCz+nzyvwUa1+jsGB3QJATn4E\nZcQk0Wy27oQ1EDxrYsZOqWIIHl0TE/WuRzzct8mCF4zn0K7aiSwtfhDIIIQV49iX\n7erZhs5DNsgaDDCVfQJBAIavhMTuGVsq5ZISPYLgiqWbL2PI0kpQqWAdjgCA02XI\nHy1PtTmKCR3YHytmsDDZOlNMcaVFd/epzPxGriOpHIU=\n-----END RSA PRIVATE KEY-----"
var publicKeyData = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC11jirOpqCVTH0hNQJMwFZ9v6w\ninoar8gUsZIHYyKhe3lmD/Mq+nfXIPhrQqd+uzEWKu4td3kqzhAKB+h+L8bpq2y6\no5p6+Fvn7pGgiu8P4qB8tZM8nMN5SqK3vht0qcgjZ4XqiwdDEisG+owTHyguIzHT\nDvJa7ryQ0Cbibb3GUQIDAQAB\n-----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
}
上面的代码是可以直接执行生成结果的,如果对公钥和私钥的生成,我们看这段代码:
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加解密大文件需要分段加密,分段解密。