Mining/pkg/ueps/reader.go
Claude 067a4c38f8
Some checks failed
Test / test (push) Waiting to run
Security Scan / security (push) Has been cancelled
ax(ueps): rename signedData to hmacInputBuffer for predictable naming
signedData was ambiguous — it did not convey that the buffer holds
accumulated header TLVs fed as input to HMAC, nor whether data was
already signed or pending signing. hmacInputBuffer makes the purpose
unambiguous on first read (AX Principle 1: predictable names over
short names).

Co-Authored-By: Charon <charon@lethean.io>
2026-04-02 12:21:22 +01:00

111 lines
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 = packetError("UEPS packet missing HMAC signature")
// packet, err := ReadAndVerify(bufio.NewReader(conn), wrongSecret)
// if err == errIntegrityViolation { header.ThreatScore += 100; /* reject packet */ }
var errIntegrityViolation = packetError("integrity violation: HMAC mismatch")
// dispatch(packet.Header.IntentID, packet.Header.ThreatScore, packet.Payload)
type ParsedPacket struct {
Header UEPSHeader
Payload []byte
}
// packet, err := ueps.ReadAndVerify(bufio.NewReader(conn), []byte("my-shared-secret"))
// 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
header := UEPSHeader{}
var hmacSignature []byte
var 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
}
tagValueLength, err := reader.ReadByte()
if err != nil {
return nil, err
}
tagValue := make([]byte, tagValueLength)
if _, err := io.ReadFull(reader, tagValue); err != nil {
return nil, err
}
switch tagType {
case TagVersion:
header.Version = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagValueLength)
hmacInputBuffer.Write(tagValue)
case TagCurrentLayer:
header.CurrentLayer = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagValueLength)
hmacInputBuffer.Write(tagValue)
case TagTargetLayer:
header.TargetLayer = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagValueLength)
hmacInputBuffer.Write(tagValue)
case TagIntent:
header.IntentID = tagValue[0]
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagValueLength)
hmacInputBuffer.Write(tagValue)
case TagThreatScore:
header.ThreatScore = binary.BigEndian.Uint16(tagValue)
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagValueLength)
hmacInputBuffer.Write(tagValue)
case TagHMAC:
hmacSignature = tagValue
default:
// hmacInputBuffer.Write([]byte{tagType, tagValueLength}); hmacInputBuffer.Write(tagValue) — unknown tags included in HMAC
hmacInputBuffer.WriteByte(tagType)
hmacInputBuffer.WriteByte(tagValueLength)
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: header,
Payload: payload,
}, nil
}