Skip to main content

go-rsa

golang rsa 签名算法

代码仓库地址-集成了多种加密方式方法和签名算法

package rsa

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/x509"
"encoding/pem"
"jihulab.com/rickyngu/gocrypto/errors"
"jihulab.com/rickyngu/gocrypto/util"
"os"
"runtime"
)

// 生成RSA密钥对
// keySize 密钥大小
// dirPath 密钥对文件路径
// 返回错误
func GenerateRsaKey(keySize int, dirPath string) error {
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
// x509
derText := x509.MarshalPKCS1PrivateKey(privateKey)
// pem Block
block := &pem.Block{
Type: "rsa private key",
Bytes: derText,
}
// just joint, caller must let dirPath right
file, err := os.Create(dirPath + "private.pem")
defer file.Close()
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
err = pem.Encode(file, block)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
// get PublicKey from privateKey
publicKey := privateKey.PublicKey
derStream, err := x509.MarshalPKIXPublicKey(&publicKey)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
block = &pem.Block{
Type: "rsa public key",
Bytes: derStream,
}
file, err = os.Create(dirPath + "public.pem")
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
err = pem.Encode(file, block)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
return nil
}

// Rsa加密
// plainText 明文
// filePath 公钥文件路径
// 返回加密后的结果 错误
func RsaEncrypt(plainText []byte, filePath string) ([]byte, error) {
// get pem.Block
block, err := util.GetKey(filePath)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
// X509
publicInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
publicKey, flag := publicInterface.(*rsa.PublicKey)
if flag == false {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, errors.RsatransError)
}
// encrypt
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
return cipherText, nil
}

// Rsa解密
// cipherText 密文
// filePath 私钥文件路径
// 返回解密后的结果 错误
func RsaDecrypt(cipherText []byte, filePath string) (plainText []byte, err error) {
// get pem.Block
block, err := util.GetKey(filePath)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
// get privateKey
privateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
// no need recover, you can add it when you call these function
//defer func() {
// if err2 := recover();err2 != nil{
// _, file, line, _ := runtime.Caller(0)
// err = util.Error(file,line,errors.RsaNilError)
// }
//}()
// get plainText use privateKey
plainText, err3 := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
if err3 != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err3.Error())
}
return plainText, err
}

// Rsa签名
// plainText 明文
// filePath 私钥文件路径
// 返回签名后的数据 错误
func RsaSign(plainText []byte, priFilePath string) ([]byte, error) {
// get pem.Block
block, err := util.GetKey(priFilePath)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
// calculate hash value
hashText := sha512.Sum512(plainText)
// Sign with hashText
signText, err := rsa.SignPKCS1v15(rand.Reader, priKey, crypto.SHA512, hashText[:])
if err != nil {
_, file, line, _ := runtime.Caller(0)
return nil, util.Error(file, line+1, err.Error())
}
return signText, nil
}

// Rsa签名验证
// plainText 明文
// filePath 公钥文件路径
// 返回签名后的数据 错误
func RsaVerify(plainText []byte, pubFilePath string, signText []byte) error {
// get pem.Block
block, err := util.GetKey(pubFilePath)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
// x509
pubInter, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
pubKey := pubInter.(*rsa.PublicKey)
// hashText to verify
hashText := sha512.Sum512(plainText)
err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA512, hashText[:], signText)
if err != nil {
_, file, line, _ := runtime.Caller(0)
return util.Error(file, line+1, err.Error())
}
return nil
}
==============================分割线(另一种)=========================================
package rsa

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

// bits 生成的公私钥对的位数,一般为 1024 或 2048
// privateKey 生成的私钥
// publicKey 生成的公钥
func GenRsaKey(bits int) (privateKey, publicKey string) {
priKey, err2 := rsa.GenerateKey(rand.Reader, bits)
if err2 != nil {
panic(err2)
}

derStream := x509.MarshalPKCS1PrivateKey(priKey)
block := &pem.Block{
Type: "PRIVATE KEY",
Bytes: derStream,
}
prvKey := pem.EncodeToMemory(block)
puKey := &priKey.PublicKey
derPkix, err := x509.MarshalPKIXPublicKey(puKey)
if err != nil {
panic(err)
}
block = &pem.Block{
Type: "PUBLIC KEY",
Bytes: derPkix,
}
pubKey := pem.EncodeToMemory(block)

privateKey = string(prvKey)
publicKey = string(pubKey)
return
}

// originalData 签名前的原始数据
// privateKey RSA 私钥
func SignBase64(originalData, privateKey string) (string, error) {
block, _ := pem.Decode([]byte(privateKey))
priKey, parseErr := x509.ParsePKCS8PrivateKey(block.Bytes)
if parseErr != nil {
fmt.Println(parseErr)
return "", errors.New("解析私钥失败")
}

// sha256 加密方式,必须与 下面的 crypto.SHA256 对应
// 例如使用 sha1 加密,此处应是 sha1.New(),对应 crypto.SHA1
hash := sha256.New()
hash.Write([]byte(originalData))
signature, err := rsa.SignPSS(rand.Reader, priKey.(*rsa.PrivateKey), crypto.SHA256, hash.Sum(nil), nil)

return base64.StdEncoding.EncodeToString(signature), err
}

// originalData 签名前的原始数据
// signData Base64 格式的签名串
// pubKey 公钥(需与加密时使用的私钥相对应)
// 返回 true 代表验签通过,反之为不通过
func VerySignWithBase64(originalData, signData, pubKey string) (bool, error) {
sign, err := base64.StdEncoding.DecodeString(signData)
if err != nil {
return false, err
}

block, _ := pem.Decode([]byte(pubKey))
pub, err1 := x509.ParsePKIXPublicKey(block.Bytes)
if err1 != nil {
return false, err1
}
// sha256 加密方式,必须与 下面的 crypto.SHA256 对应
// 例如使用 sha1 加密,此处应是 sha1.New(),对应 crypto.SHA1
hash := sha256.New()
hash.Write([]byte(originalData))
verifyErr := rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hash.Sum(nil), sign)
return verifyErr == nil, nil
}

测试代码

test code
package rsa

import (
"fmt"
"os"
"testing"
)

func TestRsa(t *testing.T) {
// 生成密钥对
err := GenerateRsaKey(1024, "./")
if err!=nil{
fmt.Println(err)
}
// 测试加密
plainText := []byte("hi, I'm lady_killer9")
cipherText,err := RsaEncrypt(plainText,"./public.pem")
if err!=nil{
fmt.Println(err)
}
fmt.Printf("加密后为:%s\n",cipherText)
// 测试解密
plainText,err = RsaDecrypt(cipherText,"./private.pem")
if err!=nil{
fmt.Println(err)
}
fmt.Printf("解密后为:%s\n",plainText)
}

func TestGenerateRsaKey(t *testing.T) {
// 测试keysize错误
err := GenerateRsaKey(10, "./")
if err!=nil{
fmt.Println(err)
}
// 测试目录错误
err = GenerateRsaKey(1024, ".//sc?")
if err!=nil{
fmt.Println(err)
}
}

func TestRsaEncrypt(t *testing.T) {
// 测试使用私钥加密
plainText := []byte("hi, I'm lady_killer9")
cipherText,err := RsaEncrypt(plainText,"./private.pem")
if err!=nil{
fmt.Println(err)
}
fmt.Printf("加密后为:%s\n",cipherText)
}

func TestRsaDecrypt(t *testing.T) {
plainText := []byte("hi, I'm lady_killer9")
cipherText,err := RsaEncrypt(plainText,"./public.pem")
if err!=nil{
fmt.Println(err)
}
// 测试使用公钥解密
plainText,err = RsaDecrypt(cipherText,"./public.pem") // 居然发现空指针异常
if err!=nil{
fmt.Println(err)
}
fmt.Printf("解密后为:%s\n",plainText)
}

func TestSignVerify(t *testing.T) {
plainText := []byte("张华考上了北京大学;李萍进了中等技术学校;我在百货公司当售货员:我们都有美好的未来")
signText,err := RsaSign(plainText,"./private.pem")
if err != nil{
fmt.Println(err)
os.Exit(0)
}
fmt.Printf("%s\n",signText)
err = RsaVerify(plainText,"./public.pem",signText)
if err != nil{
fmt.Println(err)
os.Exit(0)
}
fmt.Println("验证成功")
plainText = []byte("张华考上了北京大学;李萍进了中等技术学校;我在百货公司当售货员:我们都有美好的未来!")
err = RsaVerify(plainText,"./public.pem",signText)
if err != nil{
fmt.Println(err)
os.Exit(0)
}
}

func TestRsaSign(t *testing.T) {
// 测试公钥签名
plainText := []byte("张华考上了北京大学;李萍进了中等技术学校;我在百货公司当售货员:我们都有美好的未来")
signText,err := RsaSign(plainText,"./public.pem")
if err != nil{
fmt.Println(err)
os.Exit(0)
}
fmt.Printf("%s\n",signText)
}

func TestRsaVerify(t *testing.T) {
// 测试私钥验证
plainText := []byte("张华考上了北京大学;李萍进了中等技术学校;我在百货公司当售货员:我们都有美好的未来")
signText,err := RsaSign(plainText,"./private.pem")
if err != nil{
fmt.Println(err)
os.Exit(0)
}
fmt.Printf("%s\n",signText)
err = RsaVerify(plainText,"./private.pem",signText)
if err != nil{
fmt.Println(err)
os.Exit(0)
}
fmt.Println("验证成功")
plainText = []byte("张华考上了北京大学;李萍进了中等技术学校;我在百货公司当售货员:我们都有美好的未来!")
err = RsaVerify(plainText,"./public.pem",signText)
if err != nil{
fmt.Println(err)
os.Exit(0)
}
}