Golang加密系列之RSA

君子藏锋 · · 19963 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Golang加密系列的最后一篇,嗯,RSA涉及的概念太多,弄了好久才搞清楚。。。

代码的结构如下图

PS:StarUML这玩意在Mac上所有连到Interface的线都变成直线了...我很惆怅...


定义一个对外开放的接口

package rsa import "crypto" type Cipher interface {    Encrypt(plaintext []byte) ([]byte, error)    Decrypt(ciphertext []byte) ([]byte, error)    Sign(src []byte, hash crypto.Hash) ([]byte, error)    Verify(src []byte, sign []byte, hash crypto.Hash) error }

定义私有的pkcsClient ,实现Cipher接口, PKCS格式的私钥都使用这个client

package rsa import (    "crypto"    "crypto/rand"    "crypto/rsa" ) type pkcsClient struct {    privateKey *rsa.PrivateKey    publicKey  *rsa.PublicKey } func (this *pkcsClient) Encrypt(plaintext []byte) ([]byte, error) {    return rsa.EncryptPKCS1v15(rand.Reader, this.publicKey, plaintext) } func (this *pkcsClient) Decrypt(ciphertext []byte) ([]byte, error) {    return rsa.DecryptPKCS1v15(rand.Reader, this.privateKey, ciphertext) } func (this *pkcsClient) Sign(src []byte, hash crypto.Hash) ([]byte, error) {    h := hash.New()    h.Write(src)    hashed := h.Sum(nil)    return rsa.SignPKCS1v15(rand.Reader, this.privateKey, hash, hashed) } func (this *pkcsClient) Verify(src []byte, sign []byte, hash crypto.Hash) error {    h := hash.New()    h.Write(src)    hashed := h.Sum(nil)    return rsa.VerifyPKCS1v15(this.publicKey, hash, hashed, sign) }

将私钥类型定义成枚举类型

package privatekey type Type int64 const (    PKCS1 Type = iota    PKCS8 )

定义一个New/NewDefault函数,用于创建client

package rsa import (    "crypto/rsa"    "crypto/x509"    "encoding/pem"    "errors"    "toast/rsa/privatekey" ) //默认客户端,pkcs8私钥格式,pem编码 func NewDefault(privateKey, publicKey string) (Cipher, error) {    blockPri, _ := pem.Decode([]byte(privateKey))    if blockPri == nil {       return nil, errors.New("private key error")    }    blockPub, _ := pem.Decode([]byte(publicKey))    if blockPub == nil {       return nil, errors.New("public key error")    }    return New(blockPri.Bytes, blockPub.Bytes, privatekey.PKCS8) } func New(privateKey, publicKey []byte, privateKeyType privatekey.Type) (Cipher, error) {    priKey, err := genPriKey(privateKey, privateKeyType)    if err != nil {       return nil, err    }    pubKey, err := genPubKey(publicKey)    if err != nil {       return nil, err    }    return &pkcsClient{privateKey: priKey, publicKey: pubKey}, nil } func genPubKey(publicKey []byte) (*rsa.PublicKey, error) {    pub, err := x509.ParsePKIXPublicKey(publicKey)    if err != nil {       return nil, err    }    return pub.(*rsa.PublicKey), nil } func genPriKey(privateKey []byte, privateKeyType privatekey.Type) (*rsa.PrivateKey, error) {    var priKey *rsa.PrivateKey    var err error    switch privateKeyType {    case privatekey.PKCS1:       {          priKey, err = x509.ParsePKCS1PrivateKey([]byte(privateKey))          if err != nil {             return nil, err          }       }    case privatekey.PKCS8:       {          prkI, err := x509.ParsePKCS8PrivateKey([]byte(privateKey))          if err != nil {             return nil, err          }          priKey = prkI.(*rsa.PrivateKey)       }    default:       {          return nil, errors.New("unsupport private key type")       }    }    return priKey, nil }

最后,看看如何使用上面的代码来进行加密/解密,签名验签

package rsa_test import (    "crypto"    "encoding/base64"    "encoding/hex"    "fmt"    "testing"    "toast/rsa" ) var cipher rsa.Cipher func init() {    client, err := rsa.NewDefault(`-----BEGIN PRIVATE KEY----- 私钥信息 -----END PRIVATE KEY-----`, `-----BEGIN PUBLIC KEY----- 公钥信息 -----END PUBLIC KEY-----`)    if err != nil {       fmt.Println(err)    }    cipher = client } func Test_DefaultClient(t *testing.T) {    cp, err := cipher.Encrypt([]byte("测试加密解密"))    if err != nil {       t.Error(err)    }    cpStr := base64.URLEncoding.EncodeToString(cp)    fmt.Println(cpStr)    ppBy, err := base64.URLEncoding.DecodeString(cpStr)    if err != nil {       t.Error(err)    }    pp, err := cipher.Decrypt(ppBy)    fmt.Println(string(pp)) } func Test_Sign_DefaultClient(t *testing.T) {    src := "测试签名验签"    signBytes, err := cipher.Sign([]byte(src), crypto.SHA256)    if err != nil {       t.Error(err)    }    sign := hex.EncodeToString(signBytes)    fmt.Println(sign)    signB, err := hex.DecodeString(sign)    errV := cipher.Verify([]byte(src), signB, crypto.SHA256)    if errV != nil {       t.Error(errV)    }    fmt.Println("verify success") }

关于RSA相关的一些概念,参见我的另一篇博客.pem引发的血案

这里还有一个已经编写好的AES/RSA加解密的包,可以直接引用,github地址:https://github.com/89hmdys/toast


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:君子藏锋

查看原文:Golang加密系列之RSA

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

19963 次点击  ∙  3 赞  
加入收藏 微博
被以下专栏收入,发现更多相似内容
2 回复  |  直到 2017-11-06 09:22:51
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传