go語言實現非對稱加密——RSA加密解密的實現

版權聲明:本文爲作者原創,如需轉載,請註明出處
https://blog.csdn.net/weixin_42940826


非對稱加密簡介

什麼是非對稱加密
非對稱加密,顧名思義,是相對於對稱加密的一種加密方法,對稱加密是指加密與解密使用的是同一把祕鑰,而非對稱加密有兩把不同的祕鑰,一個稱之爲公鑰,另一個稱之爲私鑰,使用公鑰加密,私鑰可以解密。或者使用私鑰加密,公鑰可以解密。大多數情況下,公鑰可以公開,但是私鑰只能自行持有,不可泄露。
常用的非對稱密碼算法有RSA、ECC橢圓形加密這兩種。
本文亦將用go語言具體實現RSA的加密解密,關於橢圓形曲線加密,將在我的另一篇博文中作詳細介紹。

爲什麼需要非對稱加密
非對稱加密可以說是密碼學史上最偉大的發明之一,因爲它解決了對稱加密的祕鑰配送問題,舉個例子,A和B進行通信,A使用祕鑰爲123456,那麼B如何知道祕鑰爲123456進行解密呢,如果直接發送,很容易被黑客抓取到,除了私底下交換祕鑰,似乎沒有更好的方法了。
但是非對稱加密的出現解決了這一弊端,舉個例子,還是A和B進行通信,A要給B發送信息,B把自己的公鑰發送給A,然後A使用B的公鑰對信息進行加密 發送給B,由於此信息使用的B的公鑰進行加密,所以只有使用B的私鑰才能解密,因此即使黑客知道B的公鑰,也是沒有任何辦法的。

應用場景
信息加密,登陸認證,數字簽名,數字證書等等,如今紅極一時的區塊鏈技術也是使用了非對稱加密,還有包括網銀U盾、二代居民身份證本質上也是使用了非對稱加密。
關於數字簽名將在我的另一篇博文中作詳細介紹。


RSA加密解密流程一覽

生成私鑰流程

  1. 使用rsa中的GenerateKey方法生成私鑰

    func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error)

    • rand.Reader ->隨機數生成器
    • bits ->建議1024的整數倍
  2. 通過x509標準將得到的ras私鑰序列化爲ASN.1 的 DER編碼字符串

    func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte

  3. 將私鑰字符串設置到pem格式塊中

    初始化一個pem.Block塊

    type Block struct {
       Type    string            // 得自前言的類型(如"RSA PRIVATE KEY")
       Headers map[string]string // 可選的頭項
       Bytes   []byte            // 內容解碼後的數據,一般是DER編碼的ASN.1結構
    }
    
  4. 通過pem將設置好的數據進行編碼, 並寫入磁盤文件中

    func Encode(out io.Writer, b *Block) error

    • out - 準備一個文件指針
    • block- 將準備好的pem.block放入其中

生成公鑰流程

  1. 從得到的私鑰對象中將公鑰信息取出

    type PrivateKey struct {
        PublicKey            // 公鑰
        D         *big.Int   // 私有的指數
        Primes    []*big.Int // N的素因子,至少有兩個
        // 包含預先計算好的值,可在某些情況下加速私鑰的操作
        Precomputed PrecomputedValues
    }
    
  2. 通過x509標準將得到 的rsa公鑰序列化爲字符串

    func MarshalPKIXPublicKey(pub interface{}) ([]byte, error)
    
  3. 將公鑰字符串設置到pem格式塊中

    type Block struct {
        Type    string            // 得自前言的類型(如"RSA PRIVATE KEY")
        Headers map[string]string // 可選的頭項
        Bytes   []byte            // 內容解碼後的數據,一般是DER編碼的ASN.1結	}
    
  4. 通過pem將設置好的數據進行編碼, 並寫入磁盤文件

    func Encode(out io.Writer, b *Block) error

RSA加密流程

  1. 將公鑰文件中的公鑰讀出, 得到使用pem編碼的字符串

    – 讀文件

  2. 將得到的字符串pem解碼

    – pem.Decode

  3. 使用x509將編碼之後的公鑰解析出來

    – func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)

  4. 使用得到的公鑰通過rsa進行數據加密

