非对称加密 RSA
- 优点
与对称加密相比,安全性更好,加解密需要不同的密钥,公钥和私钥都可进行相互的加解密。
- 缺点
加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
- 应用场景
适合于对安全性要求很高的场景,适合加密少量数据,比如支付数据、登录数据等。
package helpers
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/asn1"
"encoding/pem"
"strings"
)
type Rsa struct {
privateKey string
publicKey string
rsaPrivateKey *rsa.PrivateKey
rsaPublicKey *rsa.PublicKey
}
func NewRsa(publicKey, privateKey string) *Rsa {
rsaObj := &Rsa{
privateKey: privateKey,
publicKey: publicKey,
}
rsaObj.init() //初始化,如果存在公钥私钥,将其解析
return rsaObj
}
//初始化
func (r *Rsa) init() {
if r.privateKey != "" {
//将私钥解码
block, _ := pem.Decode([]byte(r.privateKey))
//pkcs1 //判断是否包含 BEGIN RSA 字符串,这个是由下面生成的时候定义的
if strings.Index(r.privateKey, "BEGIN RSA") > 0 {
//解析私钥
r.rsaPrivateKey, _ = x509.ParsePKCS1PrivateKey(block.Bytes)
} else { //pkcs8
//解析私钥
privateKey, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
//转换格式 类型断言
r.rsaPrivateKey = privateKey.(*rsa.PrivateKey)
}
}
if r.publicKey != "" {
//将公钥解码 解析 转换格式
block, _ := pem.Decode([]byte(r.publicKey))
publicKey, _ := x509.ParsePKIXPublicKey(block.Bytes)
r.rsaPublicKey = publicKey.(*rsa.PublicKey)
}
}
//Encrypt 加密
func (r *Rsa) Encrypt(data []byte) ([]byte, error) {
// blockLength = 密钥长度 = 一次能加密的明文长度
// "/8" 将bit转为bytes
// "-11" 为 PKCS#1 建议的 padding 占用了 11 个字节
blockLength := r.rsaPublicKey.N.BitLen()/8 - 11
//如果明文长度不大于密钥长度,可以直接加密
if len(data) <= blockLength {
//对明文进行加密
return rsa.EncryptPKCS1v15(rand.Reader, r.rsaPublicKey, []byte(data))
}
//否则分段加密
//创建一个新的缓冲区
buffer := bytes.NewBufferString("")
pages := len(data) / blockLength //切分为多少块
//循环加密
for i := 0; i <= pages; i++ {
start := i * blockLength
end := (i + 1) * blockLength
if i == pages {//最后一页的判断
if start == len(data) {
continue
}
end = len(data)
}
//分段加密
chunk, err := rsa.EncryptPKCS1v15(rand.Reader, r.rsaPublicKey, data[start:end])
if err != nil {
return nil, err
}
//写入缓冲区
buffer.Write(chunk)
}
//读取缓冲区内容并返回,即返回加密结果
return buffer.Bytes(), nil
}
//Decrypt 解密
func (r *Rsa) Decrypt(data []byte) ([]byte, error) {
//加密后的密文长度=密钥长度。如果密文长度大于密钥长度,说明密文非一次加密形成
//1、获取密钥长度
blockLength := r.rsaPublicKey.N.BitLen() / 8
if len(data) <= blockLength {//一次形成的密文直接解密
return rsa.DecryptPKCS1v15(rand.Reader, r.rsaPrivateKey, data)
}
buffer := bytes.NewBufferString("")
pages := len(data) / blockLength
for i := 0; i <= pages; i++ {//循环解密
start := i * blockLength
end := (i + 1) * blockLength
if i == pages {
if start == len(data) {
continue
}
end = len(data)
}
chunk, err := rsa.DecryptPKCS1v15(rand.Reader, r.rsaPrivateKey, data[start:end])
if err != nil {
return nil, err
}
buffer.Write(chunk)
}
return buffer.Bytes(), nil
}
//Sign 签名
func (r *Rsa) Sign(data []byte, sHash crypto.Hash) ([]byte, error) {
hash := sHash.New()
hash.Write(data)
sign, err := rsa.SignPKCS1v15(rand.Reader, r.rsaPrivateKey, sHash, hash.Sum(nil))
if err != nil {
return nil, err
}
return sign, nil
}
//Verify 验签
func (r *Rsa) Verify(data []byte, sign []byte, sHash crypto.Hash) bool {
h := sHash.New()
h.Write(data)
return rsa.VerifyPKCS1v15(r.rsaPublicKey, sHash, h.Sum(nil), sign) == nil
}
//CreateKeys 生成pkcs1 格式的公钥私钥
func (r *Rsa) CreateKeys(keyLength int) (privateKey, publicKey string) {
//根据 随机源 与 指定位数,生成密钥对。rand.Reader = 密码强大的伪随机生成器的全球共享实例
rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return
}
//编码私钥
privateKey = string(pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",//自定义类型
Bytes: x509.MarshalPKCS1PrivateKey(rsaPrivateKey),
}))
//编码公钥
objPkix, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
if err != nil {
return
}
publicKey = string(pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: objPkix,
}))
return
}
//CreatePkcs8Keys 生成pkcs8 格式公钥私钥
func (r *Rsa) CreatePkcs8Keys(keyLength int) (privateKey, publicKey string) {
rsaPrivateKey, err := rsa.GenerateKey(rand.Reader, keyLength)
if err != nil {
return
}
//两种方式
//一:1、生成pkcs1格式的密钥 2、将其转化为pkcs8格式的密钥(使用自定义方法)
// objPkcs1 := x509.MarshalPKCS1PrivateKey(rsaPrivateKey)
// objPkcs8 := r.Pkcs1ToPkcs8(objPkcs1)
//二:直接使用 x509 包 MarshalPKCS8PrivateKey 生成pkcs8密钥
objPkcs8,_ := x509.MarshalPKCS8PrivateKey(rsaPrivateKey)
//fmt.Println("对比两种结果",strings.Compare(string(objPkcs8),string(rr)))
privateKey = string(pem.EncodeToMemory(&pem.Block{
Type: "PRIVATE KEY",
Bytes: objPkcs8,
}))
objPkix, err := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)
if err != nil {
return
}
publicKey = string(pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: objPkix,
}))
return
}
//Pkcs1ToPkcs8 将pkcs1 转到 pkcs8 自定义
func (r *Rsa) Pkcs1ToPkcs8(key []byte) []byte {
info := struct {
Version int
PrivateKeyAlgorithm []asn1.ObjectIdentifier
PrivateKey []byte
}{}
info.Version = 0
info.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
info.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
info.PrivateKey = key
k, _ := asn1.Marshal(info)
return k
}
使用
func testRsa() {
content := strings.Repeat("H", 245)+"q"
//生成 公钥 私钥
privateKey, publicKey := helpers.NewRsa("", "").CreatePkcs8Keys(2048)
//privateKey, publicKey := helpers.NewRsa("", "").CreateKeys(1024)
fmt.Printf("公钥:%v \n 私钥: %v \n", publicKey, privateKey)
rsaObj := helpers.NewRsa(publicKey, privateKey)
//加密
sData, err := rsaObj.Encrypt(data)
if err != nil {
fmt.Println("加密失败:", err)
}
//解密
pData, err := rsaObj.Decrypt(sData)
if err != nil {
fmt.Println("解密失败:", err)
}
//签名
sign, _ := rsaObj.Sign(data, crypto.SHA256)
//验签
verify := rsaObj.Verify(data, sign, crypto.SHA256)
fmt.Printf(" 加密:%v\n 解密:%v\n 签名:%v\n 验签结果:%v\n",
hex.EncodeToString(sData),
string(pData),
hex.EncodeToString(sign),
verify,
)
}