parent
0c00cf583c
commit
103be213f7
|
@ -0,0 +1,68 @@
|
|||
package YHProto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var (
|
||||
algorithm = 1
|
||||
)
|
||||
|
||||
func Encrypt(plaintext []byte) ([]byte, error) {
|
||||
switch algorithm {
|
||||
case 1: // AES-128-CBC
|
||||
block, err := aes.NewCipher([]byte(echoPkgKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
paddedPlaintext := PKCS5Padding(plaintext, block.BlockSize())
|
||||
iv := make([]byte, block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
ciphertext := make([]byte, len(paddedPlaintext))
|
||||
stream.XORKeyStream(ciphertext, paddedPlaintext)
|
||||
return ciphertext, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported encryption algorithm %d", algorithm)
|
||||
}
|
||||
}
|
||||
|
||||
func Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
switch algorithm {
|
||||
case 1: // AES-128-CBC
|
||||
block, err := aes.NewCipher([]byte(echoPkgKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iv := make([]byte, block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
plaintext := make([]byte, len(ciphertext))
|
||||
stream.XORKeyStream(plaintext, ciphertext)
|
||||
return PKCS5Trimming(plaintext), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported encryption algorithm %d", algorithm)
|
||||
}
|
||||
}
|
||||
|
||||
func PKCS5Padding(data []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(data)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(data, padtext...)
|
||||
}
|
||||
|
||||
func PKCS5Trimming(data []byte) []byte {
|
||||
padding := int(data[len(data)-1])
|
||||
return data[:len(data)-padding]
|
||||
}
|
||||
|
||||
func VerifySignature(signature []byte, privateKey []byte) bool {
|
||||
// Signature verification logic goes here
|
||||
return true
|
||||
}
|
||||
|
||||
func TamperProof(body []byte) []byte {
|
||||
// Data tamper-proofing logic goes here
|
||||
return body
|
||||
}
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/gobwas/ws/wsutil"
|
||||
"github.com/panjf2000/gnet/v2"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"hash/crc32"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
@ -38,14 +39,16 @@ func (c echoCommand) String() string {
|
|||
|
||||
var (
|
||||
echoPkgMagic uint32 = 0x20160905
|
||||
maxEchoStringLen uint32 = 0xffff
|
||||
echoPkgKey string = "123456"
|
||||
maxEchoStringLen uint32 = 0xffffff // max string length 16MB
|
||||
echoPkgKey = "example key 1234"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotEnoughStream = errors.New("packet stream is not enough")
|
||||
ErrTooLargePackage = errors.New("package length is exceed the echo package's legal maximum length.")
|
||||
ErrIllegalMagic = errors.New("package magic is not right.")
|
||||
ErrTooLargePackage = errors.New("package length is exceed the echo package's legal maximum length")
|
||||
ErrIllegalMagic = errors.New("package magic is not right")
|
||||
ErrTimeOut = errors.New("数据包已过期")
|
||||
ErrCheckSum = errors.New("数据校验和失败")
|
||||
)
|
||||
|
||||
var echoPkgHeaderLen int
|
||||
|
@ -62,18 +65,12 @@ func SetEchoPkgKey(key string) {
|
|||
|
||||
type (
|
||||
// EchoPkgHeader
|
||||
// 长度20字节.SimpleCodec Protocol format:
|
||||
//
|
||||
// * 0 4 6 8 12 16 20
|
||||
// * +----------------+----------+----------+----------------+----------------+----------------+
|
||||
// * | Magic | Sequence | Command | UT | ChkSum | Len |
|
||||
// * +----------------+----------+----------+----------------+----------------+----------------+
|
||||
// * | |
|
||||
// * + +
|
||||
// * | body bytes |
|
||||
// * + +
|
||||
// * | ... ... |
|
||||
// * +-----------------------------------------------------------------------------------------+
|
||||
//* 字节位置 4 6 8 12 16 20
|
||||
//* +----------------+----------+----------+----------------+----------------+----------------+-------------------+
|
||||
//* | Magic(4) | Seq(2) | Cmd(2) | UT(4) | ChkSum(4) | Len(4) | body |
|
||||
//* +----------------+----------+----------+----------------+----------------+----------------+-------------------+
|
||||
//* | 消息头部分 | 消息体... |
|
||||
//* +----------------+----------+----------+----------------+----------------+----------------+-------------------+
|
||||
EchoPkgHeader struct {
|
||||
Magic uint32 //包头,协议版本号
|
||||
|
||||
|
@ -81,7 +78,7 @@ type (
|
|||
Command uint16 // 命令编号
|
||||
|
||||
UT uint32 // 客户端本地时间戳(秒)
|
||||
ChkSum int32 // 检验和
|
||||
ChkSum uint32 // 检验和
|
||||
|
||||
Len uint32 // 数据包长度
|
||||
}
|
||||
|
@ -96,19 +93,61 @@ func (p EchoPkgHeader) String() string {
|
|||
return fmt.Sprintf("请求ID:%d, 命令ID:%s, 数据包长度:%d",
|
||||
p.Sequence, (echoCommand(p.Command)).String(), p.Len)
|
||||
}
|
||||
func (codec *EchoPackage) VerifyTime() bool {
|
||||
// 校验消息时间戳是否过期
|
||||
return time.Now().Unix()-int64(codec.H.UT) < int64(time.Minute.Seconds()*5)
|
||||
}
|
||||
func (codec *EchoPackage) VerifyBodySize() bool {
|
||||
// 防止恶意客户端把这个字段设置过大导致服务端死等或者服务端在准备对应的缓冲区时内存崩溃
|
||||
if maxEchoStringLen < codec.H.Len {
|
||||
|
||||
}
|
||||
return maxEchoStringLen > codec.H.Len
|
||||
}
|
||||
func (codec *EchoPackage) CheckHeader() error {
|
||||
if codec.VerifyBodySize() {
|
||||
return ErrTooLargePackage
|
||||
}
|
||||
if codec.VerifyTime() {
|
||||
return ErrTimeOut
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (codec *EchoPackage) CalculateCheckSum(body []byte) uint32 {
|
||||
// 计算消息的校验和
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
binary.Write(buffer, binary.LittleEndian, codec.H.Sequence)
|
||||
binary.Write(buffer, binary.LittleEndian, codec.H.Command)
|
||||
binary.Write(buffer, binary.LittleEndian, codec.H.UT)
|
||||
buffer.Write(body)
|
||||
checkSum := crc32.ChecksumIEEE(buffer.Bytes())
|
||||
return checkSum
|
||||
}
|
||||
|
||||
// Encode 编码
|
||||
func (codec *EchoPackage) Encode() ([]byte, error) {
|
||||
|
||||
codec.H.Magic = echoPkgMagic
|
||||
codec.H.UT = uint32(time.Now().Unix())
|
||||
buf := &bytes.Buffer{}
|
||||
codec.H.Len = uint32(len(codec.B))
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
err := binary.Write(buf, binary.LittleEndian, codec.H)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf.Write(codec.B)
|
||||
|
||||
//加密body
|
||||
encryptedBody, err := Encrypt(codec.B)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
codec.H.Len = uint32(len(codec.B))
|
||||
|
||||
//计算校验和
|
||||
codec.H.ChkSum = codec.CalculateCheckSum(encryptedBody)
|
||||
|
||||
buf.Write(encryptedBody)
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
|
@ -127,20 +166,28 @@ func (codec *EchoPackage) DecodeBuffer(msg []byte) (err error) {
|
|||
codec.H.Sequence = binary.LittleEndian.Uint16(hBuf[4:6])
|
||||
codec.H.Command = binary.LittleEndian.Uint16(hBuf[6:8])
|
||||
codec.H.UT = binary.LittleEndian.Uint32(hBuf[8:12])
|
||||
codec.H.ChkSum = int32(binary.LittleEndian.Uint32(hBuf[12:16]))
|
||||
codec.H.ChkSum = binary.LittleEndian.Uint32(hBuf[12:16])
|
||||
codec.H.Len = binary.LittleEndian.Uint32(hBuf[16:20])
|
||||
|
||||
// 防止恶意客户端把这个字段设置过大导致服务端死等或者服务端在准备对应的缓冲区时内存崩溃
|
||||
if maxEchoStringLen < codec.H.Len {
|
||||
return ErrTooLargePackage
|
||||
err = codec.CheckHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(msg)-echoPkgHeaderLen < int(codec.H.Len) {
|
||||
return ErrNotEnoughStream
|
||||
body := msg[echoPkgHeaderLen : echoPkgHeaderLen+int(codec.H.Len)]
|
||||
|
||||
// 校验和验证
|
||||
checkSum := codec.CalculateCheckSum(body)
|
||||
if checkSum != codec.H.ChkSum {
|
||||
return ErrCheckSum
|
||||
}
|
||||
|
||||
codec.B = make([]byte, codec.H.Len)
|
||||
copy(codec.B, msg[echoPkgHeaderLen:echoPkgHeaderLen+int(codec.H.Len)])
|
||||
//解密
|
||||
codec.B, err = Decrypt(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -159,7 +206,7 @@ func (codec *EchoPackage) DecodeGnet(c gnet.Conn) (err error) {
|
|||
codec.H.Sequence = binary.LittleEndian.Uint16(hBuf[4:6])
|
||||
codec.H.Command = binary.LittleEndian.Uint16(hBuf[6:8])
|
||||
codec.H.UT = binary.LittleEndian.Uint32(hBuf[8:12])
|
||||
codec.H.ChkSum = int32(binary.LittleEndian.Uint32(hBuf[12:16]))
|
||||
codec.H.ChkSum = binary.LittleEndian.Uint32(hBuf[12:16])
|
||||
codec.H.Len = binary.LittleEndian.Uint32(hBuf[16:20])
|
||||
|
||||
// 防止恶意客户端把这个字段设置过大导致服务端死等或者服务端在准备对应的缓冲区时内存崩溃
|
||||
|
@ -195,7 +242,7 @@ func (codec *EchoPackage) DecodeWsMessage(msg wsutil.Message) (err error) {
|
|||
codec.H.Sequence = binary.LittleEndian.Uint16(hBuf[4:6])
|
||||
codec.H.Command = binary.LittleEndian.Uint16(hBuf[6:8])
|
||||
codec.H.UT = binary.LittleEndian.Uint32(hBuf[8:12])
|
||||
codec.H.ChkSum = int32(binary.LittleEndian.Uint32(hBuf[12:16]))
|
||||
codec.H.ChkSum = binary.LittleEndian.Uint32(hBuf[12:16])
|
||||
codec.H.Len = binary.LittleEndian.Uint32(hBuf[16:20])
|
||||
|
||||
// 防止恶意客户端把这个字段设置过大导致服务端死等或者服务端在准备对应的缓冲区时内存崩溃
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module git.yhrjkj.com/YuanHong/YHEchoPackage
|
||||
|
||||
go 1.20
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gobwas/ws v1.1.0
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<!-- TOC -->
|
||||
* [结构](#结构)
|
||||
* [Body 加密、解密](#body-加密解密)
|
||||
* [过程](#过程)
|
||||
* [ChkSum:](#chksum)
|
||||
<!-- TOC -->
|
||||
|
||||
|
||||
# 结构
|
||||
![](/home/mic/Pictures/Screenshots/截图_选择区域_20230426173011.png)
|
||||
|
||||
消息结构由两部分组成即消息头和消息体。消息头大小固定20个字节,在解析数据流时先读取20个字节,解析出消息头数据后再读取Body数据。
|
||||
|
||||
| 参数 | 字节书(byte) | 说明 |
|
||||
| ----- | ---- |----------------------|
|
||||
| Magic | 4 | 协议头,固定值,由服务端提供 |
|
||||
| Seq | 2 | 请求编号。返回数据时系统会并带上请求编号 |
|
||||
| Cmd | 2 | 消息命令ID |
|
||||
| UT | 4 | Unix时间戳,精确到秒 |
|
||||
| ChkSum | 4 | 校验和 |
|
||||
| Len | 4 | body的长度 |
|
||||
| Body | 不固定 | 加密的body数据 |
|
||||
|
||||
---
|
||||
## Body 加密、解密
|
||||
- 算法:AES-128-CBC
|
||||
- key:`example key 1234`(正式环境另外提供)。
|
||||
#### 过程
|
||||
|
||||
## ChkSum:
|
||||
- 算法:CRC-32校验和,使用IEEE多项式。
|
||||
>说明:将Seq、Cmd、UT、body(加密后)按顺序写入buffer后,通过CRC-32计算校验和。
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue