RSA算法讲解与Go语言实例

一、RSA算法概述

RSA是"非对称加密算法",非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公钥与私钥是配对的,用公钥加密的数据只有配对的私钥才能解密,反之亦然。因加解密使用两个不同的密钥,所以这种算法叫作非对称加密算法。
使用RSA加密算法流程如下:

1.消息接收方B先把公钥广播,消息发送方A保存B的公钥
2.当A需要向B发送消息时,先用B的公钥将消息进行加密,再将密文发送给A
3.A接受到密文以后,使用自己的私钥进行解密

RSA具有一个离散对数和椭圆曲线加密都没有的特性:
既可以用公钥加密然后私钥解密,也可以用私钥加密然后公钥解密(对称性)。

公钥加密然后私钥解密,可以用于通信中拥有公钥的一方向拥有私钥的另一方传递机密信息,不被第三方窃听。

那么私钥加密然后公钥解密是用在什么场合呢?就是数字签名。

二、数字签名

RSA中的每一个公钥都有唯一的私钥与之对应,任一公钥只能解开对应私钥加密的内容。换句话说,其它私钥加密的内容,这个公钥是解不开的。

如果你生成了一对RSA密钥,你把公钥公布出去,并告诉全世界人这个公钥是你的。之后你只要在发送的消息,比如“123456”,后面加上用私钥加密过的密文,其他人拿公钥解密,看解密得到的内容是是“123456”就可以知道这个“123456”是不是你发的。

签名:
  1、提取消息摘要,使用发送方私钥对消息摘要加密,生成消息签名。
  2、将消息签名和消息一起,使用接收方公钥加密,获得密文。

验签:
  1、使用接收方私钥对密文解密,获得消息和消息签名。
  2、使用发送方公钥解密消息签名,获得消息摘要。
  3、使用相同办法重新提取消息摘要,与上一步中消息摘要对比,如相同则验签成功。

三、Go语言使用RSA算法加解密实例

package main

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"os"
)

//生成密钥对(公钥和私钥)
func RsaGenKey(bits int) error{
	//通过随机数生成密钥对
	priveKey,err := rsa.GenerateKey(rand.Reader,bits)
	if err != nil {
		return err
	}
	//x509通用的证书格式:序列号,签名算法,颁发者,有效时间等
	//PKCS:由RSA实验室和开发商指定的标准
	priStream := x509.MarshalPKCS1PrivateKey(priveKey)
	block := pem.Block{
		Type:"RSA Private key",
		Bytes:priStream,
	}
	/*
	-------------------BEGIN RSA Private Key---------------------
	内容
	-------------------END RSA Private Key-----------------------
	 */

	 //创建存储私钥文件
	priveFile,err := os.Create("private.pem")
	defer priveFile.Close()
	if err != nil{
		return err
	}

	//将块编码到文件中
	err = pem.Encode(priveFile,&block)
	if err != nil{
		return err
	}

	//从公钥获取私钥
	pubKey := priveKey.PublicKey
	//通过x509标准达到rsa公钥序列化后的切片
	pubStream,err := x509.MarshalPKIXPublicKey(&pubKey)
	if err != nil{
		return err
	}

	//创建公钥块
	block = pem.Block{
		Type:"RSA Public Key",
		Bytes:pubStream,
	}

	pubFile,err := os.Create("public.pem")
	defer pubFile.Close()
	if err != nil{
		return err
	}

	//将公钥块编码到文件
	err = pem.Encode(pubFile,&block)
	if err!= nil{
		return err
	}

	return nil
}

//公钥加密函数
//src待加密的数据,pathName公钥路径
func RsaPublicEncrypt(src []byte,pathName string)([]byte,error){
	//打开公钥文件
	file,err := os.Open(pathName)
	defer file.Close()
	if err != nil{
		return []byte(""),err
	}

	//获取文件信息
	info,err := file.Stat()
	if err != nil{
		return []byte(""),err
	}

	//创建切片,用于存储文件中读取到的公钥信息
	recvBuf := make([]byte,info.Size())
	//读取公钥文件
	file.Read(recvBuf)
	//将得到的切片解码到块中
	block,_ := pem.Decode(recvBuf)
	//使用x509包中的ParsePKIXPublicKey解析公钥
	pubInter,err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil{
		return []byte(""),err
	}
	//通过断言将接口转换成公钥
	pubKey := pubInter.(*rsa.PublicKey)
	msg,err := rsa.EncryptPKCS1v15(rand.Reader,pubKey,src)
	if err != nil{
		return []byte(""),err
	}

	return msg,err
}

//使用私钥解密信息
//src:待解密的私钥信息  pathName:私钥路径
func RsaPrivateDecrypt(src []byte,pathName string)([]byte,error){
	//通过私钥文件路径打开私钥文件
	file,err := os.Open(pathName)
	defer file.Close()
	if err != nil{
		return []byte(""),err
	}

	info,err := file.Stat()
	if err != nil {
		return []byte(""), err
	}

	//创建切片用于接受私钥内容
	recvBuf := make([]byte,info.Size())
	//读取私钥文件
	file.Read(recvBuf)
	block,_ := pem.Decode(recvBuf)

	privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil{
		return []byte(""),err
	}

	msg,err := rsa.DecryptPKCS1v15(rand.Reader,privateKey,src)
	if err != nil{
		return []byte(""),err
	}

	return msg,nil
}

func main(){
	err := RsaGenKey(1024)
	if err != nil{
		fmt.Println("err=",err)
	}


	src := []byte("单枪匹马你别怕,一腔孤勇又如何!")

	data,err := RsaPublicEncrypt(src,"public.pem")
	if err != nil{
		fmt.Println("err:",err)
		return
	}

	fmt.Println("加密:",hex.EncodeToString(data))

	data,err = RsaPrivateDecrypt(data,"private.pem")
	if err != nil{
		fmt.Println("Decrypt err:",err)
		return
	}

	fmt.Println("解密:",string(data))
}

四、Go语言使用RSA算法实现数字签名认证

package main

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

//生成密钥对(公钥和私钥)
func RsaGenKey(bits int) error{
	//通过随机数生成密钥对
	priveKey,err := rsa.GenerateKey(rand.Reader,bits)
	if err != nil {
		return err
	}
	//x509通用的证书格式:序列号,签名算法,颁发者,有效时间等
	//PKCS:由RSA实验室和开发商指定的标准
	priStream := x509.MarshalPKCS1PrivateKey(priveKey)
	block := pem.Block{
		Type:"RSA Private key",
		Bytes:priStream,
	}
	/*
	-------------------BEGIN RSA Private Key---------------------
	内容
	-------------------END RSA Private Key-----------------------
	 */

	 //创建存储私钥文件
	priveFile,err := os.Create("private.pem")
	defer priveFile.Close()
	if err != nil{
		return err
	}

	//将块编码到文件中
	err = pem.Encode(priveFile,&block)
	if err != nil{
		return err
	}

	//从公钥获取私钥
	pubKey := priveKey.PublicKey
	//通过x509标准达到rsa公钥序列化后的切片
	pubStream,err := x509.MarshalPKIXPublicKey(&pubKey)
	if err != nil{
		return err
	}

	//创建公钥块
	block = pem.Block{
		Type:"RSA Public Key",
		Bytes:pubStream,
	}

	pubFile,err := os.Create("public.pem")
	defer pubFile.Close()
	if err != nil{
		return err
	}

	//将公钥块编码到文件
	err = pem.Encode(pubFile,&block)
	if err!= nil{
		return err
	}

	return nil
}

//公钥加密函数
//src待加密的数据,pathName公钥路径
func RsaPublicEncrypt(src []byte,pathName string)([]byte,error){
	//打开公钥文件
	file,err := os.Open(pathName)
	defer file.Close()
	if err != nil{
		return []byte(""),err
	}

	//获取文件信息
	info,err := file.Stat()
	if err != nil{
		return []byte(""),err
	}

	//创建切片,用于存储文件中读取到的公钥信息
	recvBuf := make([]byte,info.Size())
	//读取公钥文件
	file.Read(recvBuf)
	//将得到的切片解码到块中
	block,_ := pem.Decode(recvBuf)
	//使用x509包中的ParsePKIXPublicKey解析公钥
	pubInter,err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil{
		return []byte(""),err
	}
	//通过断言将接口转换成公钥
	pubKey := pubInter.(*rsa.PublicKey)
	msg,err := rsa.EncryptPKCS1v15(rand.Reader,pubKey,src)
	if err != nil{
		return []byte(""),err
	}

	return msg,err
}

//使用私钥解密信息
//src:待解密的私钥信息  pathName:私钥路径
func RsaPrivateDecrypt(src []byte,pathName string)([]byte,error){
	//通过私钥文件路径打开私钥文件
	file,err := os.Open(pathName)
	defer file.Close()
	if err != nil{
		return []byte(""),err
	}

	info,err := file.Stat()
	if err != nil {
		return []byte(""), err
	}

	//创建切片用于接受私钥内容
	recvBuf := make([]byte,info.Size())
	//读取私钥文件
	file.Read(recvBuf)
	block,_ := pem.Decode(recvBuf)

	privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil{
		return []byte(""),err
	}

	msg,err := rsa.DecryptPKCS1v15(rand.Reader,privateKey,src)
	if err != nil{
		return []byte(""),err
	}

	return msg,nil
}

//私钥签名
//data:消息内容
//pathName:私钥文件名
func RsaSign(data []byte,pathName string)([]byte,error){
	h := sha256.New()
	h.Write(data)

	hashed := h.Sum(nil)

	//获取私钥
	file,err := os.Open(pathName)
	defer file.Close()
	if err != nil{
		return []byte(""),err
	}

	info,err := file.Stat()
	if err != nil {
		return []byte(""), err
	}

	//创建切片用于接受私钥内容
	recvBuf := make([]byte,info.Size())
	//读取私钥文件
	file.Read(recvBuf)
	block,_ := pem.Decode(recvBuf)

	privateKey,err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil{
		return []byte(""),err
	}

	return rsa.SignPKCS1v15(rand.Reader,privateKey,crypto.SHA256,hashed)
}


//公钥验证
func RsaSignVer(data []byte,pathName string,signature []byte)error{
	//获取私钥
	file,err := os.Open(pathName)
	defer file.Close()
	if err != nil{
		return err
	}

	info,err := file.Stat()
	if err != nil {
		return err
	}

	//创建切片用于接受公钥内容
	recvBuf := make([]byte,info.Size())
	//读取公钥文件
	file.Read(recvBuf)

	hashed := sha256.Sum256(data)
	block,_ := pem.Decode(recvBuf)

	if block == nil{
		return errors.New("public key error")
	}

	// 解析公钥
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	// 类型断言
	pub := pubInterface.(*rsa.PublicKey)
	//验证签名
	return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed[:], signature)
}

func main(){
	err := RsaGenKey(1024)
	if err != nil{
		fmt.Println("err=",err)
	}


	msg := []byte("单枪匹马你别怕,一腔孤勇又如何!")

	fmt.Println("msg:",string(msg))

	sig,err := RsaSign(msg,"private.pem")
	if err !=nil{
		fmt.Println("RsaSign error:",err)
		return
	}

	fmt.Println("sig:",sig)

	if err := RsaSignVer(msg,"public.pem",sig);err != nil{
		fmt.Println("RsaSignVer error:",err)
		return
	}

	fmt.Println("签名验证成功")
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值