@judd
Для зашифрования и расшифрования данных, передаваемых по протоколу WebSocket в Go можно использовать пакет github.com/gorilla/websocket
. Вот пример кода, показывающий, как это можно сделать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
package main import ( "crypto/aes" "crypto/cipher" "encoding/base64" "log" "net/http" "github.com/gorilla/websocket" ) var upgrader = websocket.Upgrader{} func main() { http.HandleFunc("/", handleWebSocket) log.Fatal(http.ListenAndServe(":8080", nil)) } func handleWebSocket(w http.ResponseWriter, r *http.Request) { // Обновление HTTP соединения до WebSocket conn, err := upgrader.Upgrade(w, r, nil) if err != nil { log.Println(err) return } defer conn.Close() for { // Принимаем сообщение от клиента _, msg, err := conn.ReadMessage() if err != nil { log.Println(err) break } // Расшифровываем полученные данные decryptedMsg, err := decryptAES(msg, "encryption-key") if err != nil { log.Println(err) break } log.Printf("Received: %s ", decryptedMsg) // Шифруем и отправляем обратно клиенту encryptedMsg, err := encryptAES(decryptedMsg, "encryption-key") if err != nil { log.Println(err) break } err = conn.WriteMessage(websocket.TextMessage, encryptedMsg) if err != nil { log.Println(err) break } } } func encryptAES(text, key string) ([]byte, error) { // Генерация 32-байтного ключа шифрования из строки // (предположим, что key хранится в hex-или base64-формате) keyBytes, err := base64.StdEncoding.DecodeString(key) if err != nil { return nil, err } block, err := aes.NewCipher(keyBytes) if err != nil { return nil, err } // Используем режим ECB для простоты; для более безопасного шифрования // рекомендуется использовать режим CBC или GCM ecb := cipher.NewECBEncrypter(block) // Дополняем входной текст до размера блока paddedText := padBlock(text, block.BlockSize()) encrypted := make([]byte, len(paddedText)) ecb.CryptBlocks(encrypted, []byte(paddedText)) return encrypted, nil } func decryptAES(encrypted []byte, key string) (string, error) { keyBytes, err := base64.StdEncoding.DecodeString(key) if err != nil { return "", err } block, err := aes.NewCipher(keyBytes) if err != nil { return "", err } ecb := cipher.NewECBDecrypter(block) decrypted := make([]byte, len(encrypted)) ecb.CryptBlocks(decrypted, encrypted) // Удаляем заполнение unpaddedText := unpadBlock(string(decrypted), block.BlockSize()) return unpaddedText, nil } func padBlock(text string, blockSize int) string { padSize := blockSize - len(text)%blockSize padding := byte(padSize) for i := 0; i < padSize; i++ { text += string(padding) } return text } func unpadBlock(paddedText string, blockSize int) string { padding := int(paddedText[len(paddedText)-1]) // Проверяем, что заполнение является корректным if padding < 1 || padding > blockSize { return paddedText } for i := 0; i < padding; i++ { if paddedText[len(paddedText)-1-i] != byte(padding) { return paddedText } } return paddedText[:len(paddedText)-padding] } |
Обратите внимание, что данный пример использует режим ECB шифрования - это плохая практика для безопасности. Рекомендуется использовать режим CBC или GCM вместо него.
Чтобы зашифровать и расшифровать данные на клиентской стороне в JavaScript, вы можете использовать стандартные функции для работы с шифрованием, такие как crypto.subtle.encrypt
и crypto.subtle.decrypt
. Вот пример кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
// Зашифровываем и отправляем данные на сервер function sendEncryptedData(socket, data, key) { const textEncoder = new TextEncoder(); const encodedData = textEncoder.encode(data); crypto.subtle.encrypt( { name: "AES-ECB", length: 128, }, key, encodedData ).then((encryptedData) => { socket.send(encryptedData); }).catch((error) => { console.error(error); }); } // Расшифровываем полученные данные function processEncryptedData(data, key) { crypto.subtle.decrypt( { name: "AES-ECB", length: 128, }, key, data ).then((decryptedData) => { const textDecoder = new TextDecoder(); const decodedData = textDecoder.decode(decryptedData); console.log(decodedData); }).catch((error) => { console.error(error); }); } // Генерируем ключ шифрования crypto.subtle.generateKey( { name: "AES-ECB", length: 128, }, true, ["encrypt", "decrypt"] ).then((key) => { // Отправляем ключ серверу или используем его для расшифровки данных // ... // Пример отправки зашифрованных данных const socket = new WebSocket("ws://localhost:8080/"); socket.onopen = () => { sendEncryptedData(socket, "Hello, server!", key); }; // Пример обработки полученных зашифрованных данных socket.onmessage = (event) => { processEncryptedData(event.data, key); }; }).catch((error) => { console.error(error); }); |
Обратите внимание, что примеры кода являются базовыми, их следует изменить в зависимости от конкретных требований вашего приложения.