RSA解密流程

  1. 將私鑰文件中的私鑰讀出, 得到使用pem編碼的字符串
  2. 將得到的字符串pem解碼
  3. 使用x509將編碼之後的私鑰解析出來
  4. 使用得到的私鑰通過rsa進行數據解密

代碼實現

package main

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

func Getkeys(){
	//得到私鑰
	privateKey,_:=rsa.GenerateKey(rand.Reader,2048)
	//通過x509標準將得到的ras私鑰序列化爲ASN.1 的 DER編碼字符串
	x509_Privatekey:=x509.MarshalPKCS1PrivateKey(privateKey)
	//創建一個用來保存私鑰的以.pem結尾的文件
	fp,_:=os.Create("csdn_private.pem")
	defer fp.Close()
	//將私鑰字符串設置到pem格式塊中
	pem_block:=pem.Block{
		Type:"csdn_privateKey",
		Bytes:x509_Privatekey,
	}
	//轉碼爲pem並輸出到文件中
	pem.Encode(fp,&pem_block)

	//處理公鑰,公鑰包含在私鑰中
	publickKey:=privateKey.PublicKey
	//接下來的處理方法同私鑰
	//通過x509標準將得到的ras私鑰序列化爲ASN.1 的 DER編碼字符串
	x509_PublicKey,_:=x509.MarshalPKIXPublicKey(&publickKey)
	pem_PublickKey:=pem.Block{
		Type:"csdn_PublicKey",
		Bytes:x509_PublicKey,
	}
	file,_:=os.Create("csdn_PublicKey.pem")
	defer file.Close()
	//轉碼爲pem並輸出到文件中
	pem.Encode(file,&pem_PublickKey)

}

//使用公鑰進行加密
func RSA_encrypter(path string,msg []byte)[]byte  {
	//首先從文件中提取公鑰
	fp,_:=os.Open(path)
	defer fp.Close()
	//測量文件長度以便於保存
	fileinfo,_:=fp.Stat()
	buf:=make([]byte,fileinfo.Size())
	fp.Read(buf)
	//下面的操作是與創建祕鑰保存時相反的
	//pem解碼
	block,_:=pem.Decode(buf)
	//x509解碼,得到一個interface類型的pub
	pub,_:=x509.ParsePKIXPublicKey(block.Bytes)
	//加密操作,需要將接口類型的pub進行類型斷言得到公鑰類型
	cipherText,_:=rsa.EncryptPKCS1v15(rand.Reader,pub.(*rsa.PublicKey),msg)
	return cipherText
}

//使用私鑰進行解密
func RSA_decrypter(path string,cipherText []byte)[]byte  {
	//同加密時,先將私鑰從文件中取出,進行二次解碼
	fp,_:=os.Open(path)
	defer fp.Close()
	fileinfo,_:=fp.Stat()
	buf:=make([]byte,fileinfo.Size())
	fp.Read(buf)
	block,_:=pem.Decode(buf)
	PrivateKey,_:=x509.ParsePKCS1PrivateKey(block.Bytes)
	//二次解碼完畢,調用解密函數
	afterDecrypter,_:=rsa.DecryptPKCS1v15(rand.Reader,PrivateKey,cipherText)
	return afterDecrypter
}

func main() {
	//嘗試調用
	msg:=[]byte("RSA非對稱加密很棒")
	ciphertext:=RSA_encrypter("csdn_PublicKey.pem",msg)
	//轉化爲十六進制方便查看結果
	fmt.Println(hex.EncodeToString(ciphertext))
	result:=RSA_decrypter("csdn_private.pem",ciphertext)
	fmt.Println(string(result))
}


以上就是加密解密的go語言實現了。

我博客中還有很多關於對稱加密,橢圓形曲線加密解密,單向散列函數、數字簽名等詳細分析,歡迎一起交流: )

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章