“非对称加密也叫公钥密码: 使用公钥加密, 使用私钥解密”
下面我们来看一看使用公钥密码的通信流程。假设Alice要给Bob发送一条消息,Alice是发送者,Bob是接收者,而窃听者Eve能够窃所到他们之间的通信内容。
在公非对称加密通信中,通信过程是由接收者Bob来启动的。
-
Bob生成一个包含公钥和私钥的密钥对。
私钥由Bob自行妥善保管。
-
Bob将自己的公钥发送给Alicea
Bob的公钥被窃听者Eve截获也没关系。
将公钥发送给Alice,表示Bob请Alice用这个公钥对消息进行加密并发送给他。
-
Alice用Bob的公钥对消息进行加密。
加密后的消息只有用Bob的私钥才能够解密。
虽然Alice拥有Bob的公钥,但用Bob的公钥是无法对密文进行解密的。
-
Alice将密文发送给Bobo
密文被窃听者Eve截获也没关系。Eve可能拥有Bob的公钥,但是用Bob的公钥是无法进行解密的。
-
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加密) 密文=明文EmodN(RSA加密)
也就是说,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解密) 明文=密文DmodN(RSA解密)
也就是说,对表示密文的数字的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)的首字母。
我们将上面讲过的内容整理一下,如下表所示。
生成私钥操作流程概述
- 使用rsa中的GenerateKey方法生成私钥
- 通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
- 将私钥字符串设置到pem格式块中
- 通过pem将设置好的数据进行编码, 并写入磁盘文件中
生成公钥操作流程
- 从得到的私钥对象中将公钥信息取出
- 通过x509标准将得到 的rsa公钥序列化为字符串
- 将公钥字符串设置到pem格式块中
- 通过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-----
运行结果