版權聲明:本文爲作者原創,如需轉載,請註明出處
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加密解密流程一覽
生成私鑰流程
使用rsa中的GenerateKey方法生成私鑰
func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error)
- rand.Reader ->隨機數生成器
- bits ->建議1024的整數倍
通過x509標準將得到的ras私鑰序列化爲ASN.1 的 DER編碼字符串
func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte
將私鑰字符串設置到pem格式塊中
初始化一個pem.Block塊
type Block struct { Type string // 得自前言的類型(如"RSA PRIVATE KEY") Headers map[string]string // 可選的頭項 Bytes []byte // 內容解碼後的數據,一般是DER編碼的ASN.1結構 }
通過pem將設置好的數據進行編碼, 並寫入磁盤文件中
func Encode(out io.Writer, b *Block) error
- out - 準備一個文件指針
- block- 將準備好的pem.block放入其中
生成公鑰流程
從得到的私鑰對象中將公鑰信息取出
type PrivateKey struct { PublicKey // 公鑰 D *big.Int // 私有的指數 Primes []*big.Int // N的素因子,至少有兩個 // 包含預先計算好的值,可在某些情況下加速私鑰的操作 Precomputed PrecomputedValues }
通過x509標準將得到 的rsa公鑰序列化爲字符串
func MarshalPKIXPublicKey(pub interface{}) ([]byte, error)
將公鑰字符串設置到pem格式塊中
type Block struct { Type string // 得自前言的類型(如"RSA PRIVATE KEY") Headers map[string]string // 可選的頭項 Bytes []byte // 內容解碼後的數據,一般是DER編碼的ASN.1結 構 }
通過pem將設置好的數據進行編碼, 並寫入磁盤文件
func Encode(out io.Writer, b *Block) error
RSA加密流程
將公鑰文件中的公鑰讀出, 得到使用pem編碼的字符串
– 讀文件
將得到的字符串pem解碼
– pem.Decode
使用x509將編碼之後的公鑰解析出來
– func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)
使用得到的公鑰通過rsa進行數據加密
RSA解密流程
- 將私鑰文件中的私鑰讀出, 得到使用pem編碼的字符串
- 將得到的字符串pem解碼
- 使用x509將編碼之後的私鑰解析出來
- 使用得到的私鑰通過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語言實現了。
我博客中還有很多關於對稱加密,橢圓形曲線加密解密,單向散列函數、數字簽名等詳細分析,歡迎一起交流: )