Mining/pkg/ueps/reader.go
Claude 61c45810ba
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run
ax(ueps): rename header to packetHeader for AX Principle 1 compliance
Generic name `header` replaced with `packetHeader` throughout ReadAndVerify
to satisfy AX predictable-names-over-short-names; the name now conveys what
is being built without requiring context from the surrounding function.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-02 14:01:08 +01:00

114 lines
3.3 KiB
Go

package ueps
import (
"bufio"
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/binary"
"io"
)
// packet, err := ReadAndVerify(bufio.NewReader(conn), secret)
// if err == errMissingHMAC { /* no HMAC tag found in frame */ }
var errMissingHMAC = sentinelError("UEPS packet missing HMAC signature")
// packet, err := ReadAndVerify(bufio.NewReader(conn), wrongSecret)
// if err == errIntegrityViolation { header.ThreatScore += 100; /* reject packet */ }
var errIntegrityViolation = sentinelError("integrity violation: HMAC mismatch")
// dispatch(packet.Header.IntentID, packet.Header.ThreatScore, packet.Payload)
type ParsedPacket struct {
Header UEPSHeader // packet.Header.Version == 0x09; packet.Header.IntentID == 0x01; packet.Header.ThreatScore == 0
Payload []byte // packet.Payload == []byte("hello world")
}
// packet, err := ueps.ReadAndVerify(bufio.NewReader(conn), []byte("my-shared-secret"))
// if err == errMissingHMAC { return } // unauthenticated: no HMAC tag in stream
// if err == errIntegrityViolation { return } // tampered: HMAC mismatch; reject and raise threat score
// if err == nil { dispatch(packet.Header.IntentID, packet.Header.ThreatScore, packet.Payload) }
func ReadAndVerify(reader *bufio.Reader, sharedSecret []byte) (*ParsedPacket, error) {
var (
hmacInputBuffer bytes.Buffer
packetHeader UEPSHeader
hmacSignature []byte
payload []byte
)
for {
tagType, err := reader.ReadByte()
if err != nil {
return nil, err
}
if tagType == TagPayload {
payload, err = io.ReadAll(reader)
if err != nil {
return nil, err
}
break
}
tagLength, err := reader.ReadByte()
if err != nil {
return nil, err
}
tagValue := make([]byte, int(tagLength))
if _, err := io.ReadFull(reader, tagValue); err != nil {
return nil, err
}
switch tagType {
case TagVersion:
packetHeader.Version = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagLength)
hmacInputBuffer.Write(tagValue)
case TagCurrentLayer:
packetHeader.CurrentLayer = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagLength)
hmacInputBuffer.Write(tagValue)
case TagTargetLayer:
packetHeader.TargetLayer = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagLength)
hmacInputBuffer.Write(tagValue)
case TagIntent:
packetHeader.IntentID = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagLength)
hmacInputBuffer.Write(tagValue)
case TagThreatScore:
packetHeader.ThreatScore = binary.BigEndian.Uint16(tagValue)
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagLength)
hmacInputBuffer.Write(tagValue)
case TagHMAC:
hmacSignature = tagValue
default:
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagLength)
hmacInputBuffer.Write(tagValue)
}
}
if len(hmacSignature) == 0 {
return nil, errMissingHMAC
}
messageAuthCode := hmac.New(sha256.New, sharedSecret)
messageAuthCode.Write(hmacInputBuffer.Bytes())
messageAuthCode.Write(payload)
expectedMessageAuthCode := messageAuthCode.Sum(nil)
if !hmac.Equal(hmacSignature, expectedMessageAuthCode) {
return nil, errIntegrityViolation
}
return &ParsedPacket{
Header: packetHeader,
Payload: payload,
}, nil
}