1. 程式人生 > >09 UDP實現訊息認證

09 UDP實現訊息認證

目錄

1.1 server.go

package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"net"
)

func main() {
	//01.	構造伺服器地址資訊  sunlidong
	udpAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8999")
	if err != nil {
		fmt.Println("----------------連線失敗", err)
		return
	}
	//02.	建立監聽
	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		fmt.Println("建立監聽失敗.", err)
		return
	}
	//關閉conn
	defer conn.Close()
	//引數
	count := 0
	length := 0
	data := make([]byte, 4096)
	var aseKey []byte
	var privateKey *rsa.PrivateKey
	//通訊
	for {
		count++
		//第一次接收資料
		n, raddr, err := conn.ReadFromUDP(data)
		length = n
		if count == 1 {
			//生成祕鑰對
			privateKey, err = rsa.GenerateKey(rand.Reader, 1024)
			if err != nil {
				panic(err)
			}
			//02.	取出公鑰
			publicKey := privateKey.PublicKey
			//03.	使用x509格式化公鑰
			pubText, err := x509.MarshalPKIXPublicKey(&publicKey)
			if err != nil {
				panic(err)
			}
			//04.	建立pem block結構體
			block := pem.Block{
				Type:  "rsa public key",
				Bytes: pubText,
			}
			//05.	pem編碼
			var buf bytes.Buffer
			//得到base64編碼
			pem.Encode(&buf, &block)
			//將資料傳送給客戶端
			_, err = conn.WriteToUDP(buf.Bytes(), raddr)
			if err != nil {
				panic(err)
			}
		}
		//第二次,將接受的資料從祕鑰接出來
		if count == 2 {
			//1. base64 資料解碼
			text, err := hex.DecodeString(string(data[:length]))
			if err != nil {
				panic(err)
			}
			//02.	私鑰解密資料
			aseKey, err = rsa.DecryptPKCS1v15(rand.Reader, privateKey, text)
			fmt.Printf("對稱加密的私鑰:%s\n", string(aseKey))
			//03.	回覆資料
			conn.WriteToUDP([]byte("祕鑰接受完畢......"), raddr)
		}
		//大於兩次
		if count > 2 {
			//1.建立aes介面
			block, err := aes.NewCipher(aseKey)
			if err != nil {
				panic(err)
			}
			//2.建立str分組模式介面
			stream := cipher.NewCTR(block, aseKey)
			cipherText, err := hex.DecodeString(string(data[:length]))
			plainText := make([]byte, len(cipherText))
			stream.XORKeyStream(plainText, cipherText)
			fmt.Printf("接收並解析出的資料:%s\n", string(plainText))
			conn.WriteToUDP([]byte("加密資料接收完畢...."), raddr)
		}
	}
}

1.2client.go

package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"net"
	"time"
)

func main() {
	//01.	連線伺服器
	conn, err := net.Dial("udp", "127.0.0.1:8999")
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	//迴圈傳送資料
	count := 0
	var publicKey *rsa.PublicKey
	data := make([]byte, 4096)
	havlue := md5.Sum([]byte("12345678"))
	hexText := hex.EncodeToString(havlue[:])
	aseKey := []byte(hexText)[:aes.BlockSize]
	//開始操作
	for {
		count++
		if count == 1 {
			//1.	第一次傳送資料, 給伺服器打招呼
			conn.Write([]byte("你好伺服器......"))
			//02.	接收伺服器資料
			n, err := conn.Read(data)
			if err != nil {
				panic(err)
			}
			//03.	pem解碼
			fmt.Println("string", string(data[:n]))
			block, _ := pem.Decode(data[:n])
			//04.	x509解析出公鑰
			pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
			if err != nil {
				panic(err)
			}
			//04.	 型別斷言
			publicKey = pubInterface.(*rsa.PublicKey)
		}
		if count == 2 {
			//01.	使用公鑰加密私鑰
			cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, aseKey)
			if err != nil {
				panic(err)
			}
			conn.Write([]byte(hex.EncodeToString(cipherText)))
		}
		if count > 2 {
			//01.	建立aes介面
			block, err := aes.NewCipher(aseKey)
			if err != nil {
				panic(err)
			}
			//02.	建立ctr分組模式介面
			text := []byte("對稱加密通訊......")
			stream := cipher.NewCTR(block, aseKey)
			stream.XORKeyStream(text, text)
			conn.Write([]byte(hex.EncodeToString(text)))
		}
		//
		if count > 1 {
			n, _ := conn.Read(data)
			fmt.Printf("接收到的資料是:%s\n", string(data[:n]))
		}
		time.Sleep(time.Second)
	}
}