分享
  1. 首页
  2. 文章

Golang加密系列之RSA

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

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

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

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