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) } }