From 42f8c1a0bd807d5c6ae770400f89c041fcd2917c Mon Sep 17 00:00:00 2001 From: berkkirtay Date: Sun, 8 Sep 2024 14:02:05 +0300 Subject: [PATCH] User authentication with PKCS --- .gitignore | 5 + README.md | 16 ++- src/api/controllers/authentication.go | 15 +-- src/api/middlewares/router.go | 1 - src/commands/file_handler.go | 27 ++++++ src/commands/room_command.go | 2 +- src/commands/user_command.go | 71 +++++++++++--- src/infra/cryptography/cryptography.go | 70 +++++++++++++ .../cryptography/cryptography_service.go | 78 ++++++++++----- src/infra/cryptography/encryption.go | 32 ------ src/infra/cryptography/signature.go | 70 ------------- src/services/auth/authentication.go | 30 ++++-- src/services/auth/authentication_service.go | 97 ++++++++++++++----- src/services/room/message.go | 16 +-- src/services/room/room.go | 22 ++--- src/services/room/room_service.go | 10 +- src/services/user/user.go | 26 +++-- src/services/user/user_service.go | 26 +++-- 18 files changed, 384 insertions(+), 230 deletions(-) create mode 100644 src/commands/file_handler.go create mode 100644 src/infra/cryptography/cryptography.go delete mode 100644 src/infra/cryptography/encryption.go delete mode 100644 src/infra/cryptography/signature.go diff --git a/.gitignore b/.gitignore index f095d66..a1e5730 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,8 @@ go.work # go executable file output main + +# secret files +PRIVATE_KEY +PUBLIC_KEY +SIGN diff --git a/README.md b/README.md index adcbe42..6ffcfbe 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Right now this is only a fun side project. Please contact me for any considerati - [x] HTTP based async messagging with DB synchronization among peers (requires improvement) - [ ] Diffie-hellman key exchange for p2p key agreement (requires improvement) - [x] CBC AES encryption for messages -- [ ] RSA or Elliptic-curve based digital signature for verifications +- [x] RSA or Elliptic-curve based digital signature for verifications - [ ] GUI usage instead of CLI ## Stack @@ -22,3 +22,17 @@ Right now this is only a fun side project. Please contact me for any considerati ## Considerations - HTTP based room messaging can be replaced by a custom protocol such that peers can communicate over a small layer on top of TCP directly. - For production usage, as centralized lookup server can be developed for peers to connect each other over the web. +- Old-school password based authentication requires an additional layer of encryption. To improve this point, authentication must be done with user signatures where peers validate each others signatures and hashes. This means every user should generate their own private keys and use them for communication with other peers. +In this flow: + +1. A user passes a public key and a signature to a peer. + +2. The peer can validate the signature with the public key and generate a authentication token for the user. To pass this token, the peer can encrypt it with the users public key. + +3. The user can decrypt the encrypted authentication key with his private key and start sending requests to the peer. + +4. The user can send room and message requests and the peer encrypt the room secret keys to the user which is similar to the authentication key encryption. + +5. The user can decrypt the room secret key (symmetric key) and use this key to encrypt and decrypt the messages in the room. + +6. Master peer can choose the renew the room master key and it can send a synchronization requests to the all users in a room. This would be easier to handle with UDP or WebSocket protocols. diff --git a/src/api/controllers/authentication.go b/src/api/controllers/authentication.go index dd1027c..951072f 100644 --- a/src/api/controllers/authentication.go +++ b/src/api/controllers/authentication.go @@ -17,20 +17,7 @@ func postAuthRequest(c *gin.Context) { if err != nil { panic(err) } - var foundUser = user.GetUser(userBody.Id, userBody.Name) - if foundUser.Id == "" { - c.AbortWithStatus(http.StatusNotFound) - return - } - if foundUser.Password != userBody.Password { - c.AbortWithStatus(http.StatusUnauthorized) - return - } - - res := auth.Authenticate(auth.CreateAuthenticationModel( - auth.WithId(foundUser.Id), - auth.WithName(foundUser.Name), - auth.WithPassword(foundUser.Password)), c) + res := auth.Authenticate(userBody, c) if res.Token == "" { c.AbortWithStatusJSON(http.StatusBadRequest, res) return diff --git a/src/api/middlewares/router.go b/src/api/middlewares/router.go index 0c62826..182057c 100644 --- a/src/api/middlewares/router.go +++ b/src/api/middlewares/router.go @@ -16,7 +16,6 @@ func InitializeRouters(routerGroup *gin.RouterGroup) { controllers.AuthRouter(routerGroup) routerGroup.Use(ValidateAuthentication()) controllers.Roomouter(routerGroup) - } func handleGenericPanic(c *gin.Context, err any) { diff --git a/src/commands/file_handler.go b/src/commands/file_handler.go new file mode 100644 index 0000000..f6f7777 --- /dev/null +++ b/src/commands/file_handler.go @@ -0,0 +1,27 @@ +// Copyright (c) 2024 Berk Kirtay + +package commands + +import ( + "os" +) + +func dumpToFile(data string, fileName string) { + file, err := os.Create(fileName) + if err != nil { + panic(err) + } + _, err = file.Write([]byte(data)) + if err != nil { + panic(err) + } + defer file.Close() +} + +func readFromFile(fileName string) string { + data, err := os.ReadFile(fileName) + if err != nil { + panic(err) + } + return string(data) +} diff --git a/src/commands/room_command.go b/src/commands/room_command.go index 7872156..d7a0bd0 100644 --- a/src/commands/room_command.go +++ b/src/commands/room_command.go @@ -108,7 +108,7 @@ func joinRoom(roomId string, roomPassword string) { } currentRoom = room currentRoom.RoomMasterKey = cryptography.DecryptRSA( - currentRoom.RoomMasterKey, currentUser.Signature.PrivateKey) + currentRoom.RoomMasterKey, sessionAuth.Cryptography.PrivateKey) fmt.Printf("Joined the room. You will talk with:\n") roomUsers = make(map[string]user.User) diff --git a/src/commands/user_command.go b/src/commands/user_command.go index c4b725d..5628f51 100644 --- a/src/commands/user_command.go +++ b/src/commands/user_command.go @@ -5,6 +5,7 @@ package commands import ( "encoding/json" "fmt" + "main/infra/cryptography" "main/infra/http" "main/services/auth" "main/services/user" @@ -14,39 +15,77 @@ var sessionAuth auth.AuthenticationModel var CurrentUser user.User func HandleRegister(command []string) { + if len(command) != 2 { + fmt.Printf("Wrong usage.\n") + return + } + + name := command[1] + userCrypto := cryptography.CreateCommonCrypto( + name) + dumpToFile(userCrypto.PrivateKey, "PRIVATE_KEY") + dumpToFile(userCrypto.PublicKey, "PUBLIC_KEY") + dumpToFile(userCrypto.Sign, "SIGN") + userCrypto.PrivateKey = "" + var user user.User = user.CreateUser( + user.WithName(name), + user.WithIsPeer(true), + user.WithCryptography(userCrypto)) + body, err := json.Marshal(user) + if err != nil { + fmt.Printf("Error: %s", err) + return + } + res := http.POST(assignedPeer.Address+"/users", string(body), &user) + if res.StatusCode == http.CREATED { + fmt.Printf("Successfully registered as a new peer user.\n") + fmt.Printf("Crypto files are exported.\n") + } } func HandleLogin(command []string) { - if len(command) != 3 { + if len(command) > 3 || len(command) < 2 { fmt.Printf("Wrong usage.\n") return } - userLogin := command[1] - password := command[2] - respBody := make([]user.User, 1) res := http.GET(assignedPeer.Address+"/users", &respBody, "id", userLogin, "name", userLogin) - if res.StatusCode != http.OK { fmt.Printf("User %s does not exist.\n", userLogin) return } - fmt.Printf("Hello %s! Your authentication process is ongoing..\n", respBody[0].Name) - - auth := auth.CreateAuthenticationModel( - auth.WithId(userLogin), - auth.WithName(userLogin), - auth.WithPassword(password)) - login(&auth) - - if auth.Token != "" { - sessionAuth = auth + var authentication auth.AuthenticationModel = auth.CreateDefaultAuthenticationModel() + if len(command) == 2 { + publicKey := readFromFile("PUBLIC_KEY") + privateKey := readFromFile("PRIVATE_KEY") + sign := readFromFile("SIGN") + userCrypto := cryptography.CreateCryptography( + cryptography.WithSign(sign), + cryptography.WithPublicKey(publicKey)) + authentication = auth.CreateAuthenticationModel( + auth.WithId(userLogin), + auth.WithName(userLogin), + auth.WithCryptography(userCrypto)) + login(&authentication) + if authentication.Token != "" { + authentication.Token = cryptography.DecryptRSA(authentication.Token, privateKey) + } + } else if len(command) == 3 { + password := command[2] + authentication = auth.CreateAuthenticationModel( + auth.WithId(userLogin), + auth.WithName(userLogin), + auth.WithPassword(password)) + login(&authentication) + } + if authentication.Token != "" { + sessionAuth = authentication CurrentUser = respBody[0] http.InitializeService(sessionAuth.Cookies, sessionAuth.Id, sessionAuth.Token) - fmt.Printf("You are authorized with the user-id: %s\n", auth.Id) + fmt.Printf("You are authorized with the user-id: %s\n", authentication.Id) } else { fmt.Printf("Authentication process failed.. somehow.\n") } diff --git a/src/infra/cryptography/cryptography.go b/src/infra/cryptography/cryptography.go new file mode 100644 index 0000000..3c72178 --- /dev/null +++ b/src/infra/cryptography/cryptography.go @@ -0,0 +1,70 @@ +// Copyright (c) 2024 Berk Kirtay + +package cryptography + +type Cryptography struct { + Sign string `json:"sign,omitempty" bson:"sign,omitempty"` + PublicKey string `json:"publicKey,omitempty" bson:"publicKey,omitempty"` + PrivateKey string `json:"privateKey,omitempty" bson:"privateKey,omitempty"` + Nonce int64 `json:"nonce,omitempty" bson:"nonce,omitempty"` + Timestamp string `json:"timestamp,omitempty" bson:"timestamp,omitempty"` + Hash string `json:"hash,omitempty" bson:"hash,omitempty"` +} + +type CryptographyOption func(Cryptography) Cryptography + +func WithSign(sign string) CryptographyOption { + return func(Cryptography Cryptography) Cryptography { + Cryptography.Sign = sign + return Cryptography + } +} + +func WithPublicKey(publicKey string) CryptographyOption { + return func(Cryptography Cryptography) Cryptography { + Cryptography.PublicKey = publicKey + return Cryptography + } +} + +func WithPrivateKey(privateKey string) CryptographyOption { + return func(Cryptography Cryptography) Cryptography { + Cryptography.PrivateKey = privateKey + return Cryptography + } +} + +func WithNonce(nonce int64) CryptographyOption { + return func(Cryptography Cryptography) Cryptography { + Cryptography.Nonce = nonce + return Cryptography + } +} + +func WithTimestamp(timestamp string) CryptographyOption { + return func(Cryptography Cryptography) Cryptography { + Cryptography.Timestamp = timestamp + return Cryptography + } +} + +func WithHash(hash string) CryptographyOption { + return func(Cryptography Cryptography) Cryptography { + Cryptography.Hash = hash + return Cryptography + } +} + +func CreateDefaultCryptography() Cryptography { + return Cryptography{} +} + +func CreateCryptography(options ...CryptographyOption) *Cryptography { + Cryptography := CreateDefaultCryptography() + + for _, option := range options { + Cryptography = option(Cryptography) + } + + return &Cryptography +} diff --git a/src/infra/cryptography/cryptography_service.go b/src/infra/cryptography/cryptography_service.go index bdfecd3..f79460e 100644 --- a/src/infra/cryptography/cryptography_service.go +++ b/src/infra/cryptography/cryptography_service.go @@ -24,37 +24,34 @@ const ( RSA_KEY_SIZE = 2048 ) -// TODO area. -func CreateDefaultCrypto(values ...string) *Signature { - hash := GenerateSHA256([]string(values)) - nonce := int64(12312) // TODO - privateKey, publicKey := GenerateKeyPair() - return CreateSignature( +func CreateCommonCrypto(values ...string) *Cryptography { + hash := GenerateEncodedSHA256([]string(values)) + privateKey, publicKey := generateKeyPair() + crypto := CreateCryptography( WithPublicKey(publicKey), WithPrivateKey(privateKey), WithHash(hash), - WithNonce(nonce), + WithNonce(GenerateANonce()), WithSign(generateSignature(privateKey, hash)), WithTimestamp(time.Now().Format(time.RFC1123))) + return crypto } -func generateSignature(privateKey string, data string) string { +func generateSignature(privateKey string, hash string) string { decodedKey, err := b64.StdEncoding.DecodeString(privateKey) if err != nil { panic(err) } decodedBlock, _ := pem.Decode(decodedKey) - key, err := x509.ParsePKCS1PrivateKey(decodedBlock.Bytes) if err != nil { panic(err) } - calculatedHash := sha256.Sum256([]byte(data)) signature, err := rsa.SignPKCS1v15( rand.Reader, key, crypto.SHA256, - calculatedHash[:], + decodeSHA256(hash), ) if err != nil { panic(err) @@ -62,19 +59,45 @@ func generateSignature(privateKey string, data string) string { return b64.StdEncoding.EncodeToString(signature) } -func VerifySignature(data string, signature string, publicKey string) { - return +func VerifySignature(data []string, signature string, publicKey string) bool { + decodedSignature, err := b64.StdEncoding.DecodeString(signature) + if err != nil { + panic(err) + } + decodedKey, err := b64.StdEncoding.DecodeString(publicKey) + if err != nil { + panic(err) + } + decodedBlock, _ := pem.Decode(decodedKey) + key, err := x509.ParsePKCS1PublicKey(decodedBlock.Bytes) + if err != nil { + panic(err) + } + calculatedHash := generateSHA256Object(data) + err = rsa.VerifyPKCS1v15(key, crypto.SHA256, calculatedHash[:], decodedSignature) + return err == nil } -func GenerateSHA256(values []string) string { - sha256 := crypto.SHA256.New() - for _, value := range values { - sha256.Write([]byte(value)) +func GenerateEncodedSHA256(values []string) string { + hash := generateSHA256Object(values) + encodedHash := b64.StdEncoding.EncodeToString(hash[:]) + return encodedHash +} + +func decodeSHA256(hash string) []byte { + decodedHash, err := b64.StdEncoding.DecodeString(hash) + if err != nil { + panic(err) } + return decodedHash +} - hash := sha256.Sum(nil)[0:16] - encodedHash := b64.StdEncoding.EncodeToString(hash) - return encodedHash +func generateSHA256Object(values []string) [32]byte { + var data []byte = []byte{} + for _, value := range values { + data = append(data, []byte(value)...) + } + return sha256.Sum256(data) } func GenerateARandomMasterSecret() string { @@ -82,7 +105,7 @@ func GenerateARandomMasterSecret() string { if err != nil { panic(err) } - return GenerateSHA256([]string{strconv.FormatInt(randValue.Int64(), 10)}) + return GenerateEncodedSHA256([]string{strconv.FormatInt(randValue.Int64(), 10)}) } func EnrichMasterSecret(secret string, hash string) string { @@ -90,7 +113,7 @@ func EnrichMasterSecret(secret string, hash string) string { if err != nil { panic(err) } - return GenerateSHA256( + return GenerateEncodedSHA256( []string{ strconv.FormatInt(randValue.Int64(), 10), secret, @@ -98,7 +121,7 @@ func EnrichMasterSecret(secret string, hash string) string { ) } -func GenerateKeyPair(salts ...string) (string, string) { +func generateKeyPair(salts ...string) (string, string) { keyPair, err := rsa.GenerateKey(rand.Reader, RSA_KEY_SIZE) if err != nil { panic(err) @@ -197,3 +220,12 @@ func DecryptAES(cipherText string, key string) string { } return string(plainText[aes.BlockSize:]) } + +// TODO +func GenerateANonce() int64 { + randValue, err := rand.Int(rand.Reader, big.NewInt(64)) + if err != nil { + panic(err) + } + return randValue.Int64() +} diff --git a/src/infra/cryptography/encryption.go b/src/infra/cryptography/encryption.go deleted file mode 100644 index ef73560..0000000 --- a/src/infra/cryptography/encryption.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2024 Berk Kirtay - -package cryptography - -type Encryption struct { - key string - IV int64 - nonce int64 -} - -func (encryption *Encryption) WithKey(key string) *Encryption { - encryption.key = key - return encryption -} - -func (encryption *Encryption) WithIV(iV int64) *Encryption { - encryption.IV = iV - return encryption -} - -func (encryption *Encryption) WithNonce(nonce int64) *Encryption { - encryption.nonce = nonce - return encryption -} - -func (encryption *Encryption) Build() Encryption { - return *encryption -} - -func DefaultEncryption() *Encryption { - return &Encryption{} -} diff --git a/src/infra/cryptography/signature.go b/src/infra/cryptography/signature.go deleted file mode 100644 index 00e231c..0000000 --- a/src/infra/cryptography/signature.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2024 Berk Kirtay - -package cryptography - -type Signature struct { - Sign string `json:"sign,omitempty" bson:"sign,omitempty"` - PublicKey string `json:"publicKey,omitempty" bson:"publicKey,omitempty"` - PrivateKey string `json:"privateKey,omitempty" bson:"privateKey,omitempty"` - Nonce int64 `json:"nonce,omitempty" bson:"nonce,omitempty"` - Timestamp string `json:"timestamp,omitempty" bson:"timestamp,omitempty"` - Hash string `json:"hash,omitempty" bson:"hash,omitempty"` -} - -type SignatureOption func(Signature) Signature - -func WithSign(sign string) SignatureOption { - return func(signature Signature) Signature { - signature.Sign = sign - return signature - } -} - -func WithPublicKey(publicKey string) SignatureOption { - return func(signature Signature) Signature { - signature.PublicKey = publicKey - return signature - } -} - -func WithPrivateKey(privateKey string) SignatureOption { - return func(signature Signature) Signature { - signature.PrivateKey = privateKey - return signature - } -} - -func WithNonce(nonce int64) SignatureOption { - return func(signature Signature) Signature { - signature.Nonce = nonce - return signature - } -} - -func WithTimestamp(timestamp string) SignatureOption { - return func(signature Signature) Signature { - signature.Timestamp = timestamp - return signature - } -} - -func WithHash(hash string) SignatureOption { - return func(signature Signature) Signature { - signature.Hash = hash - return signature - } -} - -func CreateDefaultSignature() Signature { - return Signature{} -} - -func CreateSignature(options ...SignatureOption) *Signature { - signature := CreateDefaultSignature() - - for _, option := range options { - signature = option(signature) - } - - return &signature -} diff --git a/src/services/auth/authentication.go b/src/services/auth/authentication.go index 1d80b15..ed9251f 100644 --- a/src/services/auth/authentication.go +++ b/src/services/auth/authentication.go @@ -2,14 +2,18 @@ package auth -import "net/http" +import ( + "main/infra/cryptography" + "net/http" +) type AuthenticationModel struct { - Id string `json:"id,omitempty" bson:"id,omitempty"` - Name string `json:"name,omitempty" bson:"name,omitempty"` - Password string `json:"password,omitempty" bson:"password,omitempty"` - Token string `json:"token,omitempty" bson:"token,omitempty"` - Cookies []*http.Cookie `json:"cookies,omitempty" bson:"cookies,omitempty"` + Id string `json:"id,omitempty" bson:"id,omitempty"` + Name string `json:"name,omitempty" bson:"name,omitempty"` + Password string `json:"password,omitempty" bson:"password,omitempty"` + Token string `json:"token,omitempty" bson:"token,omitempty"` + Cryptography *cryptography.Cryptography `json:"cryptography,omitempty" bson:"cryptography,omitempty"` + Cookies []*http.Cookie `json:"cookies,omitempty" bson:"cookies,omitempty"` } type AuthenticationModelOption func(AuthenticationModel) AuthenticationModel @@ -42,6 +46,20 @@ func WithToken(token string) AuthenticationModelOption { } } +func WithCryptography(cryptography *cryptography.Cryptography) AuthenticationModelOption { + return func(authenticationModel AuthenticationModel) AuthenticationModel { + authenticationModel.Cryptography = cryptography + return authenticationModel + } +} + +func WithCookies(cookies []*http.Cookie) AuthenticationModelOption { + return func(authenticationModel AuthenticationModel) AuthenticationModel { + authenticationModel.Cookies = cookies + return authenticationModel + } +} + func CreateDefaultAuthenticationModel() AuthenticationModel { return AuthenticationModel{} } diff --git a/src/services/auth/authentication_service.go b/src/services/auth/authentication_service.go index 3027041..a51ea81 100644 --- a/src/services/auth/authentication_service.go +++ b/src/services/auth/authentication_service.go @@ -3,8 +3,8 @@ package auth import ( - "crypto/sha256" - "encoding/base64" + "main/infra/cryptography" + "main/services/user" "math/rand" "strconv" "time" @@ -13,36 +13,87 @@ import ( "github.com/gin-gonic/gin" ) -func Authenticate(authenticationModel AuthenticationModel, c *gin.Context) AuthenticationModel { - if authenticationModel.Id == "" || authenticationModel.Password == "" { - return authenticationModel +func Authenticate(receivedUser user.User, c *gin.Context) AuthenticationModel { + var actualUser user.User = user.GetUser(receivedUser.Id, receivedUser.Name) + if actualUser.IsPeer { + return authenticateWithPKCS(receivedUser, actualUser, c) + } else { + return authenticateWithPassword(receivedUser, actualUser, c) } + +} + +func authenticateWithPKCS( + receivedUser user.User, + actualUser user.User, + c *gin.Context) AuthenticationModel { + var verification bool = cryptography.VerifySignature( + []string{ + receivedUser.Name, + receivedUser.Role}, + receivedUser.Cryptography.Sign, + receivedUser.Cryptography.PublicKey) + if verification { + var token string = initializeSessionForUser(c, actualUser) + var encryptedToken string = cryptography.EncryptRSA( + token, + receivedUser.Cryptography.PublicKey) + return CreateAuthenticationModel( + WithId(actualUser.Id), + WithName(actualUser.Name), + WithToken(encryptedToken), + WithCryptography(actualUser.Cryptography), + ) + } else { + return CreateDefaultAuthenticationModel() + } +} + +func authenticateWithPassword( + receivedUser user.User, + actualUser user.User, + c *gin.Context) AuthenticationModel { + if receivedUser.Id == "" || receivedUser.Password == "" { + return CreateDefaultAuthenticationModel() + } + + if actualUser.Id == "" { + return CreateDefaultAuthenticationModel() + } + if actualUser.Password != receivedUser.Password { + return CreateDefaultAuthenticationModel() + } + var token string = initializeSessionForUser(c, actualUser) + return CreateAuthenticationModel( + WithId(actualUser.Id), + WithName(actualUser.Name), + WithToken(token), + WithCryptography(actualUser.Cryptography), + ) +} + +func initializeSessionForUser(c *gin.Context, user user.User) string { session := sessions.Default(c) - var token string = generateToken(authenticationModel, retrieveTokenNonce(session)) - session.Set(token, authenticationModel.Id) + var token string = generateToken(user, getTokenNonce(session)) + session.Set(token, user.Id) session.Save() - return CreateAuthenticationModel( - WithId(authenticationModel.Id), - WithName(authenticationModel.Name), - WithToken(token)) + return token } -func generateToken(authenticationModel AuthenticationModel, nonce string) string { - sha256 := sha256.New() - sha256.Write([]byte(authenticationModel.Id)) - sha256.Write([]byte(authenticationModel.Name)) - sha256.Write([]byte(authenticationModel.Password)) - sha256.Write([]byte(strconv.FormatInt(rand.Int63(), 10))) - sha256.Write([]byte(strconv.FormatInt(time.Now().Unix(), 10))) - sha256.Write([]byte(nonce)) - sha256.Write(sha256.Sum(nil)) - return base64.StdEncoding.EncodeToString(sha256.Sum(nil)) +func generateToken(user user.User, nonce string) string { + return cryptography.GenerateEncodedSHA256([]string{ + user.Id, + user.Name, + user.Password, + strconv.FormatInt(rand.Int63(), 10), + strconv.FormatInt(time.Now().Unix(), 10), + nonce}) } -func retrieveTokenNonce(session sessions.Session) string { +func getTokenNonce(session sessions.Session) string { var currentNonce interface{} = session.Get("TokenNonce") if currentNonce == nil { - currentNonce = int64(1000000000) + currentNonce = cryptography.GenerateANonce() } currentNonce = currentNonce.(int64) + 1 session.Set("TokenNonce", currentNonce) diff --git a/src/services/room/message.go b/src/services/room/message.go index 6352239..99f9d39 100644 --- a/src/services/room/message.go +++ b/src/services/room/message.go @@ -8,13 +8,13 @@ import ( ) type Message struct { - Id string `json:"id,omitempty" bson:"id,omitempty"` - UserId string `json:"userId,omitempty" bson:"userId,omitempty"` - RoomId string `json:"roomId,omitempty" bson:"roomId,omitempty"` - Text string `json:"text,omitempty" bson:"text,omitempty"` - Signature *cryptography.Signature `json:"signature,omitempty" bson:"signature,omitempty"` - IsEncrypted bool `json:"isEncrypted,omitempty" bson:"isEncrypted,omitempty"` - Audit *audit.Audit `json:"audit,omitempty" bson:"audit,omitempty"` + Id string `json:"id,omitempty" bson:"id,omitempty"` + UserId string `json:"userId,omitempty" bson:"userId,omitempty"` + RoomId string `json:"roomId,omitempty" bson:"roomId,omitempty"` + Text string `json:"text,omitempty" bson:"text,omitempty"` + Signature *cryptography.Cryptography `json:"signature,omitempty" bson:"signature,omitempty"` + IsEncrypted bool `json:"isEncrypted,omitempty" bson:"isEncrypted,omitempty"` + Audit *audit.Audit `json:"audit,omitempty" bson:"audit,omitempty"` } type MessageOption func(Message) Message @@ -47,7 +47,7 @@ func WithText(text string) MessageOption { } } -func WithMessageSignature(signature *cryptography.Signature) MessageOption { +func WithMessageSignature(signature *cryptography.Cryptography) MessageOption { return func(message Message) Message { message.Signature = signature return message diff --git a/src/services/room/room.go b/src/services/room/room.go index 0a9fb72..f9c50ab 100644 --- a/src/services/room/room.go +++ b/src/services/room/room.go @@ -10,16 +10,16 @@ import ( // Reminder: Owner of the room can be verified easily by checking the signature. type Room struct { - Id string `json:"id,omitempty" bson:"id,omitempty"` - Name string `json:"name,omitempty" bson:"name,omitempty"` - Info string `json:"info,omitempty" bson:"info,omitempty"` - Password string `json:"password,omitempty" bson:"password,omitempty"` - Capacity int64 `json:"capacity,omitempty" bson:"capacity,omitempty"` - Members []string `json:"members,omitempty" bson:"members,omitempty"` - Signature *cryptography.Signature `json:"signature,omitempty" bson:"signature,omitempty"` - Audit *audit.Audit `json:"audit,omitempty" bson:"audit,omitempty"` - DiffieHelmanKeys map[string]string `json:"-"` - RoomMasterKey string `json:"roomMasterKey,omitempty" bson:"roomMasterKey,omitempty` + Id string `json:"id,omitempty" bson:"id,omitempty"` + Name string `json:"name,omitempty" bson:"name,omitempty"` + Info string `json:"info,omitempty" bson:"info,omitempty"` + Password string `json:"password,omitempty" bson:"password,omitempty"` + Capacity int64 `json:"capacity,omitempty" bson:"capacity,omitempty"` + Members []string `json:"members,omitempty" bson:"members,omitempty"` + Signature *cryptography.Cryptography `json:"signature,omitempty" bson:"signature,omitempty"` + Audit *audit.Audit `json:"audit,omitempty" bson:"audit,omitempty"` + DiffieHelmanKeys map[string]string `json:"-"` + RoomMasterKey string `json:"roomMasterKey,omitempty" bson:"roomMasterKey,omitempty` } type RoomOption func(Room) Room @@ -66,7 +66,7 @@ func WithMembers(members []string) RoomOption { } } -func WithSignature(signature *cryptography.Signature) RoomOption { +func WithSignature(signature *cryptography.Cryptography) RoomOption { return func(room Room) Room { room.Signature = signature return room diff --git a/src/services/room/room_service.go b/src/services/room/room_service.go index 38721fc..9c1cddc 100644 --- a/src/services/room/room_service.go +++ b/src/services/room/room_service.go @@ -91,7 +91,7 @@ func PostRoom(room Room) Room { WithCapacity(room.Capacity), WithMembers([]string{}), WithRoomMasterKey(cryptography.GenerateARandomMasterSecret()), - WithSignature(cryptography.CreateDefaultCrypto( + WithSignature(cryptography.CreateCommonCrypto( room.Name, room.Info, room.Password, @@ -128,7 +128,7 @@ func JoinRoom(id string, room Room, userId string) Room { user := user.GetUser(userId, "") if slices.Contains(actualRoom.Members, userId) { - actualRoom.RoomMasterKey = cryptography.EncryptRSA(actualRoom.RoomMasterKey, user.Signature.PublicKey) + actualRoom.RoomMasterKey = cryptography.EncryptRSA(actualRoom.RoomMasterKey, user.Cryptography.PublicKey) return actualRoom } @@ -141,9 +141,6 @@ func JoinRoom(id string, room Room, userId string) Room { return CreateDefaultRoom() } - // masterSecret := cryptography.ServerSideDiffieHelmanKeyExhange(userHandshakeKey) - // actualRoom.DiffieHelmanKeys[userId] = masterSecret[0] - //actualRoom.RoomMasterKey = cryptography.EnrichMasterSecret(actualRoom.RoomMasterKey, user.Signature.Hash) actualRoom.Members = append(actualRoom.Members, userId) actualRoom.Audit.LastOnlineDate = time.Now().Format(time.RFC1123) @@ -154,8 +151,7 @@ func JoinRoom(id string, room Room, userId string) Room { return CreateDefaultRoom() } // SendAMessage(id, userId, buildAMessage(room, userId, CreateMessage(WithText("Greetings! I just joined.")))) - //TODO encrypt with users key pair :) - actualRoom.RoomMasterKey = cryptography.EncryptRSA(actualRoom.RoomMasterKey, user.Signature.PublicKey) + actualRoom.RoomMasterKey = cryptography.EncryptRSA(actualRoom.RoomMasterKey, user.Cryptography.PublicKey) return actualRoom } diff --git a/src/services/user/user.go b/src/services/user/user.go index fd0e0b2..234dfbe 100644 --- a/src/services/user/user.go +++ b/src/services/user/user.go @@ -8,13 +8,14 @@ import ( ) type User struct { - Id string `json:"id,omitempty" bson:"id,omitempty"` - Name string `json:"name,omitempty" bson:"name,omitempty"` - Password string `json:"password,omitempty" bson:"password,omitempty"` - Role string `json:"role,omitempty" bson:"role,omitempty"` - Signature *cryptography.Signature `json:"signature,omitempty" bson:"signature,omitempty"` - Actions []*Action `json:"actions,omitempty" bson:"actions,omitempty"` - Audit *audit.Audit `json:"audit,omitempty" bson:"audit,omitempty"` + Id string `json:"id,omitempty" bson:"id,omitempty"` + Name string `json:"name,omitempty" bson:"name,omitempty"` + Password string `json:"password,omitempty" bson:"password,omitempty"` + Role string `json:"role,omitempty" bson:"role,omitempty"` + Cryptography *cryptography.Cryptography `json:"cryptography,omitempty" bson:"cryptography,omitempty"` + Actions []*Action `json:"actions,omitempty" bson:"actions,omitempty"` + Audit *audit.Audit `json:"audit,omitempty" bson:"audit,omitempty"` + IsPeer bool `json:"isPeer,omitempty" bson:"isPeer,omitempty"` } type UserOption func(User) User @@ -47,9 +48,9 @@ func WithRole(role string) UserOption { } } -func WithSignature(signature *cryptography.Signature) UserOption { +func WithCryptography(cryptography *cryptography.Cryptography) UserOption { return func(user User) User { - user.Signature = signature + user.Cryptography = cryptography return user } } @@ -68,6 +69,13 @@ func WithAudit(audit *audit.Audit) UserOption { } } +func WithIsPeer(isPeer bool) UserOption { + return func(user User) User { + user.IsPeer = isPeer + return user + } +} + func CreateDefaultUser() User { return User{} } diff --git a/src/services/user/user_service.go b/src/services/user/user_service.go index 922a93c..6922779 100644 --- a/src/services/user/user_service.go +++ b/src/services/user/user_service.go @@ -25,7 +25,7 @@ func GetUsers(id string, name string, size string) []User { if id != "" || name != "" { var user User = GetUser(id, name) if user.Id != "" { - users = append(users, user) + users = append(users, hideUserCrypto(user)) } } else { options := options.Find() @@ -47,7 +47,7 @@ func GetUsers(id string, name string, size string) []User { if err != nil { panic(err) } - users = append(users, currentUser) + users = append(users, hideUserCrypto(currentUser)) } } } @@ -105,18 +105,22 @@ func buildUser(user User) User { res.Decode(&lastRecord) newUserId, _ = strconv.Atoi(lastRecord.Id) } - cryptography.GenerateKeyPair() + // Server side user key generation: + var userCrypto *cryptography.Cryptography = user.Cryptography + if !user.IsPeer { + userCrypto = cryptography.CreateCommonCrypto( + user.Name, + user.Role) + } return CreateUser( WithId(strconv.Itoa(newUserId+1)), WithName(user.Name), WithPassword(user.Password), WithRole(user.Role), - WithSignature(cryptography.CreateDefaultCrypto( - user.Name, - user.Password, - user.Role)), + WithCryptography(userCrypto), WithActions(nil), - WithAudit(user.Audit)) + WithAudit(user.Audit), + WithIsPeer(user.IsPeer)) } func PutUser(id string, user User) User { @@ -127,3 +131,9 @@ func PutUser(id string, user User) User { func DeleteUser(id string) { } + +func hideUserCrypto(user User) User { + user.Password = "" + user.Cryptography = nil + return user +}