Commit b499527ee6af3c7e6f65586cf765161f8f0da537
1 parent
d3faacd0
feat: 消息包用aes加密
Showing
8 changed files
with
254 additions
and
93 deletions
Show diff stats
cmd/gameserver/game.go
... | ... | @@ -9,6 +9,7 @@ import ( |
9 | 9 | "pro2d/common/components" |
10 | 10 | "pro2d/common/db/mongoproxy" |
11 | 11 | "pro2d/common/db/redisproxy" |
12 | + "pro2d/common/logger" | |
12 | 13 | "pro2d/models" |
13 | 14 | "time" |
14 | 15 | |
... | ... | @@ -25,12 +26,19 @@ func NewGameServer(sconf *common.SConf) (*GameServer, error) { |
25 | 26 | |
26 | 27 | options := []components.ServerOption{ |
27 | 28 | components.WithPlugin(components.NewPlugin(sconf.PluginPath)), |
28 | - components.WithSplitter(components.NewPBSplitter()), | |
29 | + | |
29 | 30 | components.WithConnCbk(s.OnConnection), |
30 | 31 | components.WithMsgCbk(s.OnMessage), |
31 | 32 | components.WithCloseCbk(s.OnClose), |
32 | 33 | components.WithTimerCbk(s.OnTimer), |
33 | 34 | } |
35 | + //加密 | |
36 | + if sconf.Encipher { | |
37 | + options = append(options, components.WithSplitter(components.NewPBSplitter(components.NewAesEncipher()))) | |
38 | + logger.Debug("open encipher aes...") | |
39 | + } else { | |
40 | + options = append(options, components.WithSplitter(components.NewPBSplitter(nil))) | |
41 | + } | |
34 | 42 | |
35 | 43 | iserver := components.NewServer(sconf.Port, options...) |
36 | 44 | iserver.SetActions(action.GetActionMap()) | ... | ... |
cmd/test/client.go
... | ... | @@ -19,14 +19,14 @@ func main() { |
19 | 19 | } |
20 | 20 | |
21 | 21 | loginReq := &pb.LoginReq{ |
22 | - Token: "141815055745814528", | |
22 | + Token: "141815055745814528", | |
23 | 23 | Device: "123123", |
24 | 24 | } |
25 | - l, _ :=proto.Marshal(loginReq) | |
25 | + l, _ := proto.Marshal(loginReq) | |
26 | 26 | |
27 | 27 | options := []components.ConnectorOption{ |
28 | 28 | components.WithCtorCount(common.GlobalConf.TestClient.Count), |
29 | - components.WithCtorSplitter(components.NewPBSplitter()), | |
29 | + components.WithCtorSplitter(components.NewPBSplitter(nil)), | |
30 | 30 | } |
31 | 31 | |
32 | 32 | client := components.NewConnector(common.GlobalConf.TestClient.Ip, common.GlobalConf.TestClient.Port, options...) |
... | ... | @@ -35,8 +35,8 @@ func main() { |
35 | 35 | return |
36 | 36 | } |
37 | 37 | |
38 | - for { | |
38 | + for { | |
39 | 39 | client.Send(head.Cmd, l) |
40 | - time.Sleep(1*time.Second) | |
40 | + time.Sleep(1 * time.Second) | |
41 | 41 | } |
42 | -} | |
43 | 42 | \ No newline at end of file |
43 | +} | ... | ... |
... | ... | @@ -0,0 +1,108 @@ |
1 | +package components | |
2 | + | |
3 | +import ( | |
4 | + "bytes" | |
5 | + "crypto/aes" | |
6 | + "crypto/cipher" | |
7 | + "encoding/base64" | |
8 | + "errors" | |
9 | +) | |
10 | + | |
11 | +var ( | |
12 | + PwdKey = []byte("luluszhaozhaoAAA") //RC4 zhaolu2333 | |
13 | +) | |
14 | + | |
15 | +type AesEncipher struct { | |
16 | +} | |
17 | + | |
18 | +func NewAesEncipher() IEncipher { | |
19 | + return &AesEncipher{} | |
20 | +} | |
21 | + | |
22 | +//pkcs7Padding 填充 | |
23 | +func (a *AesEncipher) pkcs7Padding(data []byte, blockSize int) []byte { | |
24 | + //判断缺少几位长度。最少1,最多 blockSize | |
25 | + padding := blockSize - len(data)%blockSize | |
26 | + //补足位数。把切片[]byte{byte(padding)}复制padding个 | |
27 | + padText := bytes.Repeat([]byte{byte(padding)}, padding) | |
28 | + return append(data, padText...) | |
29 | +} | |
30 | + | |
31 | +//pkcs7UnPadding 填充的反向操作 | |
32 | +func (a *AesEncipher) pkcs7UnPadding(data []byte) ([]byte, error) { | |
33 | + length := len(data) | |
34 | + if length == 0 { | |
35 | + return nil, errors.New("加密字符串错误!") | |
36 | + } | |
37 | + //获取填充的个数 | |
38 | + unPadding := int(data[length-1]) | |
39 | + return data[:(length - unPadding)], nil | |
40 | +} | |
41 | + | |
42 | +//AesEncrypt 加密 | |
43 | +func (a *AesEncipher) Encrypt(data []byte) ([]byte, error) { | |
44 | + //创建加密实例 | |
45 | + block, err := aes.NewCipher(PwdKey) | |
46 | + if err != nil { | |
47 | + return nil, err | |
48 | + } | |
49 | + //判断加密快的大小 | |
50 | + blockSize := block.BlockSize() | |
51 | + //填充 | |
52 | + encryptBytes := a.pkcs7Padding(data, blockSize) | |
53 | + if len(encryptBytes)%blockSize != 0 { | |
54 | + return nil, errors.New("crypto/cipher: input not full blocks") | |
55 | + } | |
56 | + //初始化加密数据接收切片 | |
57 | + crypted := make([]byte, len(encryptBytes)) | |
58 | + //使用cbc加密模式 | |
59 | + blockMode := cipher.NewCBCEncrypter(block, PwdKey[:blockSize]) | |
60 | + //执行加密 | |
61 | + blockMode.CryptBlocks(crypted, encryptBytes) | |
62 | + return crypted, nil | |
63 | +} | |
64 | + | |
65 | +//AesDecrypt 解密 | |
66 | +func (a *AesEncipher) Decrypt(data []byte) ([]byte, error) { | |
67 | + //创建实例 | |
68 | + block, err := aes.NewCipher(PwdKey) | |
69 | + if err != nil { | |
70 | + return nil, err | |
71 | + } | |
72 | + //获取块的大小 | |
73 | + blockSize := block.BlockSize() | |
74 | + //使用cbc | |
75 | + blockMode := cipher.NewCBCDecrypter(block, PwdKey[:blockSize]) | |
76 | + //初始化解密数据接收切片 | |
77 | + dataLen := len(data) | |
78 | + if dataLen%blockSize != 0 { | |
79 | + return nil, errors.New("crypto/cipher: input not full blocks") | |
80 | + } | |
81 | + crypted := make([]byte, dataLen) | |
82 | + //执行解密 | |
83 | + blockMode.CryptBlocks(crypted, data) | |
84 | + //去除填充 | |
85 | + crypted, err = a.pkcs7UnPadding(crypted) | |
86 | + if err != nil { | |
87 | + return nil, err | |
88 | + } | |
89 | + return crypted, nil | |
90 | +} | |
91 | + | |
92 | +//EncryptByAes Aes加密 后 base64 再加 | |
93 | +func (a *AesEncipher) EncryptByAes(data []byte) (string, error) { | |
94 | + res, err := a.Encrypt(data) | |
95 | + if err != nil { | |
96 | + return "", err | |
97 | + } | |
98 | + return base64.StdEncoding.EncodeToString(res), nil | |
99 | +} | |
100 | + | |
101 | +//DecryptByAes Aes 解密 | |
102 | +func (a *AesEncipher) DecryptByAes(data string) ([]byte, error) { | |
103 | + dataByte, err := base64.StdEncoding.DecodeString(data) | |
104 | + if err != nil { | |
105 | + return nil, err | |
106 | + } | |
107 | + return a.Decrypt(dataByte) | |
108 | +} | ... | ... |
common/components/icompontents.go
... | ... | @@ -31,6 +31,12 @@ type ( |
31 | 31 | ParseMsg(data []byte, atEOF bool) (advance int, token []byte, err error) |
32 | 32 | GetHeadLen() uint32 |
33 | 33 | } |
34 | + //加解密 | |
35 | + IEncipher interface { | |
36 | + Encrypt([]byte) ([]byte, error) | |
37 | + Decrypt([]byte) ([]byte, error) | |
38 | + } | |
39 | + | |
34 | 40 | ConnectionCallback func(IConnection) |
35 | 41 | CloseCallback func(IConnection) |
36 | 42 | MessageCallback func(IMessage) |
... | ... | @@ -127,7 +133,7 @@ type ( |
127 | 133 | |
128 | 134 | SetProperty(key string, val interface{}) |
129 | 135 | SetProperties(properties map[string]interface{}) |
130 | - ParseFields(message protoreflect.Message ,properties map[string]interface{}) []int32 | |
136 | + ParseFields(message protoreflect.Message, properties map[string]interface{}) []int32 | |
131 | 137 | } |
132 | 138 | ) |
133 | 139 | ... | ... |
common/components/pbsplitter.go
... | ... | @@ -8,10 +8,10 @@ import ( |
8 | 8 | ) |
9 | 9 | |
10 | 10 | type PBHead struct { |
11 | - Length uint32 | |
12 | - Cmd uint32 | |
13 | - ErrCode int32 | |
14 | - PreField uint32 | |
11 | + Length uint32 | |
12 | + Cmd uint32 | |
13 | + ErrCode int32 | |
14 | + PreField uint32 | |
15 | 15 | } |
16 | 16 | |
17 | 17 | func (h *PBHead) GetDataLen() uint32 { |
... | ... | @@ -38,12 +38,11 @@ type PBMessage struct { |
38 | 38 | conn IConnection |
39 | 39 | } |
40 | 40 | |
41 | - | |
42 | 41 | func (m *PBMessage) GetHeader() IHead { |
43 | 42 | return m.Head |
44 | 43 | } |
45 | 44 | |
46 | -func (m *PBMessage) SetHeader(header IHead) { | |
45 | +func (m *PBMessage) SetHeader(header IHead) { | |
47 | 46 | m.Head = header |
48 | 47 | } |
49 | 48 | func (m *PBMessage) GetData() []byte { |
... | ... | @@ -62,31 +61,21 @@ func (m *PBMessage) GetSession() IConnection { |
62 | 61 | return m.conn |
63 | 62 | } |
64 | 63 | |
64 | +type PBSplitter struct { | |
65 | + encipher IEncipher | |
66 | +} | |
65 | 67 | |
66 | -type PBSplitter struct {} | |
67 | - | |
68 | -func NewPBSplitter() *PBSplitter { | |
69 | - return &PBSplitter{} | |
68 | +func NewPBSplitter(encipher IEncipher) ISplitter { | |
69 | + return &PBSplitter{ | |
70 | + encipher, | |
71 | + } | |
70 | 72 | } |
71 | 73 | |
72 | 74 | func (m *PBSplitter) GetHeadLen() uint32 { |
73 | 75 | return uint32(binary.Size(PBHead{})) |
74 | 76 | } |
75 | 77 | |
76 | -func (m *PBSplitter) UnPack(data []byte) (IMessage,error) { | |
77 | - h := &PBHead{} | |
78 | - err := binary.Read(bytes.NewReader(data), binary.BigEndian, h) | |
79 | - if err != nil { | |
80 | - return nil, err | |
81 | - } | |
82 | - | |
83 | - return &PBMessage{ | |
84 | - Head: h, | |
85 | - Body: data[m.GetHeadLen():], | |
86 | - },nil | |
87 | -} | |
88 | - | |
89 | -func (m *PBSplitter) ParseMsg (data []byte, atEOF bool) (advance int, token []byte, err error) { | |
78 | +func (m *PBSplitter) ParseMsg(data []byte, atEOF bool) (advance int, token []byte, err error) { | |
90 | 79 | // 表示我们已经扫描到结尾了 |
91 | 80 | if atEOF && len(data) == 0 { |
92 | 81 | return 0, nil, nil |
... | ... | @@ -102,9 +91,9 @@ func (m *PBSplitter) ParseMsg (data []byte, atEOF bool) (advance int, token []by |
102 | 91 | return 0, nil, fmt.Errorf("length exceeds maximum length") |
103 | 92 | } |
104 | 93 | if int(length) <= len(data) { |
105 | - return int(length) , data[:int(length)], nil | |
94 | + return int(length), data[:int(length)], nil | |
106 | 95 | } |
107 | - return 0 , nil, nil | |
96 | + return 0, nil, nil | |
108 | 97 | } |
109 | 98 | if atEOF { |
110 | 99 | return len(data), data, nil |
... | ... | @@ -115,20 +104,56 @@ func (m *PBSplitter) ParseMsg (data []byte, atEOF bool) (advance int, token []by |
115 | 104 | func (m *PBSplitter) Pack(cmd uint32, data []byte, errcode int32, preserve uint32) ([]byte, error) { |
116 | 105 | buf := &bytes.Buffer{} |
117 | 106 | h := &PBHead{ |
118 | - Length: m.GetHeadLen()+ uint32(len(data)), | |
107 | + Length: m.GetHeadLen(), | |
119 | 108 | Cmd: cmd, |
120 | 109 | ErrCode: errcode, |
121 | 110 | PreField: preserve, |
122 | 111 | } |
123 | - err := binary.Write(buf, binary.BigEndian, h) | |
112 | + var dataEn []byte | |
113 | + var err error | |
114 | + if m.encipher != nil { | |
115 | + dataEn, err = m.encipher.Encrypt(data) | |
116 | + if err != nil { | |
117 | + return nil, err | |
118 | + } | |
119 | + } else { | |
120 | + dataEn = data | |
121 | + } | |
122 | + | |
123 | + h.Length += uint32(len(dataEn)) | |
124 | + | |
125 | + err = binary.Write(buf, binary.BigEndian, h) | |
124 | 126 | if err != nil { |
125 | 127 | return nil, err |
126 | 128 | } |
127 | 129 | |
128 | - err = binary.Write(buf, binary.BigEndian, data) | |
130 | + err = binary.Write(buf, binary.BigEndian, dataEn) | |
129 | 131 | if err != nil { |
130 | 132 | return nil, err |
131 | 133 | } |
132 | 134 | |
133 | 135 | return buf.Bytes(), nil |
134 | -} | |
135 | 136 | \ No newline at end of file |
137 | +} | |
138 | + | |
139 | +func (m *PBSplitter) UnPack(data []byte) (IMessage, error) { | |
140 | + h := &PBHead{} | |
141 | + err := binary.Read(bytes.NewReader(data), binary.BigEndian, h) | |
142 | + if err != nil { | |
143 | + return nil, err | |
144 | + } | |
145 | + | |
146 | + var dataDe []byte | |
147 | + if m.encipher != nil { | |
148 | + dataDe, err = m.encipher.Decrypt(data[m.GetHeadLen():]) | |
149 | + if err != nil { | |
150 | + return nil, err | |
151 | + } | |
152 | + } else { | |
153 | + dataDe = data[m.GetHeadLen():] | |
154 | + } | |
155 | + | |
156 | + return &PBMessage{ | |
157 | + Head: h, | |
158 | + Body: dataDe, | |
159 | + }, nil | |
160 | +} | ... | ... |
common/components/timewheel_test.go
... | ... | @@ -6,13 +6,25 @@ import ( |
6 | 6 | "time" |
7 | 7 | ) |
8 | 8 | |
9 | -func PRINT() { | |
9 | +func PRINT() { | |
10 | 10 | fmt.Println("12312312312") |
11 | 11 | } |
12 | 12 | |
13 | 13 | func TestTimeWheel_Start(t *testing.T) { |
14 | - TimeOut(1 * time.Second, func() { | |
14 | + TimeOut(1*time.Second, func() { | |
15 | 15 | fmt.Println("12312313123") |
16 | 16 | }) |
17 | - select{} | |
17 | + select {} | |
18 | +} | |
19 | + | |
20 | +func TestAesEncipher_Decrypt(t *testing.T) { | |
21 | + aes := AesEncipher{} | |
22 | + encode, err := aes.Encrypt([]byte("123")) | |
23 | + if err != nil { | |
24 | + fmt.Println(err.Error()) | |
25 | + return | |
26 | + } | |
27 | + | |
28 | + dec, err := aes.Decrypt(encode) | |
29 | + fmt.Printf("%s\n", dec) | |
18 | 30 | } | ... | ... |
common/conf.go
... | ... | @@ -12,86 +12,87 @@ import ( |
12 | 12 | |
13 | 13 | type RedisConf struct { |
14 | 14 | Address string `json:"address"` |
15 | - Auth string `json:"auth"` | |
16 | - DB int `json:"db"` | |
15 | + Auth string `json:"auth"` | |
16 | + DB int `json:"db"` | |
17 | 17 | } |
18 | 18 | |
19 | 19 | type Etcd struct { |
20 | - Endpoints []string `json:"endpoints"` | |
21 | - DialTimeout int `json:"dialtimeout"` | |
20 | + Endpoints []string `json:"endpoints"` | |
21 | + DialTimeout int `json:"dialtimeout"` | |
22 | 22 | } |
23 | 23 | |
24 | 24 | type MongoConf struct { |
25 | - User string `yaml:"user"` | |
26 | - Password string `yaml:"password"` | |
27 | - Host string `yaml:"host"` | |
28 | - Port int `yaml:"port"` | |
29 | - TimeOut int `yaml:"timeout"` | |
30 | - MaxNum int `yaml:"maxnum"` | |
31 | - DBName string `yaml:"dbname"` | |
25 | + User string `yaml:"user"` | |
26 | + Password string `yaml:"password"` | |
27 | + Host string `yaml:"host"` | |
28 | + Port int `yaml:"port"` | |
29 | + TimeOut int `yaml:"timeout"` | |
30 | + MaxNum int `yaml:"maxnum"` | |
31 | + DBName string `yaml:"dbname"` | |
32 | 32 | } |
33 | 33 | |
34 | 34 | type SConf struct { |
35 | - ID string `yaml:"id"` | |
36 | - Name string `yaml:"name"` | |
37 | - IP string `yaml:"ip"` | |
38 | - Port int `yaml:"port"` | |
39 | - DebugPort int `yaml:"debugport"` | |
40 | - MongoConf *MongoConf `yaml:"mongo"` | |
41 | - RedisConf *RedisConf `yaml:"redis"` | |
42 | - WorkerPoolSize int `yaml:"pool_size"` | |
43 | - PluginPath string `yaml:"plugin_path"` | |
35 | + ID string `yaml:"id"` | |
36 | + Name string `yaml:"name"` | |
37 | + IP string `yaml:"ip"` | |
38 | + Port int `yaml:"port"` | |
39 | + Encipher bool `yaml:"encipher"` | |
40 | + DebugPort int `yaml:"debugport"` | |
41 | + MongoConf *MongoConf `yaml:"mongo"` | |
42 | + RedisConf *RedisConf `yaml:"redis"` | |
43 | + WorkerPoolSize int `yaml:"pool_size"` | |
44 | + PluginPath string `yaml:"plugin_path"` | |
44 | 45 | } |
45 | 46 | |
46 | 47 | type LogConsole struct { |
47 | - Level string `yaml:"level" json:"level"` | |
48 | - Color bool `yaml:"color" json:"color"` | |
48 | + Level string `yaml:"level" json:"level"` | |
49 | + Color bool `yaml:"color" json:"color"` | |
49 | 50 | } |
50 | 51 | |
51 | 52 | type LogFile struct { |
52 | - Level string `yaml:"level" json:"level"` | |
53 | - Daily bool `yaml:"daily" json:"daily"` | |
54 | - Maxlines int `yaml:"maxlines" json:"maxlines"` | |
55 | - Maxsize int `yaml:"maxsize" json:"maxsize"` | |
56 | - Maxdays int `yaml:"maxdays" json:"maxdays"` | |
57 | - Append bool `yaml:"append" json:"append"` | |
58 | - Permit string `yaml:"permit" json:"permit"` | |
53 | + Level string `yaml:"level" json:"level"` | |
54 | + Daily bool `yaml:"daily" json:"daily"` | |
55 | + Maxlines int `yaml:"maxlines" json:"maxlines"` | |
56 | + Maxsize int `yaml:"maxsize" json:"maxsize"` | |
57 | + Maxdays int `yaml:"maxdays" json:"maxdays"` | |
58 | + Append bool `yaml:"append" json:"append"` | |
59 | + Permit string `yaml:"permit" json:"permit"` | |
59 | 60 | } |
60 | 61 | |
61 | 62 | type LogConn struct { |
62 | - Net string `yaml:"net" json:"net"` | |
63 | - Addr string `yaml:"addr" json:"addr"` | |
64 | - Level string `yaml:"level" json:"level"` | |
65 | - Reconnect bool `yaml:"reconnect" json:"reconnect"` | |
66 | - ReconnectOnMsg bool `yaml:"reconnectOnMsg" json:"reconnectOnMsg"` | |
63 | + Net string `yaml:"net" json:"net"` | |
64 | + Addr string `yaml:"addr" json:"addr"` | |
65 | + Level string `yaml:"level" json:"level"` | |
66 | + Reconnect bool `yaml:"reconnect" json:"reconnect"` | |
67 | + ReconnectOnMsg bool `yaml:"reconnectOnMsg" json:"reconnectOnMsg"` | |
67 | 68 | } |
68 | 69 | |
69 | 70 | type LogConf struct { |
70 | - TimeFormat string `yaml:"TimeFormat" json:"TimeFormat"` | |
71 | - LogConsole *LogConsole `yaml:"Console" json:"Console"` | |
72 | - LogFile *LogFile `yaml:"File" json:"File"` | |
73 | - LogConn *LogConn `yaml:"Conn" json:"Conn"` | |
71 | + TimeFormat string `yaml:"TimeFormat" json:"TimeFormat"` | |
72 | + LogConsole *LogConsole `yaml:"Console" json:"Console"` | |
73 | + LogFile *LogFile `yaml:"File" json:"File"` | |
74 | + LogConn *LogConn `yaml:"Conn" json:"Conn"` | |
74 | 75 | } |
75 | 76 | |
76 | 77 | type TestClient struct { |
77 | - Ip string `yaml:"ip"` | |
78 | - Port int`yaml:"port"` | |
79 | - Count int `yaml:"count"` | |
78 | + Ip string `yaml:"ip"` | |
79 | + Port int `yaml:"port"` | |
80 | + Count int `yaml:"count"` | |
80 | 81 | } |
81 | 82 | |
82 | 83 | type ServerConf struct { |
83 | - ID string `yaml:"id"` | |
84 | - Name string `yaml:"name"` | |
85 | - WorkerID int64 `yaml:"workerid"` | |
86 | - DatacenterID int64 `yaml:"datacenterid"` | |
87 | - AccountConf *SConf `yaml:"server_account"` | |
88 | - GameConf *SConf `yaml:"server_game"` | |
89 | - LogConf *LogConf `yaml:"logconf" json:"logconf"` | |
90 | - TestClient *TestClient `yaml:"test_client"` | |
91 | - Etcd *Etcd `yaml:"etcd"` | |
84 | + ID string `yaml:"id"` | |
85 | + Name string `yaml:"name"` | |
86 | + WorkerID int64 `yaml:"workerid"` | |
87 | + DatacenterID int64 `yaml:"datacenterid"` | |
88 | + AccountConf *SConf `yaml:"server_account"` | |
89 | + GameConf *SConf `yaml:"server_game"` | |
90 | + LogConf *LogConf `yaml:"logconf" json:"logconf"` | |
91 | + TestClient *TestClient `yaml:"test_client"` | |
92 | + Etcd *Etcd `yaml:"etcd"` | |
92 | 93 | } |
93 | 94 | |
94 | -var( | |
95 | +var ( | |
95 | 96 | GlobalConf ServerConf |
96 | 97 | SnowFlack *snow.Snowflake |
97 | 98 | ) |
... | ... | @@ -122,4 +123,4 @@ func init() { |
122 | 123 | |
123 | 124 | //初始化雪花算法 |
124 | 125 | SnowFlack = snow.NewSnowflake(GlobalConf.WorkerID, GlobalConf.DatacenterID) |
125 | -} | |
126 | 126 | \ No newline at end of file |
127 | +} | ... | ... |