非對稱加密 RSA
- 優(yōu)點
與對稱加密相比掺出,安全性更好载慈,加解密需要不同的密鑰,公鑰和私鑰都可進行相互的加解密珍手。
- 缺點
加密和解密花費時間長办铡、速度慢,只適合對少量數(shù)據(jù)進行加密琳要。
- 應(yīng)用場景
適合于對安全性要求很高的場景寡具,適合加密少量數(shù)據(jù),比如支付數(shù)據(jù)稚补、登錄數(shù)據(jù)等童叠。
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)
//轉(zhuǎn)換格式 類型斷言
r.rsaPrivateKey = privateKey.(*rsa.PrivateKey)
}
}
if r.publicKey != "" {
//將公鑰解碼 解析 轉(zhuǎn)換格式
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轉(zhuǎn)為bytes
// "-11" 為 PKCS#1 建議的 padding 占用了 11 個字節(jié)
blockLength := r.rsaPublicKey.N.BitLen()/8 - 11
//如果明文長度不大于密鑰長度厦坛,可以直接加密
if len(data) <= blockLength {
//對明文進行加密
return rsa.EncryptPKCS1v15(rand.Reader, r.rsaPublicKey, []byte(data))
}
//否則分段加密
//創(chuàng)建一個新的緩沖區(qū)
buffer := bytes.NewBufferString("")
pages := len(data) / blockLength //切分為多少塊
//循環(huán)加密
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
}
//寫入緩沖區(qū)
buffer.Write(chunk)
}
//讀取緩沖區(qū)內(nèi)容并返回五垮,即返回加密結(jié)果
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++ {//循環(huán)解密
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) {
//根據(jù) 隨機源 與 指定位數(shù),生成密鑰對撬碟。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、將其轉(zhuǎn)化為pkcs8格式的密鑰(使用自定義方法)
// objPkcs1 := x509.MarshalPKCS1PrivateKey(rsaPrivateKey)
// objPkcs8 := r.Pkcs1ToPkcs8(objPkcs1)
//二:直接使用 x509 包 MarshalPKCS8PrivateKey 生成pkcs8密鑰
objPkcs8,_ := x509.MarshalPKCS8PrivateKey(rsaPrivateKey)
//fmt.Println("對比兩種結(jié)果",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 轉(zhuǎn)到 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 驗簽結(jié)果:%v\n",
hex.EncodeToString(sData),
string(pData),
hex.EncodeToString(sign),
verify,
)
}