安全是软件开始中很重要的一个环节,在金融场景以及设计资产的场景下更是如此,在加密算法中主要使用较多加密方式分别是对称加密和非对称加密,对称加密中的代表是AES,DES,3DES等,非对称加密中使用比较多的是RSA,ECC等,最近火热的比特币中就使用ECC椭圆曲线算法,本篇文章主要是笔者在使用Golang在使用RSA中使用私钥加密公钥解密中遇到的问题,以及寻找的解决方案进行阐述,希望可以帮助到大家!
附上:
喵了个咪的博客:
gorsa-Github地址:
喵咪优化过的gorsa-Github地址:
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加密的具体算法实现可以参考以下两篇文章
2.GoRSA
在Golang使用RSA加密算法的时候笔者遇到了一个坑,在网上找遍了官方提供的库crypto/rsa中只有公钥加密私钥解密的实现,意味着无法实现私钥加密公钥解密,而要实现双向认证必须要使用私钥加密公钥解密,通过几个小时的寻找其实有很多论坛中也在讨论这个问题,也有童鞋在GITHUB上面提及了一些解决方案,有用C封装了一次的等,但是使用其他特别难受甚至运行不起来,在快要绝望的时候找到了貌似可以使用的库,通过查看源码使用的是软实现,在这里推荐给大家
基于 进行封装优化了如下几点:
- 优化公私钥需要提前注册初始化,在并发情况下公私钥匙会混乱的问题
- 加密机没有进行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扩展解决问题,欢迎大家收藏点赞!
注:笔者能力有限有说的不对的地方希望大家能够指出,也希望多多交流!