GO语言实现非对称加密流程及实例

“非对称加密也叫公钥密码: 使用公钥加密, 使用私钥解密”

下面我们来看一看使用公钥密码的通信流程。假设Alice要给Bob发送一条消息,Alice是发送者,Bob是接收者,而窃听者Eve能够窃所到他们之间的通信内容。

在公非对称加密通信中,通信过程是由接收者Bob来启动的。

  1. Bob生成一个包含公钥和私钥的密钥对。

    私钥由Bob自行妥善保管。

  2. Bob将自己的公钥发送给Alicea

    Bob的公钥被窃听者Eve截获也没关系。

    将公钥发送给Alice,表示Bob请Alice用这个公钥对消息进行加密并发送给他。

  3. Alice用Bob的公钥对消息进行加密。

    加密后的消息只有用Bob的私钥才能够解密。

    虽然Alice拥有Bob的公钥,但用Bob的公钥是无法对密文进行解密的。

  4. Alice将密文发送给Bobo

    密文被窃听者Eve截获也没关系。Eve可能拥有Bob的公钥,但是用Bob的公钥是无法进行解密的。

  5. Bob用自己的私钥对密文进行解密。

    请参考下图, 看一看在Alice和Bob之间到底传输了哪些信息。其实它们之间所传输的信息只有两个:Bob的公钥以及用Bob的公钥加密的密文。由于Bob的私钥没有出现在通信内容中,因此窃听者Eve无法对密文进行解密。

在这里插入图片描述

窃听者Eve可能拥有Bob的公钥,但是Bob的公钥只是加密密钥,而不是解密密钥,因此窃听者Eve就无法完成解密操作。

RSA加密

下面我们终于可以讲一讲非对称加密的代表—RSA的加密过程了。在RSA中,明文、密钥和密文都是数字。RSA的加密过程可以用下列公式来表达,如下。

密 文 = 明 文 E m o d N ( R S A 加 密 ) 密文=明文 ^ E mod N(RSA加密) =EmodNRSA

也就是说,RSA的密文是对代表明文的数字的E次方求modN的结果。换句话说,就是将明文自己做E次乘法,然后将其结果除以N求余数,这个余数就是密文。

咦,就这么简单?

对,就这么简单。仅仅对明文进行乘方运算并求mod即可,这就是整个加密的过程。在对称密码中,出现了很多复杂的函数和操作,就像做炒鸡蛋一样将比特序列挪来挪去,还要进行XOR(按位异或)等运算才能完成,但RSA却不同,它非常简洁。

对了,加密公式中出现的两个数一一一E和N,到底都是什么数呢?RSA的加密是求明文的E次方modN,因此只要知道E和N这两个数,任何人都可以完成加密的运算。所以说,E和N是RSA加密的密钥,也就是说,E和N的组合就是公钥

不过,E和N并不是随便什么数都可以的,它们是经过严密计算得出的。顺便说一句,E是加密(Encryption)的首字母,N是数字(Number)的首字母

有一个很容易引起误解的地方需要大家注意一一E和N这两个数并不是密钥对(公钥和私钥的密钥对)。E和N两个数才组成了一个公钥,因此我们一般会写成 “公钥是(E,N)” 或者 “公钥是{E, N}" 这样的形式,将E和N用括号括起来。

现在大家应该已经知道,RSA的加密就是 “求E次方的modN",接下来我们来看看RSA的解密。

RSA解密

RSA的解密和加密一样简单,可以用下面的公式来表达:

明 文 = 密 文 D m o d N ( R S A 解 密 ) 明文=密文^DmodN(RSA解密) =DmodNRSA

也就是说,对表示密文的数字的D次方求modN就可以得到明文。换句话说,将密文自己做D次乘法,再对其结果除以N求余数,就可以得到明文。

这里所使用的数字N和加密时使用的数字N是相同的。数D和数N组合起来就是RSA的解密密钥,因此D和N的组合就是私钥。只有知道D和N两个数的人才能够完成解密的运算。

大家应该已经注意到,在RSA中,加密和解密的形式是相同的。加密是求 "E次方的mod N”,而解密则是求 "D次方的modN”,这真是太美妙了。

当然,D也并不是随便什么数都可以的,作为解密密钥的D,和数字E有着相当紧密的联系。否则,用E加密的结果可以用D来解密这样的机制是无法实现的。

顺便说一句,D是解密〈Decryption)的首字母,N是数字(Number)的首字母

我们将上面讲过的内容整理一下,如下表所示。

在这里插入图片描述
在这里插入图片描述
生成私钥操作流程概述

  1. 使用rsa中的GenerateKey方法生成私钥
  2. 通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
  3. 将私钥字符串设置到pem格式块中
  4. 通过pem将设置好的数据进行编码, 并写入磁盘文件中

生成公钥操作流程

  1. 从得到的私钥对象中将公钥信息取出
  2. 通过x509标准将得到 的rsa公钥序列化为字符串
  3. 将公钥字符串设置到pem格式块中
  4. 通过pem将设置好的数据进行编码, 并写入磁盘文件
package main

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

//生成rsa密钥对,并且保存到磁盘中
func GenerateRsaKey(keySize int) {
	//使用rsa中的GenerateKey生成私钥
	privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
	if err != nil {
		panic(err)
	}

	//2. 通过x509标准将得到的rsa私钥序列化为ASN.1的DER编码格式
	derText := x509.MarshalPKCS1PrivateKey(privateKey)

	//3. 要组织一个pem.block
	block := pem.Block{
		Type:  "rsa private key", //这个地方随便写什么
		Bytes: derText,           //ASN.1的DER编码格式
	}

	//4. pem编码
	file, err1 := os.Create("private.pem") //保存在磁盘的文件名
	if err1 != nil {
		panic(err1)
	}
	pem.Encode(file, &block)

	file.Close()

	//生成rsa公钥 ===================================
	//1. 从私钥中取出公钥
	publicKey := privateKey.PublicKey
	//2.使用x509标准序列化  注意参数传参为地址
	derstream, err2 := x509.MarshalPKIXPublicKey(&publicKey)
	if err2 != nil {
		panic(err2)
	}

	//3. 将得到的数据放到pem.block中
	block = pem.Block{
		Type:    "rsa public key",
		Headers: nil,
		Bytes:   derstream,
	}

	//pem编码
	file, err = os.Create("public.pem")
	if err != nil {
		panic(err)
	}
	pem.Encode(file, &block)

	file.Close()
}

//使用rsa公钥加密文件
func publicEncode(plainText []byte, filename string) []byte {
	//1. 读取公钥信息 放到data变量中
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	stat, _ := file.Stat() //得到文件属性信息
	data := make([]byte, stat.Size())
	file.Read(data)
	file.Close()
	//2. 将得到的字符串pem解码
	block, _ := pem.Decode(data)

	//3. 使用x509将编码之后的公钥解析出来
	pubInterface, err2 := x509.ParsePKIXPublicKey(block.Bytes)
	if err2 != nil {
		panic(err2)
	}
	pubKey := pubInterface.(*rsa.PublicKey)

	//4. 使用公钥加密
	cipherText, err3 := rsa.EncryptPKCS1v15(rand.Reader, pubKey, plainText)
	if err3 != nil {
		panic(err3)
	}
	return cipherText
}

//使用rsa私钥加密
func privateDecode(cipherText []byte, filename string) []byte {
	//1. 打开并读取私钥文件
	file, err := os.Open(filename)
	if err != nil {
		panic(err)
	}
	stat, _ := file.Stat()
	data := make([]byte, stat.Size())
	file.Read(data)
	file.Close()
	//2. 将得到的字符串进行pem解码
	block, _ := pem.Decode(data)
	//3. 使用x509将编码之后的私钥解析出来
	privateKey, err3 := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err3 != nil {
		panic(err3)
	}
	//4. 使用私钥将数据解密
	plainText, err4 := rsa.DecryptPKCS1v15(rand.Reader, privateKey, cipherText)
	if err4 != nil {
		panic(err4)
	}
	return plainText
}

func main() {
	//生成rsa密钥对 1024 为密钥长度
	GenerateRsaKey(1024)
	//src表示明文,注意,明文越长,密钥的长度也要相应增加
	src := []byte("我是小崔,如果我死了,肯定不是自杀...")
	//使用rsa公钥加密
	cipherText := publicEncode(src, "public.pem")
	//使用rsa私钥解密
	plainText := privateDecode(cipherText, "private.pem")
	fmt.Println(string(plainText))
}

