安全是软件开始中很重要的一个环节,在金融场景以及设计资产的场景下更是如此,在加密算法中主要使用较多加密方式分别是对称加密和非对称加密,对称加密中的代表是 AES,DES,3DES 等,非对称加密中使用比较多的是 RSA,ECC 等,最近火热的比特币中就使用ECC椭圆曲线算法,本篇文章主要是笔者在使用Golang在使用RSA中使用私钥加密公钥解密中遇到的问题,以及寻找的解决方案进行阐述,希望可以帮助到大家!

附上:

喵了个咪的博客:w-blog.cngorsa-Github地址:喵咪优化过的gorsa-Github地址: rsa

PS:特别感谢farmerx提供的gorsa实现

1.了解RSA

要了解RSA就要先分别对称加密和非对称加密的区别:

  • 对称加密中只有一个钥匙也就是KEY,加解密都依靠这组密钥
  • 非对称加密中有公私钥之分,私钥可以生产公钥(比特币的钱包地址就是公钥),一般加密通过公钥加密私钥解密(也有私钥加密公钥解密)

RSA使用场景:

  1. 我们最熟悉的就是HTTPS中就是使用的RSA加密,CA机构给你颁发的就是私钥给到我们进行配置,在请求过程中端用CA内置到系统的公钥加密,请求道服务器由服务器进行解密验证,保障了传输过程中的请求加密
  2. 高安全场景(比如金融设备银联交易等)下的双向认证(一机一密钥),每台机器本地都会生成一组公私钥对,并且吧公钥发送给服务器,这个使用发起的请求模型如下:
  • – – –
    服务器的公私钥对简称: spuk,spvk

端生成的公私钥对简称: cpuk,cpvk

服务器存储: spvk和cpuk

端存储 :spuk,cpvk

端使用cpvk加密请求 -> 服务器使用cpuk解密(验证端) -> 使用spvk加密返回结果返回 -> 端使用spuk解密获得返回结果(验证服务器)

这个过程中就完成了端认证服务器,服务器认证端称之为双向认证(这里是指简单的表达这个模型,更加安全的模式中会引入加密机进一步保障安全)

  • – – –

PS:关于RSA加密的具体算法实现可以参考以下两篇文章

2.GoRSA

在Golang使用 RSA加密算法 的时候笔者遇到了一个坑,在网上找遍了官方提供的库 crypto/rsa 中只有公钥加密私钥解密的实现,意味着无法实现私钥加密公钥解密,而要实现双向认证必须要使用 私钥加密公钥解密 ,通过几个小时的寻找其实有很多论坛中也在讨论这个问题,也有童鞋在GITHUB上面提及了一些解决方案,有用C封装了一次的等,但是使用其他特别难受甚至运行不起来,在快要绝望的时候找到了貌似可以使用的库,通过查看源码使用的是软实现,在这里推荐给大家

基于 进行封装优化了如下几点:

  • 优化公私钥需要提前注册初始化,在并发情况下公私钥匙会混乱的问题
  • 加密机没有进行base64处理,在跨程序传递或存储过程中都需要base64避免二次封装
  • 传入返回都统一使用string类型避免转换麻烦

获取扩展包:

 go get github.com/wenzhenxi/gorsa  

具体使用:

 package main

import (
    "log"
    "errors"
    "github.com/wenzhenxi/gorsa"
)

var Pubkey = `-----BEGIN 公钥-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+89V7vpOj1rG6bTAKYM
56qmFLwNCBVDJ3MltVVtxVUUByqc5b6u909MmmrLBqS//PWC6zc3wZzU1+ayh8xb
UAEZuA3EjlPHIaFIVIz04RaW10+1xnby/RQE23tDqsv9a2jv/axjE/27b62nzvCW
eItu1kNQ3MGdcuqKjke+LKhQ7nWPRCOd/ffVqSuRvG0YfUEkOz/6UpsPr6vrI331
hWRB4DlYy8qFUmDsyvvExe4NjZWblXCqkEXRRAhi2SQRCl3teGuIHtDUxCskRIDi
aMD+Qt2Yp+Vvbz6hUiqIWSIH1BoHJer/JOq2/O6X3cmuppU4AdVNgy8Bq236iXvr
MQIDAQAB
-----END 公钥-----
`

var Pirvatekey = `-----BEGIN 私钥-----
MIIEpAIBAAKCAQEAk+89V7vpOj1rG6bTAKYM56qmFLwNCBVDJ3MltVVtxVUUByqc
5b6u909MmmrLBqS//PWC6zc3wZzU1+ayh8xbUAEZuA3EjlPHIaFIVIz04RaW10+1
xnby/RQE23tDqsv9a2jv/axjE/27b62nzvCWeItu1kNQ3MGdcuqKjke+LKhQ7nWP
RCOd/ffVqSuRvG0YfUEkOz/6UpsPr6vrI331hWRB4DlYy8qFUmDsyvvExe4NjZWb
lXCqkEXRRAhi2SQRCl3teGuIHtDUxCskRIDiaMD+Qt2Yp+Vvbz6hUiqIWSIH1BoH
Jer/JOq2/O6X3cmuppU4AdVNgy8Bq236iXvrMQIDAQABAoIBAQCCbxZvHMfvCeg+
YUD5+W63dMcq0QPMdLLZPbWpxMEclH8sMm5UQ2SRueGY5UBNg0WkC/R64BzRIS6p
jkcrZQu95rp+heUgeM3C4SmdIwtmyzwEa8uiSY7Fhbkiq/Rly6aN5eB0kmJpZfa1
6S9kTszdTFNVp9TMUAo7IIE6IheT1x0WcX7aOWVqp9MDXBHV5T0Tvt8vFrPTldFg
IuK45t3tr83tDcx53uC8cL5Ui8leWQjPh4BgdhJ3/MGTDWg+LW2vlAb4x+aLcDJM
CH6Rcb1b8hs9iLTDkdVw9KirYQH5mbACXZyDEaqj1I2KamJIU2qDuTnKxNoc96HY
2XMuSndhAoGBAMPwJuPuZqioJfNyS99x++ZTcVVwGRAbEvTvh6jPSGA0k3cYKgWR
NnssMkHBzZa0p3/NmSwWc7LiL8whEFUDAp2ntvfPVJ19Xvm71gNUyCQ/hojqIAXy
tsNT1gBUTCMtFZmAkUsjqdM/hUnJMM9zH+w4lt5QM2y/YkCThoI65BVbAoGBAMFI
GsIbnJDNhVap7HfWcYmGOlWgEEEchG6Uq6Lbai9T8c7xMSFc6DQiNMmQUAlgDaMV
b6izPK4KGQaXMFt5h7hekZgkbxCKBd9xsLM72bWhM/nd/HkZdHQqrNAPFhY6/S8C
IjRnRfdhsjBIA8K73yiUCsQlHAauGfPzdHET8ktjAoGAQdxeZi1DapuirhMUN9Zr
kr8nkE1uz0AafiRpmC+cp2Hk05pWvapTAtIXTo0jWu38g3QLcYtWdqGa6WWPxNOP
NIkkcmXJjmqO2yjtRg9gevazdSAlhXpRPpTWkSPEt+o2oXNa40PomK54UhYDhyeu
akuXQsD4mCw4jXZJN0suUZMCgYAgzpBcKjulCH19fFI69RdIdJQqPIUFyEViT7Hi
bsPTTLham+3u78oqLzQukmRDcx5ddCIDzIicMfKVf8whertivAqSfHytnf/pMW8A
vUPy5G3iF5/nHj76CNRUbHsfQtv+wqnzoyPpHZgVQeQBhcoXJSm+qV3cdGjLU6OM
HgqeaQKBgQCnmL5SX7GSAeB0rSNugPp2GezAQj0H4OCc8kNrHK8RUvXIU9B2zKA2
z/QUKFb1gIGcKxYr+LqQ25/+TGvINjuf6P3fVkHL0U8jOG0IqpPJXO3Vl9B8ewWL
cFQVB/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扩展解决问题,欢迎大家收藏点赞!

注:笔者能力有限有说的不对的地方希望大家能够指出,也希望多多交流!