Mining/pkg/ueps/packet.go
Claude 40b57849ff
Some checks are pending
Security Scan / security (push) Waiting to run
Test / test (push) Waiting to run
ax(ueps): fix tlvError comment to show type usage, not sentinel usage
The comment was a duplicate of errTLVValueTooLarge's example.
Fixed to show how tlvError defines new sentinels.

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

135 lines
4.3 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(buf, 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)
// Note: 0xFF length is variable. For simplicity in this specialized reader,
// we might handle 0xFF as "read until EOF" or use a varint length.
// Implementing standard 1-byte length for payload is risky if payload > 255.
// Assuming your spec allows >255 bytes, we handle 0xFF differently.
buffer.WriteByte(TagPayload)
// We don't write a 1-byte length for payload here assuming stream mode,
// but if strict TLV, we'd need a multi-byte length protocol.
// For this snippet, simply appending data:
buffer.Write(builder.Payload)
return buffer.Bytes(), nil
}
// writeTLV(buf, TagVersion, []byte{0x09})
// writeTLV(buf, 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
}