1、当有客户端连接成功时,就在服务器端生成一个RSA密钥对
2、服务器将公钥发送给客户端
3、客户端生成一个对称加密的密钥
4、客户端用公钥对对称加密的密钥加密,发送给服务器端
5、服务器用私钥对密文进行解密,拿到对称加密的密钥
6、双方使用对称加密的方式进行通信
server.go
func main() {
//服务器地址信息
udpaddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8888")
if err != nil {
panic(err)
}
conn, err1 := net.ListenUDP("udp", udpaddr)
if err1 != nil {
panic(err)
}
defer conn.Close()
count := 0
length := 0
data := make([]byte, 4096)
var aesKey []byte
var privateKey *rsa.PrivateKey
//通信
for {
count++
//接受客户端发送来的消息
n, raddr, err := conn.ReadFromUDP(data)
length = n
if count == 1 {
//1、生成密钥对,指定密钥私钥长度为1024
privateKey, err = rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
//2、取出公钥
publickey := privateKey.PublicKey
//3、x509格式化公钥
pubder, err := x509.MarshalPKIXPublicKey(&publickey)
if err != nil {
panic(err)
}
//4、pem block
block := pem.Block{Type: "rsa publickkey",
Bytes: pubder,
}
//5、pem编码得到base64编码
var buf bytes.Buffer
pem.Encode(&buf, &block)
//将编码好的公钥发送给客户端
_, err = conn.WriteToUDP(buf.Bytes(), raddr)
if err != nil {
panic(err)
}
}
if count == 2 {
//接受客户端发送来的对称密钥,由于客户端发送来的数据是经过16进制编码,因此要解码
text, err := hex.DecodeString(string(data[:length]))
if err != nil {
panic(err)
}
if err != nil {
panic(err)
}
//私钥解密,拿到对称加密的密钥
aesKey, err = rsa.DecryptPKCS1v15(rand.Reader, privateKey, text)
fmt.Println("对称加密的密钥:", aesKey)
conn.WriteToUDP([]byte("对称密钥接受完毕"), raddr)
}
//往后就是对称加密通信
if count > 2 {
//创建aes接口
block, err := aes.NewCipher(aesKey)
if err != nil {
panic(err)
}
//创建一个使用CTR分组的接口
stream := cipher.NewCTR(block, aesKey)
//解码拿到密文
cipherText, err := hex.DecodeString(string(data[:length]))
if err != nil {
panic(err)
}
plainText := make([]byte, len(cipherText))
stream.XORKeyStream(plainText, cipherText)
fmt.Println("接受并解析的数据:", string(plainText))
conn.WriteToUDP([]byte("加密数据接受完毕"), raddr)
}
}
}
client.go
func main() {
conn, err := net.Dial("udp", "127.0.0.1:8888")
if err != nil {
panic(err)
}
defer conn.Close()
count := 0
var publicKey *rsa.PublicKey
data := make([]byte, 4096)
//以下三行产生对称加密的密钥
hvalue := md5.Sum([]byte("1234abcd")) //得到16字节二进制哈希值
hexText := hex.EncodeToString(hvalue[:]) //把二进制转换为16进制字符串 长度为16*2
aesKey := []byte(hexText)[:aes.BlockSize] //把32字节长的密钥阶段为16字节
for {
count++
if count == 1 {
//向服务器say hello
conn.Write([]byte("hello i am client"))
//阻塞。。。
//收到服务器发送来的公钥
n, err := conn.Read(data)
if err != nil {
panic(err)
}
fmt.Println(string(data[:n]))
//pem解码
block, _ := pem.Decode(data[:n])
//x509解码
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic(err)
}
//类型断言,拿到公钥
publicKey = pubInterface.(*rsa.PublicKey)
}
if count == 2 {
//使用公钥加密aeskey
//通过公钥加密的密文是二进制,在网络通信时不要发送二进制,因为有不可见字符
//最好给他编码,base64或者16进制编码,
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, aesKey)
if err != nil {
panic(err)
}
//发送给服务器
conn.Write([]byte(hex.EncodeToString(cipherText)))
}
//开始使用对称加密通信
if count > 2 {
block, err := aes.NewCipher(aesKey)
if err != nil {
panic(err)
}
//创建ctr模式接口
text := []byte("[对称加密通信]你吃了吗?")
stream := cipher.NewCTR(block, aesKey)
stream.XORKeyStream(text, text)
conn.Write([]byte(hex.EncodeToString(text)))
}
if count > 1 {
//阻塞
n, _ := conn.Read(data)
fmt.Println("接受到的数据:", string(data[:n]))
}
time.Sleep(time.Second)
}
}
