RSA演算法講解與Go語言例項
阿新 • • 發佈:2018-12-10
一、RSA演算法概述
RSA是"非對稱加密演算法",非對稱加密演算法需要兩個金鑰:公開金鑰(publickey)和私有金鑰(privatekey)。公鑰與私鑰是配對的,用公鑰加密的資料只有配對的私鑰才能解密,反之亦然。因加解密使用兩個不同的金鑰,所以這種演算法叫作非對稱加密演算法。 使用RSA加密演算法流程如下:
1.訊息接收方B先把公鑰廣播,訊息傳送方A儲存B的公鑰 2.當A需要向B傳送訊息時,先用B的公鑰將訊息進行加密,再將密文傳送給A 3.A接受到密文以後,使用自己的私鑰進行解密
RSA具有一個離散對數和橢圓曲線加密都沒有的特性: 既可以用公鑰加密然後私鑰解密,也可以用私鑰加密然後公鑰解密(對稱性)。
公鑰加密然後私鑰解密,可以用於通訊中擁有公鑰的一方向擁有私鑰的另一方傳遞機密資訊,不被第三方竊聽。
那麼私鑰加密然後公鑰解密是用在什麼場合呢?就是數字簽名。
二、數字簽名
RSA中的每一個公鑰都有唯一的私鑰與之對應,任一公鑰只能解開對應私鑰加密的內容。換句話說,其它私鑰加密的內容,這個公鑰是解不開的。
如果你生成了一對RSA金鑰,你把公鑰公佈出去,並告訴全世界人這個公鑰是你的。之後你只要在傳送的訊息,比如“123456”,後面加上用私鑰加密過的密文,其他人拿公鑰解密,看解密得到的內容是是“123456”就可以知道這個“123456”是不是你發的。
簽名: 1、提取訊息摘要,使用傳送方私鑰對訊息摘要加密,生成訊息簽名。 2、將訊息簽名和訊息一起,使用接收方公鑰加密,獲得密文。
驗籤: 1、使用接收方私鑰對密文解密,獲得訊息和訊息簽名。 2、使用傳送方公鑰解密訊息簽名,獲得訊息摘要。 3、使用相同辦法重新提取訊息摘要,與上一步中訊息摘要對比,如相同則驗籤成功。
三、Go語言使用RSA演算法加解密例項
package main import ( "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/hex" "encoding/pem" "fmt" "os" ) //生成金鑰對(公鑰和私鑰) func RsaGenKey(bits int) error{ //通過隨機數生成金鑰對 priveKey,err := rsa.GenerateKey(rand.Reader,bits) if err != nil { return err } //x509通用的證書格式:序列號,簽名演算法,頒發者,有效時間等 //PKCS:由RSA實驗室和開發商指定的標準 priStream := x509.MarshalPKCS1PrivateKey(priveKey) block := pem.Block{ Type:"RSA Private key", Bytes:priStream, } /* -------------------BEGIN RSA Private Key--------------------- 內容 -------------------END RSA Private Key----------------------- */ //建立儲存私鑰檔案 priveFile,err := os.Create("private.pem") defer priveFile.Close() if err != nil{ return err } //將塊編碼到檔案中 err = pem.Encode(priveFile,&block) if err != nil{ return err } //從公鑰獲取私鑰 pubKey := priveKey.PublicKey //通過x509標準達到rsa公鑰序列化後的切片 pubStream,err := x509.MarshalPKIXPublicKey(&pubKey) if err != nil{ return err } //建立公鑰塊 block = pem.Block{ Type:"RSA Public Key", Bytes:pubStream, } pubFile,err := os.Create("public.pem") defer pubFile.Close() if err != nil{ return err } //將公鑰塊編碼到檔案 err = pem.Encode(pubFile,&block) if err!= nil{ return err } return nil } //公鑰加密函式 //src待加密的資料,pathName公鑰路徑 func RsaPublicEncrypt(src []byte,pathName string)([]byte,error){ //開啟公鑰檔案 file,err := os.Open(pathName) defer file.Close() if err != nil{ return []byte(""),err } //獲取檔案資訊 info,err := file.Stat() if err != nil{ return []byte(""),err } //建立切片,用於儲存檔案中讀取到的公鑰資訊 recvBuf := make([]byte,info.Size()) //讀取公鑰檔案 file.Read(recvBuf) //將得到的切片解碼到塊中 block,_ := pem.Decode(recvBuf) //使用x509包中的ParsePKIXPublicKey解析公鑰 pubInter,err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil{ return []byte(""),err } //通過斷言將介面轉換成公鑰 pubKey := pubInter.(*rsa.PublicKey) msg,err := rsa.EncryptPKCS1v15(rand.Reader,pubKey,src) if err != nil{ return []byte(""),err } return msg,err } //使用私鑰解密資訊 //src:待解密的私鑰資訊 pathName:私鑰路徑 func RsaPrivateDecrypt(src []byte,pathName string)([]byte,error){ //通過私鑰檔案路徑開啟私鑰檔案 file,err := os.Open(pathName) defer file.Close() if err != nil{ return []byte(""),err } info,err := file.Stat() if err != nil { return []byte(""), err } //建立切片用於接受私鑰內容 recvBuf := make([]byte,info.Size()) //讀取私鑰檔案 file.Read(recvBuf) block,_ := pem.Decode(recvBuf) privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil{ return []byte(""),err } msg,err := rsa.DecryptPKCS1v15(rand.Reader,privateKey,src) if err != nil{ return []byte(""),err } return msg,nil } func main(){ err := RsaGenKey(1024) if err != nil{ fmt.Println("err=",err) } src := []byte("單槍匹馬你別怕,一腔孤勇又如何!") data,err := RsaPublicEncrypt(src,"public.pem") if err != nil{ fmt.Println("err:",err) return } fmt.Println("加密:",hex.EncodeToString(data)) data,err = RsaPrivateDecrypt(data,"private.pem") if err != nil{ fmt.Println("Decrypt err:",err) return } fmt.Println("解密:",string(data)) }
四、Go語言使用RSA演算法實現數字簽名認證
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"os"
)
//生成金鑰對(公鑰和私鑰)
func RsaGenKey(bits int) error{
//通過隨機數生成金鑰對
priveKey,err := rsa.GenerateKey(rand.Reader,bits)
if err != nil {
return err
}
//x509通用的證書格式:序列號,簽名演算法,頒發者,有效時間等
//PKCS:由RSA實驗室和開發商指定的標準
priStream := x509.MarshalPKCS1PrivateKey(priveKey)
block := pem.Block{
Type:"RSA Private key",
Bytes:priStream,
}
/*
-------------------BEGIN RSA Private Key---------------------
內容
-------------------END RSA Private Key-----------------------
*/
//建立儲存私鑰檔案
priveFile,err := os.Create("private.pem")
defer priveFile.Close()
if err != nil{
return err
}
//將塊編碼到檔案中
err = pem.Encode(priveFile,&block)
if err != nil{
return err
}
//從公鑰獲取私鑰
pubKey := priveKey.PublicKey
//通過x509標準達到rsa公鑰序列化後的切片
pubStream,err := x509.MarshalPKIXPublicKey(&pubKey)
if err != nil{
return err
}
//建立公鑰塊
block = pem.Block{
Type:"RSA Public Key",
Bytes:pubStream,
}
pubFile,err := os.Create("public.pem")
defer pubFile.Close()
if err != nil{
return err
}
//將公鑰塊編碼到檔案
err = pem.Encode(pubFile,&block)
if err!= nil{
return err
}
return nil
}
//公鑰加密函式
//src待加密的資料,pathName公鑰路徑
func RsaPublicEncrypt(src []byte,pathName string)([]byte,error){
//開啟公鑰檔案
file,err := os.Open(pathName)
defer file.Close()
if err != nil{
return []byte(""),err
}
//獲取檔案資訊
info,err := file.Stat()
if err != nil{
return []byte(""),err
}
//建立切片,用於儲存檔案中讀取到的公鑰資訊
recvBuf := make([]byte,info.Size())
//讀取公鑰檔案
file.Read(recvBuf)
//將得到的切片解碼到塊中
block,_ := pem.Decode(recvBuf)
//使用x509包中的ParsePKIXPublicKey解析公鑰
pubInter,err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil{
return []byte(""),err
}
//通過斷言將介面轉換成公鑰
pubKey := pubInter.(*rsa.PublicKey)
msg,err := rsa.EncryptPKCS1v15(rand.Reader,pubKey,src)
if err != nil{
return []byte(""),err
}
return msg,err
}
//使用私鑰解密資訊
//src:待解密的私鑰資訊 pathName:私鑰路徑
func RsaPrivateDecrypt(src []byte,pathName string)([]byte,error){
//通過私鑰檔案路徑開啟私鑰檔案
file,err := os.Open(pathName)
defer file.Close()
if err != nil{
return []byte(""),err
}
info,err := file.Stat()
if err != nil {
return []byte(""), err
}
//建立切片用於接受私鑰內容
recvBuf := make([]byte,info.Size())
//讀取私鑰檔案
file.Read(recvBuf)
block,_ := pem.Decode(recvBuf)
privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil{
return []byte(""),err
}
msg,err := rsa.DecryptPKCS1v15(rand.Reader,privateKey,src)
if err != nil{
return []byte(""),err
}
return msg,nil
}
//私鑰簽名
//data:訊息內容
//pathName:私鑰檔名
func RsaSign(data []byte,pathName string)([]byte,error){
h := sha256.New()
h.Write(data)
hashed := h.Sum(nil)
//獲取私鑰
file,err := os.Open(pathName)
defer file.Close()
if err != nil{
return []byte(""),err
}
info,err := file.Stat()
if err != nil {
return []byte(""), err
}
//建立切片用於接受私鑰內容
recvBuf := make([]byte,info.Size())
//讀取私鑰檔案
file.Read(recvBuf)
block,_ := pem.Decode(recvBuf)
privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil{
return []byte(""),err
}
return rsa.SignPKCS1v15(rand.Reader,privateKey,crypto.SHA256,hashed)
}
//公鑰驗證
func RsaSignVer(data []byte,pathName string,signature []byte)error{
//獲取私鑰
file,err := os.Open(pathName)
defer file.Close()
if err != nil{
return err
}
info,err := file.Stat()
if err != nil {
return err
}
//建立切片用於接受公鑰內容
recvBuf := make([]byte,info.Size())
//讀取公鑰檔案
file.Read(recvBuf)
hashed := sha256.Sum256(data)
block,_ := pem.Decode(recvBuf)
if block == nil{
return errors.New("public key error")
}
// 解析公鑰
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return err
}
// 型別斷言
pub := pubInterface.(*rsa.PublicKey)
//驗證簽名
return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed[:], signature)
}
func main(){
err := RsaGenKey(1024)
if err != nil{
fmt.Println("err=",err)
}
msg := []byte("單槍匹馬你別怕,一腔孤勇又如何!")
fmt.Println("msg:",string(msg))
sig,err := RsaSign(msg,"private.pem")
if err !=nil{
fmt.Println("RsaSign error:",err)
return
}
fmt.Println("sig:",sig)
if err := RsaSignVer(msg,"public.pem",sig);err != nil{
fmt.Println("RsaSignVer error:",err)
return
}
fmt.Println("簽名驗證成功")
}