go语言实现非对称加密——RSA加密解密的实现

版权声明:本文为作者原创,如需转载,请注明出处
https://blog.csdn.net/weixin_42940826


非对称加密简介

什么是非对称加密
非对称加密,顾名思义,是相对于对称加密的一种加密方法,对称加密是指加密与解密使用的是同一把秘钥,而非对称加密有两把不同的秘钥,一个称之为公钥,另一个称之为私钥,使用公钥加密,私钥可以解密。或者使用私钥加密,公钥可以解密。大多数情况下,公钥可以公开,但是私钥只能自行持有,不可泄露。
常用的非对称密码算法有RSA、ECC椭圆形加密这两种。
本文亦将用go语言具体实现RSA的加密解密,关于椭圆形曲线加密,将在我的另一篇博文中作详细介绍。

为什么需要非对称加密
非对称加密可以说是密码学史上最伟大的发明之一,因为它解决了对称加密的秘钥配送问题,举个例子,A和B进行通信,A使用秘钥为123456,那么B如何知道秘钥为123456进行解密呢,如果直接发送,很容易被黑客抓取到,除了私底下交换秘钥,似乎没有更好的方法了。
但是非对称加密的出现解决了这一弊端,举个例子,还是A和B进行通信,A要给B发送信息,B把自己的公钥发送给A,然后A使用B的公钥对信息进行加密 发送给B,由于此信息使用的B的公钥进行加密,所以只有使用B的私钥才能解密,因此即使黑客知道B的公钥,也是没有任何办法的。

应用场景
信息加密,登陆认证,数字签名,数字证书等等,如今红极一时的区块链技术也是使用了非对称加密,还有包括网银U盾、二代居民身份证本质上也是使用了非对称加密。
关于数字签名将在我的另一篇博文中作详细介绍。


RSA加密解密流程一览

生成私钥流程

  1. 使用rsa中的GenerateKey方法生成私钥

    func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error)

    • rand.Reader ->随机数生成器
    • bits ->建议1024的整数倍
  2. 通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串

    func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte

  3. 将私钥字符串设置到pem格式块中

    初始化一个pem.Block块

    type Block struct {
       Type    string            // 得自前言的类型(如"RSA PRIVATE KEY")
       Headers map[string]string // 可选的头项
       Bytes   []byte            // 内容解码后的数据,一般是DER编码的ASN.1结构
    }
    
  4. 通过pem将设置好的数据进行编码, 并写入磁盘文件中

    func Encode(out io.Writer, b *Block) error

    • out - 准备一个文件指针
    • block- 将准备好的pem.block放入其中

生成公钥流程

  1. 从得到的私钥对象中将公钥信息取出

    type PrivateKey struct {
        PublicKey            // 公钥
        D         *big.Int   // 私有的指数
        Primes    []*big.Int // N的素因子,至少有两个
        // 包含预先计算好的值,可在某些情况下加速私钥的操作
        Precomputed PrecomputedValues
    }
    
  2. 通过x509标准将得到 的rsa公钥序列化为字符串

    func MarshalPKIXPublicKey(pub interface{}) ([]byte, error)
    
  3. 将公钥字符串设置到pem格式块中

    type Block struct {
        Type    string            // 得自前言的类型(如"RSA PRIVATE KEY")
        Headers map[string]string // 可选的头项
        Bytes   []byte            // 内容解码后的数据,一般是DER编码的ASN.1结	}
    
  4. 通过pem将设置好的数据进行编码, 并写入磁盘文件

    func Encode(out io.Writer, b *Block) error

RSA加密流程

  1. 将公钥文件中的公钥读出, 得到使用pem编码的字符串

    – 读文件

  2. 将得到的字符串pem解码

    – pem.Decode

  3. 使用x509将编码之后的公钥解析出来

    – func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error)

  4. 使用得到的公钥通过rsa进行数据加密

RSA解密流程

  1. 将私钥文件中的私钥读出, 得到使用pem编码的字符串
  2. 将得到的字符串pem解码
  3. 使用x509将编码之后的私钥解析出来
  4. 使用得到的私钥通过rsa进行数据解密

代码实现

package main

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

func Getkeys(){
	//得到私钥
	privateKey,_:=rsa.GenerateKey(rand.Reader,2048)
	//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
	x509_Privatekey:=x509.MarshalPKCS1PrivateKey(privateKey)
	//创建一个用来保存私钥的以.pem结尾的文件
	fp,_:=os.Create("csdn_private.pem")
	defer fp.Close()
	//将私钥字符串设置到pem格式块中
	pem_block:=pem.Block{
		Type:"csdn_privateKey",
		Bytes:x509_Privatekey,
	}
	//转码为pem并输出到文件中
	pem.Encode(fp,&pem_block)

	//处理公钥,公钥包含在私钥中
	publickKey:=privateKey.PublicKey
	//接下来的处理方法同私钥
	//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
	x509_PublicKey,_:=x509.MarshalPKIXPublicKey(&publickKey)
	pem_PublickKey:=pem.Block{
		Type:"csdn_PublicKey",
		Bytes:x509_PublicKey,
	}
	file,_:=os.Create("csdn_PublicKey.pem")
	defer file.Close()
	//转码为pem并输出到文件中
	pem.Encode(file,&pem_PublickKey)

}

//使用公钥进行加密
func RSA_encrypter(path string,msg []byte)[]byte  {
	//首先从文件中提取公钥
	fp,_:=os.Open(path)
	defer fp.Close()
	//测量文件长度以便于保存
	fileinfo,_:=fp.Stat()
	buf:=make([]byte,fileinfo.Size())
	fp.Read(buf)
	//下面的操作是与创建秘钥保存时相反的
	//pem解码
	block,_:=pem.Decode(buf)
	//x509解码,得到一个interface类型的pub
	pub,_:=x509.ParsePKIXPublicKey(block.Bytes)
	//加密操作,需要将接口类型的pub进行类型断言得到公钥类型
	cipherText,_:=rsa.EncryptPKCS1v15(rand.Reader,pub.(*rsa.PublicKey),msg)
	return cipherText
}

//使用私钥进行解密
func RSA_decrypter(path string,cipherText []byte)[]byte  {
	//同加密时,先将私钥从文件中取出,进行二次解码
	fp,_:=os.Open(path)
	defer fp.Close()
	fileinfo,_:=fp.Stat()
	buf:=make([]byte,fileinfo.Size())
	fp.Read(buf)
	block,_:=pem.Decode(buf)
	PrivateKey,_:=x509.ParsePKCS1PrivateKey(block.Bytes)
	//二次解码完毕,调用解密函数
	afterDecrypter,_:=rsa.DecryptPKCS1v15(rand.Reader,PrivateKey,cipherText)
	return afterDecrypter
}

func main() {
	//尝试调用
	msg:=[]byte("RSA非对称加密很棒")
	ciphertext:=RSA_encrypter("csdn_PublicKey.pem",msg)
	//转化为十六进制方便查看结果
	fmt.Println(hex.EncodeToString(ciphertext))
	result:=RSA_decrypter("csdn_private.pem",ciphertext)
	fmt.Println(string(result))
}


以上就是加密解密的go语言实现了。

我博客中还有很多关于对称加密,椭圆形曲线加密解密,单向散列函数、数字签名等详细分析,欢迎一起交流: )

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
双向 RSA + AES 加密是一种常见的加密方式,其中使用 RSA 算法加密 AES 密钥,然后使用 AES 算法加密数据。在 C# 中,可以使用 `RSACryptoServiceProvider` 类和 `AesCryptoServiceProvider` 类来实现加密方式。以下是一个简单的示例: ```csharp using System; using System.IO; using System.Security.Cryptography; using System.Text; class Program { static void Main(string[] args) { string plainText = "Hello, world!"; byte[] encryptedData = Encrypt(plainText); string decryptedText = Decrypt(encryptedData); Console.WriteLine("Original text: {0}", plainText); Console.WriteLine("Encrypted data: {0}", Convert.ToBase64String(encryptedData)); Console.WriteLine("Decrypted text: {0}", decryptedText); } static byte[] Encrypt(string plainText) { byte[] aesKey = GenerateAesKey(); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] encryptedAesKey = rsa.Encrypt(aesKey, true); // 使用 RSA 加密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.GenerateIV(); using (var memoryStream = new MemoryStream()) { memoryStream.Write(aes.IV, 0, aes.IV.Length); using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write)) { byte[] plainData = Encoding.UTF8.GetBytes(plainText); cryptoStream.Write(plainData, 0, plainData.Length); cryptoStream.FlushFinalBlock(); } byte[] encryptedData = memoryStream.ToArray(); byte[] result = new byte[encryptedAesKey.Length + encryptedData.Length]; Buffer.BlockCopy(encryptedAesKey, 0, result, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, 0, result, encryptedAesKey.Length, encryptedData.Length); return result; } } } } static string Decrypt(byte[] encryptedData) { byte[] encryptedAesKey = new byte[128]; // RSA 加密 AES 密钥得到的密文长度为 128 字节 byte[] encryptedDataOnly = new byte[encryptedData.Length - encryptedAesKey.Length]; Buffer.BlockCopy(encryptedData, 0, encryptedAesKey, 0, encryptedAesKey.Length); Buffer.BlockCopy(encryptedData, encryptedAesKey.Length, encryptedDataOnly, 0, encryptedDataOnly.Length); using (var rsa = new RSACryptoServiceProvider()) { rsa.PersistKeyInCsp = false; byte[] aesKey = rsa.Decrypt(encryptedAesKey, true); // 使用 RSA 解密 AES 密钥 using (var aes = new AesCryptoServiceProvider()) { aes.Key = aesKey; aes.IV = encryptedDataOnly.Take(aes.IV.Length).ToArray(); using (var memoryStream = new MemoryStream()) { using (var cryptoStream = new CryptoStream(memoryStream, aes.CreateDecryptor(), CryptoStreamMode.Write)) { cryptoStream.Write(encryptedDataOnly, aes.IV.Length, encryptedDataOnly.Length - aes.IV.Length); cryptoStream.FlushFinalBlock(); } byte[] decryptedData = memoryStream.ToArray(); return Encoding.UTF8.GetString(decryptedData); } } } } static byte[] GenerateAesKey() { using (var aes = new AesCryptoServiceProvider()) { aes.GenerateKey(); return aes.Key; } } } ``` 上面的代码中,首先调用 `GenerateAesKey` 方法生成 AES 密钥,然后使用 RSA 算法加密 AES 密钥。加密时,先将 AES 密钥使用 RSA 加密,然后使用 AES 算法加密数据。具体来说,将 AES 密钥和 IV 都写入 `MemoryStream` 对象中,然后使用 `CryptoStream` 对象将数据写入 `MemoryStream` 对象中。最后将密文和 RSA 加密的 AES 密钥一起返回。 解密时,先从密文中取出 RSA 加密的 AES 密钥,然后使用 RSA 算法解密 AES 密钥。解密时,先从密文中取出 AES 的 IV 值,然后使用 `CryptoStream` 对象将数据解密。最后将解密后的文本返回。 注意,上面的示例仅用于演示 RSA + AES 加密的基本原理,实际使用中还需要考虑安全性等因素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值