Golang Rsa加解密【与C#、Golang、Python、Java(Android)、PHP互通】

golang中关于RSA的加密、解密、签名、验签的使用主要在于使用x509及rsa package下相关的方法。

1.秘钥、加密/签名字符串加密的格式

目前主要见到有hex及base64

(1)hex

针对hex的加解密

hex.DecodeString(s string)//解密
hex.EncodeToString(src []byte) string//加密

(2)base64

针对base64的加解密

base64.StdEncoding.DecodeString(s string) ([]byte, error)//解密
base64.StdEncoding.EncodeToString(src []byte) string//加密

2.私钥的格式

解析私钥的方式如下:

(1)PKCS1

x509.ParsePKCS1PrivateKey(der []byte) (key interface{}, err error)

(2)PKCS8

x509.ParsePKCS8PrivateKey(der []byte) (key interface{}, err error)

3.采用的数字签名算法SHA

SA sign主要有SHA1和SHA256

(1)SHA1

hash := sha1.New()
    hash.Write([]byte(originalData))
    encryptedData, err := rsa.SignPKCS1v15(rand.Reader, prvKey, crypto.SHA1, hash.Sum(nil))

(2)SHA256

hash := sha256.New()
    hash.Write([]byte(originalData))
    encryptedData, err := rsa.SignPKCS1v15(rand.Reader, prvKey, crypto.SHA256, hash.Sum(nil))

4.RSA使用类型

主要分为加密/解密、签名/验签4种方式,且加密/解密与签名/验签均是一个相反的过程。分别是根据对公钥及私钥的使用划分的。

[v_error]加密/解密是采用公钥加密,私钥解密。
签名/验签是采用私钥签名,公钥验签。[/v_error]

(1)加密

rsa.EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error)

(2)解密

rsa.DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error)

(3)签名

rsa.SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error)

(4)解签

rsa.VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error

5.具体实现Rsa加密、解密、签名、验签工具类的代码如下

//公钥加密私钥解密  私钥签名公钥验证
package sdrsa

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"errors"
)

type PriKeyType uint

const (
	PKCS1 PriKeyType = iota
	PKCS8
)

//私钥签名
func Sign(data, privateKey []byte, keyType PriKeyType) ([]byte, error) {
	h := sha256.New()
	h.Write(data)
	hashed := h.Sum(nil)
	priv, err := getPriKey(privateKey, keyType)
	if err != nil {
		return nil, err
	}
	return rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed)
}

//公钥验证
func SignVer(data, signature, publicKey []byte) error {
	hashed := sha256.Sum256(data)
	//获取公钥
	pub, err := getPubKey(publicKey)
	if err != nil {
		return err
	}
	//验证签名
	return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed[:], signature)
}

// 公钥加密
func Encrypt(data, publicKey []byte) ([]byte, error) {
	//获取公钥
	pub, err := getPubKey(publicKey)
	if err != nil {
		return nil, err
	}
	//加密
	return rsa.EncryptPKCS1v15(rand.Reader, pub, data)
}

// 私钥解密,privateKey为pem文件里的字符
func Decrypt(encData, privateKey []byte, keyType PriKeyType) ([]byte, error) {
	//解析PKCS1a或者PKCS8格式的私钥
	priv, err := getPriKey(privateKey, keyType)
	if err != nil {
		return nil, err
	}
	// 解密
	return rsa.DecryptPKCS1v15(rand.Reader, priv, encData)
}

func getPubKey(publicKey []byte) (*rsa.PublicKey, error) {
	//解密pem格式的公钥
	block, _ := pem.Decode(publicKey)
	if block == nil {
		return nil, errors.New("public key error")
	}
	// 解析公钥
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	// 类型断言
	if pub, ok := pubInterface.(*rsa.PublicKey); ok {
		return pub, nil
	} else {
		return nil, errors.New("public key error")
	}
}

func getPriKey(privateKey []byte, keyType PriKeyType) (*rsa.PrivateKey, error) {
	//获取私钥
	block, _ := pem.Decode(privateKey)
	if block == nil {
		return nil, errors.New("private key error!")
	}
	var priKey *rsa.PrivateKey
	var err error
	switch keyType {
	case PKCS1:
		{
			priKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
			if err != nil {
				return nil, err
			}
		}
	case PKCS8:
		{
			prkI, err := x509.ParsePKCS8PrivateKey(block.Bytes)
			if err != nil {
				return nil, err
			}
			priKey = prkI.(*rsa.PrivateKey)
		}
	default:
		{
			return nil, errors.New("unsupport private key type")
		}
	}
	return priKey, nil
}

6.附录:Rsa密钥对生成工具类

//生成公钥和私钥 pem文件

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/asn1"
	"encoding/pem"
	"flag"
	"log"
	"os"
)

func main() {
	var bits int
	flag.IntVar(&bits, "b", 1024, "秘钥长度,默认为1024")
	if err := GenRsaKey(bits); err != nil {
		log.Fatal("秘钥文件生成失败")
	}
	log.Println("秘钥文件生成成功")
}

//生成 PKCS1私钥、PKCS8私钥和公钥文件
func GenRsaKey(bits int) error {
	//生成私钥文件
	privateKey, err := rsa.GenerateKey(rand.Reader, bits)
	if err != nil {
		return err
	}
	derStream := x509.MarshalPKCS1PrivateKey(privateKey)
	block := &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: derStream,
	}
	file, err := os.Create("private_key.pem")
	if err != nil {
		return err
	}
	err = pem.Encode(file, block)
	if err != nil {
		return err
	}

	//生成PKCS8私钥
	pk8Stream := MarshalPKCS8PrivateKey(derStream)
	block = &pem.Block{
		Type:  "PRIVATE KEY",
		Bytes: pk8Stream,
	}
	file, err = os.Create("pkcs8_private_key.pem")
	if err != nil {
		return err
	}
	err = pem.Encode(file, block)
	if err != nil {
		return err
	}

	//生成公钥文件
	publicKey := &privateKey.PublicKey
	defPkix, err := x509.MarshalPKIXPublicKey(publicKey)
	if err != nil {
		return err
	}
	block = &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: defPkix,
	}
	file, err = os.Create("public_key.pem")
	if err != nil {
		return err
	}
	err = pem.Encode(file, block)
	if err != nil {
		return err
	}
	return nil
}

// 由私钥获取PKCS8公钥 这种方式生成的PKCS8与OpenSSL转成的不一样,但是BouncyCastle里可用
func MarshalPKCS8PrivateKey(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, err := asn1.Marshal(info)
	if err != nil {
		log.Panic(err.Error())
	}
	return k
}

// 由私钥获取PKCS8公钥
func MarshalPKCS8PrivateKey1(key *rsa.PrivateKey) []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 = x509.MarshalPKCS1PrivateKey(key)

	k, err := asn1.Marshal(info)
	if err != nil {
		log.Panic(err.Error())
	}
	return k
}

7.参考文章

https://blog.csdn.net/lhtzbj12/article/details/84799827
https://blog.csdn.net/xz_studying/article/details/80314111

8.相关阅读

golang对称加密实现—ASE算法(CBC,ECB,CFB)

 

RIPRO主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
荐书网 » Golang Rsa加解密【与C#、Golang、Python、Java(Android)、PHP互通】

发表评论

提供最优质的资源集合

立即查看 了解详情