Go語(yǔ)言 如何實(shí)現(xiàn)RSA加密解密
RSA是一種非對(duì)稱加密算法,它的名字是由它的三位開(kāi)發(fā)者,即RonRivest、AdiShamir和LeonardAdleman 的姓氏的首字母組成的(Rivest-Shamir-Adleman ),可用于數(shù)據(jù)加密和數(shù)字簽名。
用于數(shù)據(jù)加密時(shí),消息發(fā)送方利用對(duì)方的公鑰進(jìn)行加密,消息接受方收到密文時(shí)使用自己的私鑰進(jìn)行解密。
實(shí)現(xiàn)代碼如下:
import ( "crypto/rsa" "crypto/rand" "crypto/x509" "os" "encoding/pem" "fmt" ) //生成RSA私鑰和公鑰,保存到文件中 func GenerateRSAKey(bits int){ //GenerateKey函數(shù)使用隨機(jī)數(shù)據(jù)生成器random生成一對(duì)具有指定字位數(shù)的RSA密鑰 //Reader是一個(gè)全局、共享的密碼用強(qiáng)隨機(jī)數(shù)生成器 privateKey, err := rsa.GenerateKey(rand.Reader, bits) if err!=nil{ panic(err) } //保存私鑰 //通過(guò)x509標(biāo)準(zhǔn)將得到的ras私鑰序列化為ASN.1 的 DER編碼字符串 X509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey) //使用pem格式對(duì)x509輸出的內(nèi)容進(jìn)行編碼 //創(chuàng)建文件保存私鑰 privateFile, err := os.Create("private.pem") if err!=nil{ panic(err) } defer privateFile.Close() //構(gòu)建一個(gè)pem.Block結(jié)構(gòu)體對(duì)象 privateBlock:= pem.Block{Type: "RSA Private Key",Bytes:X509PrivateKey} //將數(shù)據(jù)保存到文件 pem.Encode(privateFile,&privateBlock) //保存公鑰 //獲取公鑰的數(shù)據(jù) publicKey:=privateKey.PublicKey //X509對(duì)公鑰編碼 X509PublicKey,err:=x509.MarshalPKIXPublicKey(&publicKey) if err!=nil{ panic(err) } //pem格式編碼 //創(chuàng)建用于保存公鑰的文件 publicFile, err := os.Create("public.pem") if err!=nil{ panic(err) } defer publicFile.Close() //創(chuàng)建一個(gè)pem.Block結(jié)構(gòu)體對(duì)象 publicBlock:= pem.Block{Type: "RSA Public Key",Bytes:X509PublicKey} //保存到文件 pem.Encode(publicFile,&publicBlock) } //RSA加密 func RSA_Encrypt(plainText []byte,path string)[]byte{ //打開(kāi)文件 file,err:=os.Open(path) if err!=nil{ panic(err) } defer file.Close() //讀取文件的內(nèi)容 info, _ := file.Stat() buf:=make([]byte,info.Size()) file.Read(buf) //pem解碼 block, _ := pem.Decode(buf) //x509解碼 publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes) if err!=nil{ panic(err) } //類型斷言 publicKey:=publicKeyInterface.(*rsa.PublicKey) //對(duì)明文進(jìn)行加密 cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText) if err!=nil{ panic(err) } //返回密文 return cipherText } //RSA解密 func RSA_Decrypt(cipherText []byte,path string) []byte{ //打開(kāi)文件 file,err:=os.Open(path) if err!=nil{ panic(err) } defer file.Close() //獲取文件內(nèi)容 info, _ := file.Stat() buf:=make([]byte,info.Size()) file.Read(buf) //pem解碼 block, _ := pem.Decode(buf) //X509解碼 privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err!=nil{ panic(err) } //對(duì)密文進(jìn)行解密 plainText,_:=rsa.DecryptPKCS1v15(rand.Reader,privateKey,cipherText) //返回明文 return plainText }
測(cè)試代碼如下:
func main(){ //生成密鑰對(duì),保存到文件 GenerateRSAKey(2048) message:=[]byte("hello world") //加密 cipherText:=RSA_Encrypt(message,"public.pem") fmt.Println("加密后為:",string(cipherText)) //解密 plainText := RSA_Decrypt(cipherText, "private.pem") fmt.Println("解密后為:",string(plainText)) }
測(cè)試結(jié)果如下:
補(bǔ)充:golang中關(guān)于RSA加密、解密、簽名、驗(yàn)簽的總結(jié)
golang中關(guān)于RSA的加密、解密、簽名、驗(yàn)簽的使用主要在于使用x509及rsa package下相關(guān)的方法。
gocrypt是本人對(duì)一般常用的加/解密、簽名/驗(yàn)簽、hash的封裝庫(kù),歡迎大家使用。
以下總結(jié)相關(guān)的各種變化類型:
1.秘鑰、加密/簽名字符串加密的格式
目前主要見(jiàn)到有hex及base64
(1)hex
針對(duì)hex的加解密
hex.DecodeString(s string)//解密 hex.EncodeToString(src []byte) string//加密
(2)base64
base64.StdEncoding.DecodeString(s string) ([]byte, error)//解密 base64.StdEncoding.EncodeToString(src []byte) string//加密
2.私鑰的格式
解析私鑰的方式如下:
(1)PKCS1
x509.ParsePKCS1PrivateKey(der []byte) (key interface{}, err error)
(2)PKCS8
x509.ParsePKCS8PrivateKey(der []byte) (key interface{}, err error)
3.采用的數(shù)字簽名算法SHA
以下為RSA sign的不同說(shuō)明:
(1)SHA1
hash := sha1.New() hash.Write([]byte(originalData)) encryptedData, err := rsa.SignPKCS1v15(rand.Reader, prvKey, crypto.SHA1, hash.Sum(nil))
(2)SHA256
hash := sha256.New() hash.Write([]byte(originalData)) encryptedData, err := rsa.SignPKCS1v15(rand.Reader, prvKey, crypto.SHA256, hash.Sum(nil))
4.RSA使用類型
主要有加密/解密、簽名/驗(yàn)簽4種方式,且加密/解密與簽名/驗(yàn)簽均是一個(gè)相反的過(guò)程。兩對(duì)是根據(jù)對(duì)公鑰及私鑰的使用劃分的。
加密/解密是采用公鑰加密,私鑰解密。
簽名/驗(yàn)簽是采用私鑰簽名,公鑰驗(yàn)簽。
(1)加密
rsa.EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)
(2)解密
rsa.DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)
(3)簽名
rsa.SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)
(4)驗(yàn)簽
rsa.VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error
5.具體的使用示例
(1)加密:采用sha1算法加密后轉(zhuǎn)base64格式 func RsaEncryptWithSha1Base64(originalData,publicKey string)(string,error){ key, _ := base64.StdEncoding.DecodeString(publicKey) pubKey, _ := x509.ParsePKIXPublicKey(key) encryptedData,err:=rsa.EncryptPKCS1v15(rand.Reader, pubKey.(*rsa.PublicKey), []byte(originalData)) return base64.StdEncoding.EncodeToString(encryptedData),err } (2)解密:對(duì)采用sha1算法加密后轉(zhuǎn)base64格式的數(shù)據(jù)進(jìn)行解密(私鑰PKCS1格式) func RsaDecryptWithSha1Base64(encryptedData,privateKey string)(string,error){ encryptedDecodeBytes,err:=base64.StdEncoding.DecodeString(encryptedData) if err!=nil { return "",err } key,_:=base64.StdEncoding.DecodeString(privateKey) prvKey,_:=x509.ParsePKCS1PrivateKey(key) originalData,err:=rsa.DecryptPKCS1v15(rand.Reader,prvKey,encryptedDecodeBytes) return string(originalData),err } (3)簽名:采用sha1算法進(jìn)行簽名并輸出為hex格式(私鑰PKCS8格式) func RsaSignWithSha1Hex(data string, prvKey string) (string, error) { keyByts, err := hex.DecodeString(prvKey) if err != nil { fmt.Println(err) return "", err } privateKey, err := x509.ParsePKCS8PrivateKey(keyByts) if err != nil { fmt.Println("ParsePKCS8PrivateKey err", err) return "", err } h := sha1.New() h.Write([]byte([]byte(data))) hash := h.Sum(nil) signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey.(*rsa.PrivateKey), crypto.SHA1, hash[:]) if err != nil { fmt.Printf("Error from signing: %s\n", err) return "", err } out := hex.EncodeToString(signature) return out, nil } (4)驗(yàn)簽:對(duì)采用sha1算法進(jìn)行簽名后轉(zhuǎn)base64格式的數(shù)據(jù)進(jìn)行驗(yàn)簽 func RsaVerySignWithSha1Base64(originalData, signData, pubKey string) error{ sign, err := base64.StdEncoding.DecodeString(signData) if err != nil { return err } public, _ := base64.StdEncoding.DecodeString(pubKey) pub, err := x509.ParsePKIXPublicKey(public) if err != nil { return err } hash := sha1.New() hash.Write([]byte(originalData)) return rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA1, hash.Sum(nil), sign) }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏的解決方案詳解
這篇文章主要為大家詳細(xì)介紹了當(dāng)Golang因Channel未關(guān)閉導(dǎo)致內(nèi)存泄漏時(shí)蓋如何解決,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-07-07Go語(yǔ)言實(shí)現(xiàn)運(yùn)算符重載的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何利用Go語(yǔ)言實(shí)現(xiàn)運(yùn)算符重載的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-09-09Go語(yǔ)言繼承功能使用結(jié)構(gòu)體實(shí)現(xiàn)代碼重用
今天我來(lái)給大家介紹一下在?Go?語(yǔ)言中如何實(shí)現(xiàn)類似于繼承的功能,讓我們的代碼更加簡(jiǎn)潔和可重用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01golang 結(jié)構(gòu)體初始化時(shí)賦值格式介紹
這篇文章主要介紹了golang 結(jié)構(gòu)體初始化時(shí)賦值格式介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12