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 = tlvError("UEPS packet missing HMAC signature") // packet, err := ReadAndVerify(bufio.NewReader(conn), wrongSecret) // if err == errIntegrityViolation { /* HMAC mismatch — threat score incremented */ } var errIntegrityViolation = tlvError("integrity violation: HMAC mismatch (ThreatScore +100)") // packet, err := ueps.ReadAndVerify(bufio.NewReader(conn), sharedSecret) // if err == nil { _ = 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 signedData bytes.Buffer header := UEPSHeader{} var signature []byte var payload []byte for { tagByte, err := reader.ReadByte() if err != nil { return nil, err } if tagByte == TagPayload { var err error payload, err = io.ReadAll(reader) if err != nil { return nil, err } break } tagLengthByte, err := reader.ReadByte() if err != nil { return nil, err } tagLength := int(tagLengthByte) tagValue := make([]byte, tagLength) if _, err := io.ReadFull(reader, tagValue); err != nil { return nil, err } switch tagByte { case TagVersion: header.Version = tagValue[0] signedData.WriteByte(tagByte) signedData.WriteByte(byte(tagLength)) signedData.Write(tagValue) case TagCurrentLayer: header.CurrentLayer = tagValue[0] signedData.WriteByte(tagByte) signedData.WriteByte(byte(tagLength)) signedData.Write(tagValue) case TagTargetLayer: header.TargetLayer = tagValue[0] signedData.WriteByte(tagByte) signedData.WriteByte(byte(tagLength)) signedData.Write(tagValue) case TagIntent: header.IntentID = tagValue[0] signedData.WriteByte(tagByte) signedData.WriteByte(byte(tagLength)) signedData.Write(tagValue) case TagThreatScore: header.ThreatScore = binary.BigEndian.Uint16(tagValue) signedData.WriteByte(tagByte) signedData.WriteByte(byte(tagLength)) signedData.Write(tagValue) case TagHMAC: signature = tagValue default: signedData.WriteByte(tagByte) signedData.WriteByte(byte(tagLength)) signedData.Write(tagValue) } } if len(signature) == 0 { return nil, errMissingHMAC } messageAuthCode := hmac.New(sha256.New, sharedSecret) messageAuthCode.Write(signedData.Bytes()) messageAuthCode.Write(payload) expectedMessageAuthCode := messageAuthCode.Sum(nil) if !hmac.Equal(signature, expectedMessageAuthCode) { return nil, errIntegrityViolation } return &ParsedPacket{ Header: header, Payload: payload, }, nil }