09 UDP實現訊息認證
阿新 • • 發佈:2018-12-14
目錄
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) } }