Mining/pkg/ueps/packet.go
Claude e65057e8af
Some checks failed
Test / test (push) Waiting to run
Security Scan / security (push) Has been cancelled
ax(ueps): rename buf→buffer in usage example comments
Abbreviated names in comments teach agents bad patterns.
AX Principle 1 applies to usage examples too.

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

128 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package ueps
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/binary"
"io"
)
// writeTLV(buffer, TagPayload, oversized) → errTLVValueTooLarge
// if errors.Is(err, errTLVValueTooLarge) { /* value exceeded 255-byte TLV length limit */ }
var errTLVValueTooLarge = tlvError("TLV value too large for 1-byte length header")
// var errMyError = tlvError("my error message")
type tlvError string
func (e tlvError) Error() string { return string(e) }
// TLV Types
const (
TagVersion = 0x01
TagCurrentLayer = 0x02
TagTargetLayer = 0x03
TagIntent = 0x04
TagThreatScore = 0x05
TagHMAC = 0x06 // The Signature
TagPayload = 0xFF // The Data
)
// header := ueps.UEPSHeader{Version: 0x09, CurrentLayer: 5, TargetLayer: 3, IntentID: 0x01, ThreatScore: 0}
type UEPSHeader struct {
Version uint8 // 0x09 = IPv9
CurrentLayer uint8 // OSI layer of the sender (5 = Application)
TargetLayer uint8 // OSI layer of the destination
IntentID uint8 // semantic token identifying the packet's purpose
ThreatScore uint16 // 065535; elevated by integrity violations
}
// builder := ueps.NewBuilder(intentID, payload); frame, _ := builder.MarshalAndSign(secret)
type PacketBuilder struct {
Header UEPSHeader
Payload []byte
}
// builder := ueps.NewBuilder(0x01, []byte("hello"))
// builder.Header.ThreatScore = 100
// frame, err := builder.MarshalAndSign(sharedSecret)
func NewBuilder(intentID uint8, payload []byte) *PacketBuilder {
return &PacketBuilder{
Header: UEPSHeader{
Version: 0x09, // IPv9
CurrentLayer: 5, // Application
TargetLayer: 5, // Application
IntentID: intentID,
ThreatScore: 0, // Assumed innocent until proven guilty
},
Payload: payload,
}
}
// frame, err := builder.MarshalAndSign([]byte("my-shared-secret"))
func (builder *PacketBuilder) MarshalAndSign(sharedSecret []byte) ([]byte, error) {
buffer := new(bytes.Buffer)
// 1. Write Standard Header Tags (0x01 - 0x05)
// We write these first because they are part of what we sign.
if err := writeTLV(buffer, TagVersion, []byte{builder.Header.Version}); err != nil {
return nil, err
}
if err := writeTLV(buffer, TagCurrentLayer, []byte{builder.Header.CurrentLayer}); err != nil {
return nil, err
}
if err := writeTLV(buffer, TagTargetLayer, []byte{builder.Header.TargetLayer}); err != nil {
return nil, err
}
if err := writeTLV(buffer, TagIntent, []byte{builder.Header.IntentID}); err != nil {
return nil, err
}
// Threat Score is uint16, needs binary packing
threatScoreBytes := make([]byte, 2)
binary.BigEndian.PutUint16(threatScoreBytes, builder.Header.ThreatScore)
if err := writeTLV(buffer, TagThreatScore, threatScoreBytes); err != nil {
return nil, err
}
// 2. Calculate HMAC
// The signature covers: Existing Header TLVs + The Payload
// It does NOT cover the HMAC TLV tag itself (obviously)
messageAuthCode := hmac.New(sha256.New, sharedSecret)
messageAuthCode.Write(buffer.Bytes()) // The headers so far
messageAuthCode.Write(builder.Payload) // The data
signature := messageAuthCode.Sum(nil)
// 3. Write HMAC TLV (0x06)
// Length is 32 bytes for SHA256
if err := writeTLV(buffer, TagHMAC, signature); err != nil {
return nil, err
}
// 4. Write Payload TLV (0xFF) — tag byte only; payload appended length-prefixless.
// buffer.Bytes() → [...headerTLVs..., 0x06, 0x20, <hmac32>, 0xFF, <payload...>]
buffer.WriteByte(TagPayload)
buffer.Write(builder.Payload)
return buffer.Bytes(), nil
}
// writeTLV(buffer, TagVersion, []byte{0x09})
// writeTLV(buffer, TagIntent, []byte{intentID})
func writeTLV(writer io.Writer, tag uint8, value []byte) error {
// Check strict length constraint (1 byte length = max 255 bytes)
if len(value) > 255 {
return errTLVValueTooLarge
}
if _, err := writer.Write([]byte{tag}); err != nil {
return err
}
if _, err := writer.Write([]byte{uint8(len(value))}); err != nil {
return err
}
if _, err := writer.Write(value); err != nil {
return err
}
return nil
}