5

Go加密解密之RSA

 3 years ago
source link: http://blog.studygolang.com/2013/01/go%e5%8a%a0%e5%af%86%e8%a7%a3%e5%af%86%e4%b9%8brsa/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Go加密解密之RSA

Go加密解密之RSA

安全总是很重要的,各个语言对于通用的加密算法都会有实现。前段时间,用Go实现了RSA和DES的加密解密,在这分享一下。(对于RSA和DES加密算法本身,请查阅相关资料)

在PHP中,很多功能经常是一个函数解决;而Go中的却不是。本文会通过PHP加密,Go解密;Go加密,PHP解密来学习Go的RSA和DES相关的API。

该文讨论Go RSA加密解密。所有操作在linux下完成。

这是一个非对称加密算法,一般通过公钥加密,私钥解密。

在加解密过程中,使用openssl生产密钥。执行如下操作:

1)创建私钥
openssl genrsa -out private.pem 1024 //密钥长度,1024觉得不够安全的话可以用2048,但是代价也相应增大
2)创建公钥
openssl rsa -in private.pem -pubout -out public.pem

这样便生产了密钥。

一般地,各个语言也会提供API,用于生成密钥。在Go中,可以查看encoding/pem包和crypto/x509包。具体怎么产生,可查看《GO加密解密RSA番外篇:生成RSA密钥》

加密解密这块,涉及到很多标准,个人建议需要的时候临时学习一下。

二、Go RSA加密解密

1、rsa加解密,必然会去查crypto/ras这个包

Package rsa implements RSA encryption as specified in PKCS#1.

这是该包的说明:实现RSA加密技术,基于PKCS#1规范。

对于什么是PKCS#1,可以查阅相关资料。PKCS(公钥密码标准),而#1就是RSA的标准。可以查看:PKCS系列简介

从该包中函数的名称,可以看到有两对加解密的函数。

EncryptOAEP和DecryptOAEP
EncryptPKCS1v15和DecryptPKCS1v15

这称作加密方案,详细可以查看,PKCS #1 v2.1 RSA 算法标准

可见,当与其他语言交互时,需要确定好使用哪种方案。

PublicKey和PrivateKey两个类型分别代表公钥和私钥,关于这两个类型中成员该怎么设置,这涉及到RSA加密算法,本文中,这两个类型的实例通过解析文章开头生成的密钥得到。

2、解析密钥得到PublicKey和PrivateKey的实例

这个过程,我也是花了好些时间(主要对各种加密的各种东东不熟):怎么将openssl生成的密钥文件解析到公钥和私钥实例呢?

在encoding/pem包中,看到了—–BEGIN Type—–这样的字样,这正好和openssl生成的密钥形式差不多,那就试试。

在该包中,一个block代表的是PEM编码的结构,关于PEM,请查阅相关资料。我们要解析密钥,当然用Decode方法:

func Decode(data []byte) (p *Block, rest []byte)

这样便得到了一个Block的实例(指针)。

解析来看crypto/x509。为什么是x509呢?这又涉及到一堆概念。先不管这些,我也是看encoding和crypto这两个包的子包摸索出来的。
在x509包中,有一个函数:

func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)

从该函数的说明:ParsePKIXPublicKey parses a DER encoded public key. These values are typically found in PEM blocks with “BEGIN PUBLIC KEY”。可见这就是解析PublicKey的。另外,这里说到了PEM,可以上面的encoding/pem对了。(PKIX是啥东东,查看这里

而解析私钥的,有好几个方法,从上面的介绍,我们知道,RSA是PKCS#1,刚好有一个方法:

func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)

返回的就是rsa.PrivateKey。

3、解密解密实现

通过上面的介绍,Go中RSA的解密解密实现就不难了。代码如下:

1// 加密
2func RsaEncrypt(origData []byte) ([]byte, error) {
3block, _ := pem.Decode(publicKey)
4if block == nil {
5return nil, errors.New("public key error")
6}
7pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
8if err != nil {
9return nil, err
10}
11pub := pubInterface.(*rsa.PublicKey)
12return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
13}
14 
15// 解密
16func RsaDecrypt(ciphertext []byte) ([]byte, error) {
17block, _ := pem.Decode(privateKey)
18if block == nil {
19return nil, errors.New("private key error!")
20}
21priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
22if err != nil {
23return nil, err
24}
25return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
26}

其中,publicKey和privateKey是openssl生成的密钥,我生成的如下:

1// 公钥和私钥可以从文件中读取
2var privateKey = []byte(`
3-----BEGIN RSA PRIVATE KEY-----
4MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y
57m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7
6Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB
7AoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaM
8ZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1
9XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB
10/jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40
11IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG
124G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9
13DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI8
149KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrw
15DPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWO
16AQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O
17-----END RSA PRIVATE KEY-----
18`)
19 
20var publicKey = []byte(`
21-----BEGIN PUBLIC KEY-----
22MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmv
23ppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0Dgacd
24wYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NL
25AUeJ6PeW+DAkmJWF6QIDAQAB
26-----END PUBLIC KEY-----
27`)

