资讯专栏INFORMATION COLUMN

Golang 实现RSA 加密解密(附带php)

kun_jian / 3760人阅读

摘要:安全总是很重要的,各个语言对于通用的加密算法都会有实现。对于和加密算法本身,请查阅相关资料在中,很多功能经常是一个函数解决而中的却不是。该文讨论加密解密。一概要这是一个非对称加密算法,一般通过公钥加密,私钥解密。

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

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

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

一、概要

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

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

1)创建私钥:

</>复制代码

  1. openssl genrsa -out private.pem 1024 //密钥长度,1024觉得不够安全的话可以用2048,但是代价也相应增大

2)创建公钥:

</>复制代码

  1. openssl rsa -in private.pem -pubout -out public.pem

这样便生产了密钥。

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

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

二、Go RSA加密解密

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

</>复制代码

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

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

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

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

</>复制代码

  1. EncryptOAEP和DecryptOAEP
  2. EncryptPKCS1v15和DecryptPKCS1v15

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

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

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

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

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

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

</>复制代码

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

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

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

</>复制代码

  1. 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,刚好有一个方法:

</>复制代码

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

返回的就是rsa.PrivateKey。

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

// 加密

</>复制代码

  1. func RsaEncrypt(origData []byte) ([]byte, error) {
  2. block, _ := pem.Decode(publicKey)
  3. if block == nil {
  4. return nil, errors.New("public key error")
  5. }
  6. pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
  7. if err != nil {
  8. return nil, err
  9. }
  10. pub := pubInterface.(*rsa.PublicKey)
  11. return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
  12. }

// 解密

</>复制代码

  1. func RsaDecrypt(ciphertext []byte) ([]byte, error) {
  2. block, _ := pem.Decode(privateKey)
  3. if block == nil {
  4. return nil, errors.New("private key error!")
  5. }
  6. priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  7. if err != nil {
  8. return nil, err
  9. }
  10. return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
  11. }

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

// 公钥和私钥可以从文件中读取

</>复制代码

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

4、使用例子

</>复制代码

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

该例子是加密完git@github.com/mrkt后立马解密

三、跨语言加解密

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

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

</>复制代码

  1. 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-----
    MIICXQIBAAKBgQDZsfv1qscqYdy4vY+P4e3cAtmvppXQcRvrF1cB4drkv0haU24Y
    7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0DgacdwYWd/7PeCELyEipZJL07Vro7
    Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NLAUeJ6PeW+DAkmJWF6QIDAQAB
    AoGBAJlNxenTQj6OfCl9FMR2jlMJjtMrtQT9InQEE7m3m7bLHeC+MCJOhmNVBjaM
    ZpthDORdxIZ6oCuOf6Z2+Dl35lntGFh5J7S34UP2BWzF1IyyQfySCNexGNHKT1G1
    XKQtHmtc2gWWthEg+S6ciIyw2IGrrP2Rke81vYHExPrexf0hAkEA9Izb0MiYsMCB
    /jemLJB0Lb3Y/B8xjGjQFFBQT7bmwBVjvZWZVpnMnXi9sWGdgUpxsCuAIROXjZ40
    IRZ2C9EouwJBAOPjPvV8Sgw4vaseOqlJvSq/C/pIFx6RVznDGlc8bRg7SgTPpjHG
    4G+M3mVgpCX1a/EU1mB+fhiJ2LAZ/pTtY6sCQGaW9NwIWu3DRIVGCSMm0mYh/3X9
    DAcwLSJoctiODQ1Fq9rreDE5QfpJnaJdJfsIJNtX1F+L3YceeBXtW0Ynz2MCQBI8
    9KP274Is5FkWkUFNKnuKUK4WKOuEXEO+LpR+vIhs7k6WQ8nGDd4/mujoJBr5mkrw
    DPwqA3N5TMNDQVGv8gMCQQCaKGJgWYgvo3/milFfImbp+m7/Y3vCptarldXrYQWO
    AQjxwc71ZGBFDITYvdgJM1MTqc8xQek1FXn1vfpy2c6O
    -----END RSA PRIVATE KEY-----"; $publicKey = "-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZsfv1qscqYdy4vY+P4e3cAtmv
    ppXQcRvrF1cB4drkv0haU24Y7m5qYtT52Kr539RdbKKdLAM6s20lWy7+5C0Dgacd
    wYWd/7PeCELyEipZJL07Vro7Ate8Bfjya+wltGK9+XNUIHiumUKULW4KDx21+1NL
    AUeJ6PeW+DAkmJWF6QIDAQAB
    -----END PUBLIC KEY-----";

</>复制代码

  1. function rsaEncrypt($data)
  2. {
  3. global $publicKey;
  4. openssl_public_encrypt($data, $crypted, $publicKey);
  5. return $crypted;
  6. }
  7. function rsaDecrypt($data)
  8. {
  9. global $privateKey;
  10. openssl_private_decrypt($data, $decrypted, $privateKey);
  11. return $decrypted;
  12. }
  13. function main()
  14. {
  15. $crypted = rsaEncrypt("git@github.com/mrk");
  16. $decrypted = rsaDecrypt($crypted);
  17. echo "encrypt and decrypt:" . $decrypted;
  18. }

main();
这里也是用PHP加解密git@github.com/mrkt

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21836.html

相关文章

  • 永强教你加解密:对称篇(一)

    摘要:大家好,我是永强,就是老李之前经常给你们说的区块链大神大学肄业却依然大公司主程一波儿流只生活在老李口中尚未真实露面的骗钱高手老王的左膀右臂赵永强。 大家好,我是永强,就是老李之前经常给你们说的区块链大神、大学肄业却依然大公司iOS主程一波儿流、只生活在老李口中尚未真实露面的骗钱高手、老王的左膀右臂 ——— 赵永强。我和尼古拉斯赵四之间并没有什么强关联,我只是单方面认识他而已。 之前老李...

    opengps 评论0 收藏0
  • 利用RSA对前后端加密的探索

    摘要:项目地址前后端交互时为了保证信息安全可使用方式加密信息,在数据量大的时候可采用结合方式。由于加密和解密使用同样规则简称密钥,这被称为对称加密算法。从那时直到现在,算法一直是最广为使用的非对称加密算法。 RSA-JS-PHP 项目地址rsa-js-php 前后端交互时为了保证信息安全可使用RSA方式加密信息,在数据量大的时候可采用DES+RSA结合方式。DEMO演示地址 一点历史 1...

    banana_pi 评论0 收藏0
  • PHP服务端和APP客户端实现RSA+AES双向加密解密

    摘要:目的服务端和移动端双向加密解密共有七个文件其中包括三个类文件对称加密解密类服务端公钥私钥非对称加密解密类客户端公钥私钥非对称加密解密类四个过程文件其中文件中有注释和数据第一步客户端和服务端交换密钥明文第二步客户端发起带参数请求加密后第三 目的:服务端和移动端双向加密解密 共有七个文件 其中包括三个类文件 lib_aes.php aes对称加密解密类 server_rsa_crypt....

    ivydom 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<