即可得到的公钥和私钥

-----BEGIN rsa private key-----
MIICXgIBAAKBgQC3swOLvQsBKQcb6o/medAanjuv3PMgK1jYvSD31IcMvU9N0nOv
qYgytSloHlu1GyKURBs5Vg3xVRsVaVgeRQnBtUEtaJNhT3+Qqe0Pynv+ifx2YidV
LyqgTzG+hHGp9uH2JAupkAqLzYwpw/rulOt2dq1J6hThT937FvpoH/KbBwIDAQAB
AoGBAIeeof+IkZdJsvXpNlPxmrIMIAS2GsilN/LLrotJXGsLWIEb3kzR3LuTA/7a
atpKLj1ICtFJtwF004n7PBMc5RXbeYQ5Sdb/6pYvlRWtkm4jaUZaB63SnbzL6RPp
NwCJjVGdJOdUG6yXeuHrvuTsbo/hlgoYWdr80Lb7Jf9ex6gBAkEA8tktzAU2+RkK
ue6elDUiytWk/XbEK3upEDp1L1FIJE2ioYRtrOxEEcBVbYXL+YkipL9rLf3C4k74
0STvprij1QJBAMGlzIyQyccnbBBF3TgYqKsMhdzTvemMWDX2Giq9nxxTgVaOqPYQ
u0W+/yN9gzlrJrKTOer4CEwkaCLNX2PbHWsCQQDZ6QVOODOu68iTNMo5JUD2DyVA
hyzZ89mthTcX4XDBmqRfGIytiUg/QX2mjFOOs35RpK4RE86m8cQVL3aX/MCNAkEA
qN2qeFGyg6cPB0nFVau7Oh4bhaxoCgfGzJelzeu5mnv/Z7nUAXApvvKFjy9ehW25
OzRD53EP20ZMQT0SmAN1rQJAQp949K4gjYLoIjmNKKulRix6HLDCVMsp132w/Hjv
kVpKJJ4IyDiPV8+6A3VAlxvSpjVusaR7Jq8VDiHBKEf5jQ==
-----END rsa private key-----

-----BEGIN rsa public key-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3swOLvQsBKQcb6o/medAanjuv
3PMgK1jYvSD31IcMvU9N0nOvqYgytSloHlu1GyKURBs5Vg3xVRsVaVgeRQnBtUEt
aJNhT3+Qqe0Pynv+ifx2YidVLyqgTzG+hHGp9uH2JAupkAqLzYwpw/rulOt2dq1J
6hThT937FvpoH/KbBwIDAQAB
-----END rsa public key-----

运行结果
在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对称加密算法是一种常用的加密方式,它采用了一对密钥,即公钥和私钥。公钥是公开的,可以任意分发,而私钥则只能由密钥的所有者持有,用于解密加密数据。常见的对称加密算法包括RSA、DSA、ECC等。 下面是一个使用RSA算法实现对称加密的Java示例代码: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import javax.crypto.Cipher; public class RSAEncryptionExample { public static void main(String[] args) throws Exception { String input = "Hello World!"; KeyPair keyPair = generateRSAKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); byte[] encryptedData = rsaEncrypt(input.getBytes(), publicKey); byte[] decryptedData = rsaDecrypt(encryptedData, privateKey); System.out.println("Original data: " + input); System.out.println("Encrypted data: " + new String(encryptedData)); System.out.println("Decrypted data: " + new String(decryptedData)); } public static KeyPair generateRSAKeyPair() throws Exception { KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA"); generator.initialize(2048); // key size KeyPair keyPair = generator.generateKeyPair(); return keyPair; } public static byte[] rsaEncrypt(byte[] data, PublicKey publicKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedData = cipher.doFinal(data); return encryptedData; } public static byte[] rsaDecrypt(byte[] data, PrivateKey privateKey) throws Exception { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedData = cipher.doFinal(data); return decryptedData; } } ``` 这个示例代码中,我们首先生成了一个RSA密钥对,包括公钥和私钥。然后使用公钥对原始数据进行加密,得到加密后的数据。接着使用私钥对加密后的数据进行解密,得到原始数据。 需要注意的是,RSA算法使用的密钥长度越长,安全性就越高,但加解密的速度也越慢。在实际应用中,需要根据实际需求和环境选择合适的密钥长度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值