天天看點

GO實作MD5和RSA分段加解密

前言

在嘗試RSA加/解密的時候,發現go标準庫中僅有"公鑰加密,私鑰解密",而沒有“私鑰加密、公鑰解密”。經過考慮,我認為GO的開發者是故意這樣設計的,原因如下:

  1. 非對稱加密相比對稱加密的好處就是:私鑰自己保留,公鑰公布出去,公鑰加密後隻有私鑰能解開,私鑰加密後隻有公鑰能解開。
  2. 如果僅有一對密鑰,與對稱加密差別就不大了。

    假如你是服務提供方,使用私鑰進行加密後,接入方使用你提供的公鑰進行解密,一旦這個公鑰洩漏,帶來的後果和對稱加密密鑰洩漏是一樣的。隻有雙方互換公鑰(均使用對方公鑰加密,己方私鑰解密),才能充分發揮非對稱加密的優勢。

當然,有第三方庫支援“私鑰加密、公鑰解密”的,有興趣的夥伴可自行百度。

RSA加密時,明文長度>(密鑰長度-padding長度)時需要進行分段。PKCS1填充長度為11

main_test.go

package main

import (
	"demos/kris/security"
	"encoding/base64"
	"encoding/hex"
	"log"
)

func main() {
	var mingwen = "我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥"
	md5 := security.MD5([]byte(mingwen))
	//MD5列印為16進制字元串
	log.Println(hex.EncodeToString(md5))

	//RSA的内容使用base64列印
	privateKey, publicKey, _ := security.GenRSAKey(1024)
	log.Println("rsa私鑰:\t", base64.StdEncoding.EncodeToString(privateKey))
	log.Println("rsa公鑰:\t", base64.StdEncoding.EncodeToString(publicKey))

	miwen, err := security.RsaEncryptBlock([]byte(mingwen), publicKey)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("加密後:\t", base64.StdEncoding.EncodeToString(miwen))

	jiemi, err := security.RsaDecryptBlock(miwen, privateKey)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("解密後:\t", string(jiemi))
}

           

md5.go

package security

import (
	"crypto/md5"
)

func MD5(src []byte) []byte {
	hash := md5.New()
	hash.Write(src)
	return hash.Sum(nil)
}
           

rsa.go

代碼中使用[]byte傳遞明文、密文、密鑰。提供普通加解密、分段加解密,生成密鑰對的功能。

package security

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"log"
)

/**
生成RSA密鑰對
 */
func GenRSAKey(size int) (privateKeyBytes, publicKeyBytes []byte, err error) {
	//生成密鑰
	privateKey, err := rsa.GenerateKey(rand.Reader, size)
	if err != nil {
		return
	}
	privateKeyBytes = x509.MarshalPKCS1PrivateKey(privateKey)
	publicKeyBytes = x509.MarshalPKCS1PublicKey(&privateKey.PublicKey)
	return
}

/**
公鑰加密
 */
func RsaEncrypt(src, publicKeyByte []byte) (bytes []byte, err error) {
	publicKey, err := x509.ParsePKCS1PublicKey(publicKeyByte)
	if err != nil {
		return
	}
	return rsa.EncryptPKCS1v15(rand.Reader, publicKey, src)
}

/**
公鑰加密-分段
 */
func RsaEncryptBlock(src, publicKeyByte []byte) (bytesEncrypt []byte, err error) {
	publicKey, err := x509.ParsePKCS1PublicKey(publicKeyByte)
	if err != nil {
		return
	}
	keySize, srcSize := publicKey.Size(), len(src)
	log.Println("密鑰長度:", keySize, "\t明文長度:\t", srcSize)
	//單次加密的長度需要減掉padding的長度,PKCS1為11
	offSet, once := 0, keySize-11
	buffer := bytes.Buffer{}
	for offSet < srcSize {
		endIndex := offSet + once
		if endIndex > srcSize {
			endIndex = srcSize
		}
		// 加密一部分
		bytesOnce, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, src[offSet:endIndex])
		if err != nil {
			return nil, err
		}
		buffer.Write(bytesOnce)
		offSet = endIndex
	}
	bytesEncrypt = buffer.Bytes()
	return
}


/**
私鑰解密
 */
func RsaDecrypt(src, privateKeyBytes []byte) (bytesDecrypt []byte, err error) {
	privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes)
	if err != nil {
		return
	}
	return rsa.DecryptPKCS1v15(rand.Reader, privateKey, src)
}

/**
私鑰解密-分段
 */
func RsaDecryptBlock(src, privateKeyBytes []byte) (bytesDecrypt []byte, err error) {
	privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBytes)
	if err != nil {
		return
	}
	keySize := privateKey.Size()
	srcSize := len(src)
	log.Println("密鑰長度:", keySize, "\t密文長度:\t", srcSize)
	var offSet = 0
	var buffer = bytes.Buffer{}
	for offSet < srcSize {
		endIndex := offSet + keySize
		if endIndex > srcSize {
			endIndex = srcSize
		}
		bytesOnce, err := rsa.DecryptPKCS1v15(rand.Reader, privateKey, src[offSet:endIndex])
		if err != nil {
			return nil, err
		}
		buffer.Write(bytesOnce)
		offSet = endIndex
	}
	bytesDecrypt = buffer.Bytes()
	return
}
           

運作結果:

2018/12/29 15:30:52 d97dda9fb100759916be5c32f9daaa3a
2018/12/29 15:30:52 rsa私鑰:	 MIICXAIBAAKBgQCzTAvxAijkbdAM63NM+UmWv7Yx11/fK2FkX1svklK8BBk9XGBCkg4iePEUqhR9YUljRfEQI/EAlc5wG84w+FTnNqdHa95KK+fALQvKqxAU3976RqH2j4r28WUUQxPZjWfEeIjb5XfG5DjNFwQbJXmrymaHeDNsKg5a0LggGHmmlwIDAQABAoGAAddZFAuCof3isg9E6thwggTL+S0OBfurD13PUOi+wsGEBNZLAsP/MylsyFqKxVLXbxaLyC+mTOw853fRoT0bmhPVbma5z5BLFE8yExPOhEOJJU87WA4AXLMdCCZ6+XXs9JhTfT0UPgTIk7l5OLYxmclyTjoxlZCe9gF75n31HxECQQDOtwv5fiOzM8mNoFa82YmnGyHVqDFoXw2kFLTIZd+cqSiS6kN0WsNO4DbslqD5Xr+ENaDmWDWTeRmHY0cwZlI5AkEA3guH2D0LbKqa2FTn/lf9sraXQGsEKm+72ut4Y88XpgfTU4TlEE/y1ipd2W0GwdvJQrt8QIZ6mW0TeIj4Jvx/TwJBAK6EaS6kaL1lDldsM25Sdd1HkcQQsE2+WgTZmlrJbwSS53dJIdO8wMD5mEUbUiHV9PhIUmPFus2bYosjrLlW2TkCQBTcRnXlPkaGPKfoSidWAuqgRtNxemG2P5LQnm3aDeG2SH9HM/H1YN4H+usrWAAsctsHHCQ/vhLd8X9Ydt/KxvcCQHDFGYvFnjnhNW7fGicjYkM3wLrzx+Fy38PDZX+yYNfUxlQcGqru6h3PtabRAu3/pqKX9/HWhgCiIj4jRNFSn3Q=
2018/12/29 15:30:52 rsa公鑰:	 MIGJAoGBALNMC/ECKORt0Azrc0z5SZa/tjHXX98rYWRfWy+SUrwEGT1cYEKSDiJ48RSqFH1hSWNF8RAj8QCVznAbzjD4VOc2p0dr3kor58AtC8qrEBTf3vpGofaPivbxZRRDE9mNZ8R4iNvld8bkOM0XBBsleavKZod4M2wqDlrQuCAYeaaXAgMBAAE=
2018/12/29 15:30:52 密鑰長度: 128 	明文長度:	 288
2018/12/29 15:30:52 加密後:	 MTDi/0SZ3iy7RpWDX4yotnldqZMlyjoCfXpu1W/LjmNwV8TB9cm0upy8TLp9N2aULq2jw2OgTzwihCjsd3qQVpjCS5BkYWBi9dBQoRMdV5pqq/RS9Ydb0rvx9dL9yWxLRjfAabGq3eJPI9NyGrd+aMSmQfN7Mcnd7Vzrch94DGoeIIW+qzHk8tKmiV01xvx1m+jMxUZAfave7AT35HzNiJBr7OhXugFyYfOay2A+BCi8mBSH+kcbzsnyFc7XPiaOeZZY6Jsh8PPznZpbS8A2IK50CYI8FmmadP13yk0X5KF3PZK2rEVAQh9zbDJmme8oW4TCJvg7E3y+pzTVNKCeQ50Fv9GGLNrQRemd8rEkKH2sTn6lvAEnJlD3bTOxbGQfsDLELEtcl8ua6pjxU9dwdU7Y/Ednm7x/3FcvtCzG42rMrZcZhYm0FoKwLnW5I9TSrQGuJDOH5hSvA6ZZxSTeBgKjRqInAyf9Vx48wdVv04WS/LHGB8nnO3XLHvO0C4sf
2018/12/29 15:30:52 密鑰長度: 128 	密文長度:	 384
2018/12/29 15:30:52 解密後:	 我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥我不管我就是最帥