Files
Erupe/network/crypt_conn.go
Andrew Gutekanst 96ec589651 Initial commit
2019-12-19 21:53:28 +09:00

79 lines
2.3 KiB
Go

package network
import (
"errors"
"fmt"
"io"
"net"
"github.com/Andoryuuta/Erupe/network/crypto"
)
// CryptConn represents a MHF encrypted two-way connection,
// it automatically handles encryption, decryption, and key rotation via it's methods.
type CryptConn struct {
conn net.Conn
readKeyRot uint32
sendKeyRot uint32
sentPackets int32
prevSendPacketCombinedCheck uint16
}
// NewCryptConn creates a new CryptConn with proper default values.
func NewCryptConn(conn net.Conn) *CryptConn {
cc := &CryptConn{
conn: conn,
readKeyRot: 995117,
sendKeyRot: 995117,
sentPackets: 0,
prevSendPacketCombinedCheck: 0,
}
return cc
}
// ReadPacket reads an packet from the connection and returns the decrypted data.
func (cc *CryptConn) ReadPacket() ([]byte, error) {
// Read the raw 14 byte header.
headerData := make([]byte, CryptPacketHeaderLength)
_, err := io.ReadFull(cc.conn, headerData)
if err != nil {
return nil, err
}
//fmt.Printf("Header: %s\n", hex.Dump(headerData))
// Parse the data into a usable struct.
cph, err := NewCryptPacketHeader(headerData)
if err != nil {
return nil, err
}
// Now read the encrypted packet body after getting its size from the header.
encryptedPacketBody := make([]byte, cph.DataSize)
_, err = io.ReadFull(cc.conn, encryptedPacketBody)
if err != nil {
return nil, err
}
// Update the key rotation before decrypting.
if cph.KeyRotDelta != 0 {
cc.readKeyRot = (uint32(cph.KeyRotDelta) * (cc.readKeyRot + 1))
}
out, combinedCheck, check0, check1, check2 := crypto.Decrypt(encryptedPacketBody, cc.readKeyRot, nil)
if cph.Check0 != check0 || cph.Check1 != check1 || cph.Check2 != check2 {
fmt.Printf("got c0 %X, c1 %X, c2 %X\n", check0, check1, check2)
fmt.Printf("want c0 %X, c1 %X, c2 %X\n", cph.Check0, cph.Check1, cph.Check2)
return nil, errors.New("decrypted data checksum doesn't match header")
}
_ = combinedCheck
/*
fmt.Printf("cc %X, c0 %X, c1 %X, c2 %X\n", combinedCheck, check0, check1, check2)
fmt.Printf("cc %X, c0 %X, c1 %X, c2 %X\n", cph.PrevPacketCombinedCheck, cph.Check0, cph.Check1, cph.Check2)
fmt.Printf("cph: %+v\n", cph)
*/
return out, nil
}