這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
安全是軟體開始中很重要的一個環節,在金融情境以及設計資產的情境下更是如此,在密碼編譯演算法中主要使用較多加密方式分別是對稱式加密和非對稱式加密,對稱式加密中的代表是AES,DES,3DES等,非對稱式加密中使用比較多的是RSA,ECC等,最近火熱的比特幣中就使用ECC橢圓曲線演算法,本篇文章主要是筆者在使用Golang在使用RSA中使用私密金鑰加密公開金鑰解密中遇到的問題,以及尋找的解決方案進行闡述,希望可以協助到大家!
附上:
喵了個咪的部落格:w-blog.cngorsa-Github地址:https://github.com/farmerx/gorsa喵咪最佳化過的gorsa-Github地址:https://github.com/wenzhenxi/gorsa
PS:特別感謝farmerx提供的gorsa實現
1.瞭解RSA
要瞭解RSA就要先分別對稱式加密和非對稱式加密的區別:
- 對稱式加密中只有一個鑰匙也就是KEY,加解密都依靠這組密鑰
- 非對稱式加密中有公私密金鑰之分,私密金鑰可以生產公開金鑰(比特幣的錢包地址就是公開金鑰),一般加密通過公開金鑰加密私密金鑰解密(也有私密金鑰加密公開金鑰解密)
RSA使用情境:
我們最熟悉的就是HTTPS中就是使用的RSA加密,CA機構給你頒發的就是私密金鑰給到我們進行配置,在請求過程中端用CA內建到系統的公開金鑰加密,請求道伺服器由伺服器進行解密驗證,保障了傳輸過程中的請求加密
高安全情境(比如金融裝置銀聯交易等)下的雙向認證(一機一密鑰),每台機器本地都會產生一組公私密金鑰對,並且吧公開金鑰發送給伺服器,這個使用發起的請求模型如下:
伺服器的公私密金鑰對簡稱: s_puk,s_pvk
端產生的公私密金鑰對簡稱: c_puk,c_pvk
伺服器儲存: s_pvk和c_puk
端儲存 :s_puk,c_pvk
端使用c_pvk加密請求 -> 伺服器使用c_puk解密(驗證端) -> 使用s_pvk加密返回結果返回 -> 端使用s_puk解密獲得返回結果(驗證伺服器)
這個過程中就完成了端證明伺服器,伺服器認證端稱之為雙向認證(這裡是指簡單的表達這個模型,更加安全的模式中會引入加密機進一步保障安全)
PS:關於RSA加密的具體演算法實現可以參考以下兩篇文章
RSA演算法原理(一)
RSA演算法原理(二)
2.GoRSA
在Golang使用RSA密碼編譯演算法的時候筆者遇到了一個坑,在網上找遍了官方提供的庫crypto/rsa中只有公開金鑰加密私密金鑰解密的實現,意味著無法實現私密金鑰加密公開金鑰解密,而要實現雙向認證必須要使用私密金鑰加密公開金鑰解密,通過幾個小時的尋找其實有很多論壇中也在討論這個問題,也有童鞋在GITHUB上面提及了一些解決方案,有用C封裝了一次的等,但是使用其他特別難受甚至運行不起來,在快要絕望的時候找到了貌似可以使用的庫,通過查看源碼使用的是軟實現,在這裡推薦給大家
基於 https://github.com/farmerx/gorsa 進行封裝最佳化了如下幾點:
- 最佳化公私密金鑰需要提前註冊初始化,在並發情況下公私密金鑰匙會混亂的問題
- 加密機沒有進行base64處理,在跨程式傳遞或預存程序中都需要base64避免二次封裝
- 傳入返回都統一使用string類型避免轉換麻煩
擷取擴充包:
go get github.com/wenzhenxi/gorsa
具體使用:
package mainimport ("log""errors""github.com/wenzhenxi/gorsa")var Pubkey = `-----BEGIN 公開金鑰-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+89V7vpOj1rG6bTAKYM56qmFLwNCBVDJ3MltVVtxVUUByqc5b6u909MmmrLBqS//PWC6zc3wZzU1+ayh8xbUAEZuA3EjlPHIaFIVIz04RaW10+1xnby/RQE23tDqsv9a2jv/axjE/27b62nzvCWeItu1kNQ3MGdcuqKjke+LKhQ7nWPRCOd/ffVqSuRvG0YfUEkOz/6UpsPr6vrI331hWRB4DlYy8qFUmDsyvvExe4NjZWblXCqkEXRRAhi2SQRCl3teGuIHtDUxCskRIDiaMD+Qt2Yp+Vvbz6hUiqIWSIH1BoHJer/JOq2/O6X3cmuppU4AdVNgy8Bq236iXvrMQIDAQAB-----END 公開金鑰-----`var Pirvatekey = `-----BEGIN 私密金鑰-----MIIEpAIBAAKCAQEAk+89V7vpOj1rG6bTAKYM56qmFLwNCBVDJ3MltVVtxVUUByqc5b6u909MmmrLBqS//PWC6zc3wZzU1+ayh8xbUAEZuA3EjlPHIaFIVIz04RaW10+1xnby/RQE23tDqsv9a2jv/axjE/27b62nzvCWeItu1kNQ3MGdcuqKjke+LKhQ7nWPRCOd/ffVqSuRvG0YfUEkOz/6UpsPr6vrI331hWRB4DlYy8qFUmDsyvvExe4NjZWblXCqkEXRRAhi2SQRCl3teGuIHtDUxCskRIDiaMD+Qt2Yp+Vvbz6hUiqIWSIH1BoHJer/JOq2/O6X3cmuppU4AdVNgy8Bq236iXvrMQIDAQABAoIBAQCCbxZvHMfvCeg+YUD5+W63dMcq0QPMdLLZPbWpxMEclH8sMm5UQ2SRueGY5UBNg0WkC/R64BzRIS6pjkcrZQu95rp+heUgeM3C4SmdIwtmyzwEa8uiSY7Fhbkiq/Rly6aN5eB0kmJpZfa16S9kTszdTFNVp9TMUAo7IIE6IheT1x0WcX7aOWVqp9MDXBHV5T0Tvt8vFrPTldFgIuK45t3tr83tDcx53uC8cL5Ui8leWQjPh4BgdhJ3/MGTDWg+LW2vlAb4x+aLcDJMCH6Rcb1b8hs9iLTDkdVw9KirYQH5mbACXZyDEaqj1I2KamJIU2qDuTnKxNoc96HY2XMuSndhAoGBAMPwJuPuZqioJfNyS99x++ZTcVVwGRAbEvTvh6jPSGA0k3cYKgWRNnssMkHBzZa0p3/NmSwWc7LiL8whEFUDAp2ntvfPVJ19Xvm71gNUyCQ/hojqIAXytsNT1gBUTCMtFZmAkUsjqdM/hUnJMM9zH+w4lt5QM2y/YkCThoI65BVbAoGBAMFIGsIbnJDNhVap7HfWcYmGOlWgEEEchG6Uq6Lbai9T8c7xMSFc6DQiNMmQUAlgDaMVb6izPK4KGQaXMFt5h7hekZgkbxCKBd9xsLM72bWhM/nd/HkZdHQqrNAPFhY6/S8CIjRnRfdhsjBIA8K73yiUCsQlHAauGfPzdHET8ktjAoGAQdxeZi1DapuirhMUN9Zrkr8nkE1uz0AafiRpmC+cp2Hk05pWvapTAtIXTo0jWu38g3QLcYtWdqGa6WWPxNOPNIkkcmXJjmqO2yjtRg9gevazdSAlhXpRPpTWkSPEt+o2oXNa40PomK54UhYDhyeuakuXQsD4mCw4jXZJN0suUZMCgYAgzpBcKjulCH19fFI69RdIdJQqPIUFyEViT7HibsPTTLham+3u78oqLzQukmRDcx5ddCIDzIicMfKVf8whertivAqSfHytnf/pMW8AvUPy5G3iF5/nHj76CNRUbHsfQtv+wqnzoyPpHZgVQeQBhcoXJSm+qV3cdGjLU6OMHgqeaQKBgQCnmL5SX7GSAeB0rSNugPp2GezAQj0H4OCc8kNrHK8RUvXIU9B2zKA2z/QUKFb1gIGcKxYr+LqQ25/+TGvINjuf6P3fVkHL0U8jOG0IqpPJXO3Vl9B8ewWLcFQVB/nQfmaMa4ChK0QEUe+Mqi++MwgYbRHx1lIOXEfUJO+PXrMekw==-----END 私密金鑰-----`func main() {// 公開金鑰加密私密金鑰解密if err := applyPubEPriD(); err != nil {log.Println(err)}// 公開金鑰解密私密金鑰加密if err := applyPriEPubD(); err != nil {log.Println(err)}}// 公開金鑰加密私密金鑰解密func applyPubEPriD() error {pubenctypt, err := gorsa.PublicEncrypt(`hello world`,Pubkey)if err != nil {return err}pridecrypt, err := gorsa.PriKeyDecrypt(pubenctypt,Pirvatekey)if err != nil {return err}if string(pridecrypt) != `hello world` {return errors.New(`解密失敗`)}return nil}// 公開金鑰解密私密金鑰加密func applyPriEPubD() error {prienctypt, err := gorsa.PriKeyEncrypt(`hello world`,Pirvatekey)if err != nil {return err}pubdecrypt, err := gorsa.PublicDecrypt(prienctypt,Pubkey)if err != nil {return err}if string(pubdecrypt) != `hello world` {return errors.New(`解密失敗`)}return nil}
3 總結
RSA在軟體開發中運用廣泛,如果大家也遇到了Golang私密金鑰加密公開金鑰解密問題,歡迎大家使用gorsa擴充解決問題,歡迎大家收藏點贊!
注:筆者能力有限有說的不對的地方希望大家能夠指出,也希望多多交流!