From ee201b761f02c95e57e91528cf6060a55fd259d1 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 13 May 2021 22:02:27 +0400 Subject: Added signature verification on client side. --- http-client/client.go | 43 +++++++++++++++++++++++++++++++++++++++++++ http-client/cryptography.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) (limited to 'http-client') diff --git a/http-client/client.go b/http-client/client.go index a83659e..d448b8c 100644 --- a/http-client/client.go +++ b/http-client/client.go @@ -29,6 +29,8 @@ var storage struct { binding binding.ExternalStringList } +var userKeys = make(map[string]string) + type Request struct { User string Data string @@ -106,6 +108,26 @@ func tryAuth(user UserData) (bool, error) { } } +func getUserKey(user UserData, checkedUser string) (string, error) { + var resp Response + httpResp, err := makeRequest(Request{ + User: user.Username, + Data: checkedUser, + }, GetUserKey, user) + if err != nil { + return "", err + } + + body, _ := io.ReadAll(httpResp.Body) + _ = json.Unmarshal(body, &resp) + + if httpResp.StatusCode == http.StatusOK { + return resp.Message, nil + } else { + return "", errors.New(resp.Message) + } +} + func pingServer(user UserData) error { _, err := http.Get(user.ServerUrl) return err @@ -157,6 +179,27 @@ func runClient(user UserData) { storage.Lock() for _, signedMessage := range signedMessages { msg, _ := parseMessage(signedMessage) + userKey, ok := userKeys[msg.User] + if !ok { + key, err := getUserKey(user, msg.User) + if err != nil { + fmt.Printf("Error occurred when polling user (%s) key\n", msg.User) + continue + } + userKey = key + userKeys[msg.User] = key + } + passed, err := checkSignature(msg.Payload, msg.Signature, userKey) + if !passed { + fmt.Printf("Message didn't pass signature check. From %s: %s\n", msg.User, msg.Data) + continue + } + if err != nil { + fmt.Printf( + "Error occurred when checking signature of message. From %s: %s\n", + msg.User, msg.Data) + } + fmt.Printf("Polled new message from %s: %s\n", msg.User, msg.Data) _ = storage.binding.Append(msg.toString()) storage.messages = append(storage.messages, msg) diff --git a/http-client/cryptography.go b/http-client/cryptography.go index 175e60b..135f6b2 100644 --- a/http-client/cryptography.go +++ b/http-client/cryptography.go @@ -9,6 +9,7 @@ import ( "encoding/base64" "encoding/json" "encoding/pem" + "errors" "fmt" ) @@ -17,6 +18,8 @@ const KeyBitSize = 4096 // Приватный ключ - отдаётся серверу // Публичный ключ - сохраняется на клиенте +// Функции для подписи сообщений + func signRequest(req Request, key *rsa.PublicKey) (string, error) { body, _ := json.Marshal(req) based := base64.StdEncoding.EncodeToString(body) @@ -58,3 +61,39 @@ func generateKeys() (private []byte, public []byte, err error) { bytePublic := pem.EncodeToMemory(publicKey) return bytePrivate, bytePublic, nil } + +// Функции для проверки подписи полученных сообщений + +func decodeMessage(ciphertext []byte, stringKey string) ([]byte, error) { + block, _ := pem.Decode([]byte(stringKey)) + if block == nil { + return nil, errors.New("key is not found in given string") + } + + key, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + + plaintext, err := rsa.DecryptPKCS1v15(rand.Reader, key, ciphertext) + if err != nil { + return nil, err + } + return plaintext, err +} + +func checkSignature(payload string, signature string, key string) (bool, error) { + h := sha256.Sum256([]byte(payload)) + requestHash := fmt.Sprintf("%x", h) + + decodedSign, err := base64.StdEncoding.DecodeString(signature) + if err != nil { + return false, err + } + signHash, err := decodeMessage(decodedSign, key) + if err != nil { + return false, err + } + + return requestHash == string(signHash), nil +} -- cgit v1.2.3