4、使用例子

1package main
2 
3import (
4"fmt"
5)
6 
7func main() {
8data, err := RsaEncrypt([]byte("[email protected]"))
9if err != nil {
10panic(err)
11}
12origData, err := RsaDecrypt(data)
13if err != nil {
14panic(err)
15}
16fmt.Println(string(origData))
17}

该例子是加密完[email protected]后立马解密

三、跨语言加解密

语言内部正常,还得看看和其他语言是否一致,即:其他语言加密,Go语言得正确解密;Go语言加密,其他语言正确解密

1、PHP RSA加解密

这里,我选择PHP,使用的是openssl扩展。PHP中加解密很简单,如下两个方法(这里只考虑用公钥加密,私钥解密):

bool openssl_public_encrypt ( string $data , string &$crypted , mixed $key [, int $padding = OPENSSL_PKCS1_PADDING ] )
bool openssl_private_decrypt ( string $data , string &$decrypted , mixed $key [, int $padding = OPENSSL_PKCS1_PADDING ] )

最后一个参数是加密方案(补齐方式)。由于Go中使用的是PKCS1而不是OAEP,所以,使用默认值即可。

PHP代码如下:

1$privateKey = '-----BEGIN RSA PRIVATE KEY-----
2MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y
37m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7
4Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB
5AoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaM
6ZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1
7XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB
8/jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40
9IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG
104G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9
11DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI8
129KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrw
13DPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWO
14AQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O
15-----END RSA PRIVATE KEY-----';
16 
17$publicKey = '-----BEGIN PUBLIC KEY-----
18MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmv
19ppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0Dgacd
20wYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NL
21AUeJ6PeW+DAkmJWF6QIDAQAB
22-----END PUBLIC KEY-----';
23 
24function rsaEncrypt($data)
25{
26global $publicKey;
27openssl_public_encrypt($data, $crypted, $publicKey);
28return $crypted;
29}
30 
31function rsaDecrypt($data)
32{
33global $privateKey;
34openssl_private_decrypt($data, $decrypted, $privateKey);
35return $decrypted;
36}
37 
38function main()
39{
40$crypted = rsaEncrypt("[email protected]");
41$decrypted = rsaDecrypt($crypted);
42echo "encrypt and decrypt:" . $decrypted;
43}
44 
45main();

这里也是用PHP加解密[email protected]

2、Go和PHP一起工作

这里要注意的一点是,由于加密后是字节流,直接输出查看会乱码,因此,为了便于语言直接加解密,这里将加密之后的数据进行base64编码。

完整代码放在了github上
https://github.com/polaris1119/myblog_article_code/tree/master/rsa

示例中,php和Go版本都支持-d参数传入加密好的字符串,将其解密;不传时,会输出加密好并base64编码的串,可用于其他语言解密。

欢迎关注我的公众号:

polarisxu-qrcode-soso-s.png

好差啊挺差的一般般还行很赞 (4 人打了分, 平均分:4.00,总分:5)

12 thoughts on “Go加密解密之RSA”

  1. f79a3d300c76bf75b9d4e641f51996c9?s=50&d=mm&r=gTwitter25说道:

    Hi, just wanted to say i liked this article.

  2. 503c07368b6401f6cb92b0c51139b877?s=50&d=mm&r=ghikerell说道:

    最近也在研究go标准库,你的github上的·文档的确不错~有需要帮忙的话随时召唤,静候差遣~

  3. e19d9a8ab73dd032a277bc5c2bb9168c?s=50&d=mm&r=gagen ibcbet说道:

    After looking at a few of the blog articles on your website, I honestly appreciate
    your technique of writing a blog. I book marked it to my bookmark webpage list and will be checking back in the near future.
    Please check out my website too and let me know how you feel.

  4. My brother suggested I might like this blog. He used to
    be entirely right. This submit truly made my day. You can not believe simply how much time
    I had spent for this info! Thanks!

  5. ?s=50&d=mm&r=g匿名说道:

    RSA2有例子吗?

  6. ?s=50&d=mm&r=g匿名说道:

    这个不好使了吧

    1. c700a93cbc5d7d9f7118b8854c7675e8?s=50&d=mm&r=g徐新华说道:

      有什么问题?怎么不好使?

      1. ?s=50&d=mm&r=g匿名说道:

        php加密的结果base64后,用golang解不开

发表评论 取消回复

电子邮件地址不会被公开。

评论

姓名

电子邮件

站点

在此浏览器中保存我的名字、电邮和网站。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK