This repository has been archived by the owner on Mar 6, 2021. It is now read-only.
/
clientencryption.go
115 lines (91 loc) · 2.53 KB
/
clientencryption.go
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
package proxy
import (
"crypto/rsa"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
)
import crand "crypto/rand"
type clientEncryptionManager struct {
gem *globalEncryptionManager
playerName string
playerUUID string
verifyToken []byte
sharedSecret []byte
}
func (gem *globalEncryptionManager) newClient(playerName string) (cem *clientEncryptionManager, err error) {
verifyToken := make([]byte, 16)
_, err = io.ReadFull(crand.Reader, verifyToken)
if err != nil {
return nil, err
}
cem = &clientEncryptionManager{
gem: gem,
playerName: playerName,
verifyToken: verifyToken,
}
return cem, nil
}
func (cem *clientEncryptionManager) makeEncryptionRequest() (packet *LC1EncryptionRequestPacket, err error) {
packet = &LC1EncryptionRequestPacket{
ServerID: cem.gem.serverID,
PublicKey: cem.gem.encodedPublicKey,
VerifyToken: cem.verifyToken,
}
return packet, nil
}
func (cem *clientEncryptionManager) handleEncryptionResponse(packet *LS1EncryptionResponsePacket) (err error) {
cem.sharedSecret, err = rsa.DecryptPKCS1v15(crand.Reader, cem.gem.privateKey, packet.EncryptedSharedSecret)
if err != nil {
return err
}
returnedVerifyToken, err := rsa.DecryptPKCS1v15(crand.Reader, cem.gem.privateKey, packet.EncryptedVerifyToken)
if err != nil {
return err
}
if len(cem.verifyToken) != len(returnedVerifyToken) {
return fmt.Errorf("Authentication failure")
}
var diff uint8
for i := 0; i < len(cem.verifyToken); i++ {
diff |= cem.verifyToken[i] ^ returnedVerifyToken[i]
}
if diff != 0 {
return fmt.Errorf("Authentication failure")
}
return nil
}
func (cem *clientEncryptionManager) notifyHasJoined() (err error) {
log.Printf("notifyHasJoined")
serverHash := AuthDigest(cem.gem.serverID, cem.sharedSecret, cem.gem.encodedPublicKey)
params := make(url.Values)
params.Set("username", cem.playerName)
params.Set("serverId", serverHash)
resp, err := http.Get("https://sessionserver.mojang.com/session/minecraft/hasJoined?" + params.Encode())
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 300 {
return fmt.Errorf("HTTP authentication error: %s", resp.Status)
}
var responseMessage hasJoinedResponse
dec := json.NewDecoder(resp.Body)
err = dec.Decode(&responseMessage)
if err != nil {
return err
}
cem.playerUUID = responseMessage.UUID
return nil
}
type hasJoinedResponse struct {
UUID string `json:"id"`
Properties []hasJoinedProperty `json:"properties"`
}
type hasJoinedProperty struct {
Name string `json:"name"`
Value interface{} `json:"value"`
}