添加加密逻辑

master v0.0.21
章传马 2023-04-26 18:12:43 +08:00
parent 0c00cf583c
commit 103be213f7
19 changed files with 180 additions and 30 deletions

68
YHProto/enc.go 100644
View File

@ -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
}

105
YHProto/protocol.go 100644 → 100755
View File

@ -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])
// 防止恶意客户端把这个字段设置过大导致服务端死等或者服务端在准备对应的缓冲区时内存崩溃

0
define/define.go 100644 → 100755
View File

2
go.mod 100644 → 100755
View File

@ -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
tcp/config.go 100644 → 100755
View File

0
tcp/engine.go 100644 → 100755
View File

0
tcp/gnetserver.go 100644 → 100755
View File

0
tcp/internal/server.go 100644 → 100755
View File

0
tcp/server.go 100644 → 100755
View File

0
tcp/types.go 100644 → 100755
View File

0
ws/codec.go 100644 → 100755
View File

0
ws/config.go 100644 → 100755
View File

0
ws/engine.go 100644 → 100755
View File

0
ws/gnetserver.go 100644 → 100755
View File

0
ws/helper.go 100644 → 100755
View File

0
ws/internal/server.go 100644 → 100755
View File

0
ws/server.go 100644 → 100755
View File

0
ws/types.go 100644 → 100755
View File

35
消息结构.md 100644
View File

@ -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计算校验和。