RSA解決對稱密鑰分發


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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM