nex-go/hpp_packet.go
Daniel López Guimaraes a97e9e6b19
Add getter for PasswordFromPIDFunction
This allows the common authentication protocol to reuse this function
and avoid confusion.
2023-04-23 18:05:19 +01:00

119 lines
3.1 KiB
Go

package nex
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"encoding/hex"
"errors"
)
// HPPPacket represents an HPP packet
type HPPPacket struct {
Packet
accessKeySignature []byte
passwordSignature []byte
}
// SetAccessKeySignature sets the packet access key signature
func (packet *HPPPacket) SetAccessKeySignature(accessKeySignature string) {
accessKeySignatureBytes, err := hex.DecodeString(accessKeySignature)
if err != nil {
logger.Error("[HPP] Failed to convert AccessKeySignature to bytes")
}
packet.accessKeySignature = accessKeySignatureBytes
}
// AccessKeySignature returns the packet access key signature
func (packet *HPPPacket) AccessKeySignature() []byte {
return packet.accessKeySignature
}
// SetPasswordSignature sets the packet password signature
func (packet *HPPPacket) SetPasswordSignature(passwordSignature string) {
passwordSignatureBytes, err := hex.DecodeString(passwordSignature)
if err != nil {
logger.Error("[HPP] Failed to convert PasswordSignature to bytes")
}
packet.passwordSignature = passwordSignatureBytes
}
// PasswordSignature returns the packet password signature
func (packet *HPPPacket) PasswordSignature() []byte {
return packet.passwordSignature
}
// ValidateAccessKey checks if the access key signature is valid
func (packet *HPPPacket) ValidateAccessKey() error {
accessKey := packet.Sender().Server().AccessKey()
buffer := packet.rmcRequest.Bytes()
accessKeyBytes, err := hex.DecodeString(accessKey)
if err != nil {
return err
}
calculatedAccessKeySignature := packet.calculateSignature(buffer, accessKeyBytes)
if !bytes.Equal(calculatedAccessKeySignature, packet.accessKeySignature) {
return errors.New("[HPP] Access key signature is not valid")
}
return nil
}
// ValidatePassword checks if the password signature is valid
func (packet *HPPPacket) ValidatePassword() error {
if packet.sender.server.passwordFromPIDHandler == nil {
return errors.New("[HPP] Missing passwordFromPIDHandler!")
}
pid := packet.Sender().PID()
buffer := packet.rmcRequest.Bytes()
password, _ := packet.sender.server.passwordFromPIDHandler(pid)
if password == "" {
return errors.New("[HPP] PID does not exist")
}
passwordBytes := []byte(password)
passwordSignatureKey := DeriveKerberosKey(pid, passwordBytes)
calculatedPasswordSignature := packet.calculateSignature(buffer, passwordSignatureKey)
if !bytes.Equal(calculatedPasswordSignature, packet.passwordSignature) {
return errors.New("[HPP] Password signature is invalid")
}
return nil
}
func (packet *HPPPacket) calculateSignature(buffer []byte, key []byte) []byte {
mac := hmac.New(md5.New, key)
mac.Write(buffer)
hmac := mac.Sum(nil)
return hmac
}
// NewHPPPacket returns a new HPP packet
func NewHPPPacket(client *Client, data []byte) (*HPPPacket, error) {
packet := NewPacket(client, data)
hppPacket := HPPPacket{Packet: packet}
if data != nil {
hppPacket.payload = data
rmcRequest := NewRMCRequest()
err := rmcRequest.FromBytes(data)
if err != nil {
return &HPPPacket{}, errors.New("[HPP] Error parsing RMC request: " + err.Error())
}
hppPacket.rmcRequest = rmcRequest
}
return &hppPacket, nil
}