TagoTiP/S — Secure Crypto Envelope
Version: 1.0 Date: April 2026 Status: Specification — Revision D
TagoTiP/S wraps TagoTiP data in a binary envelope. For the plaintext frame format (methods, variable syntax, parsing), see TagoTiP.md.
1. Introduction
TagoTiP/S (Secure) is a binary crypto envelope that provides AEAD authenticated encryption for TagoTiP data without requiring TLS. It is designed for links where TLS is unavailable or too expensive — such as LoRa, Sigfox, NB-IoT, or raw UDP.
TagoTiP/S uses a compact headless inner frame that omits fields carried by the envelope header, saving ~40–50 bytes per message (see §4).
1.1 How It Works
1.2 Envelope at a Glance
21 bytes header + ciphertext + auth tag
1.3 Design Goals
- Encrypted — AEAD authenticated encryption (configurable cipher suite) for links where TLS is unavailable
- Integrity-verified — built-in authentication tag detects tampering or corruption
- Compact — 29–37 bytes of envelope overhead (depending on cipher suite)
- Transport-agnostic — works over UDP, TCP, HTTP(S), MQTT, or any byte-capable channel
- C-friendly — predictable buffer sizes, no dynamic allocation required
2. Credentials
TagoTiP/S uses the following credentials for envelope construction and processing.
| Credential | Format | Secrecy | Purpose |
|---|---|---|---|
| Authorization Token | at + 32 hex chars (34 chars total) | Secret | Identifies the Account/Profile. Used to derive the Authorization Hash. Never transmitted on the wire. |
| Authorization Hash | 8 bytes (derived) | Public | First 8 bytes of SHA-256 of the Authorization Token without the at prefix (UTF-8 encoded). Used as the profile identifier in the envelope header and in TagoTiP frames. Safe to display in UIs/logs. |
| Device Hash | 8 bytes (derived) | Public | First 8 bytes of SHA-256 of the device serial number (UTF-8 encoded). Used as the device identifier in the envelope header. Allows the server to identify the device before decryption. |
| Encryption Key | 16 or 32 bytes (depends on cipher suite) | Secret | AEAD key used to encrypt/decrypt frames. Scoped per-device — each device has its own key. Looked up by the combination of Authorization Hash and Device Hash. |
Encryption Keys MUST be unique per device within a profile. Key reuse across devices is a configuration error and may compromise nonce uniqueness. Key length (16 or 32 bytes) is determined by the cipher suite (see §3.1). Changing to a cipher suite with a different key length requires reprovisioning the Encryption Key.
2.1 Deriving the Authorization Hash
Given an Authorization Token ate2bd319014b24e0a8aca9f00aea4c0d0:
- Strip the
atprefix:e2bd319014b24e0a8aca9f00aea4c0d0 - Encode the hex string as UTF-8 bytes
- Compute SHA-256 of those bytes
- Take the first 8 bytes of the digest:
0x4d 0xee 0xdd 0x7b 0xab 0x88 0x17 0xec
Note: The Authorization Hash derivation is shared between TagoTiP and TagoTiP/S. See TagoTiP.md §2 for the same computation.
2.2 Deriving the Device Hash
Given a device serial sensor-01:
- Compute SHA-256 of the UTF-8 bytes of
sensor-01 - Take the first 8 bytes of the digest (e.g.,
0xab 0x77 0x88 0xd2 0x2e 0xb7 0x37 0x2f)
Note: With an 8-byte hash (2^64 space), collisions within a single profile are virtually impossible in practice. If multiple devices nonetheless share the same Device Hash within a profile, the server SHOULD attempt decryption with each matching device's key until one succeeds or all fail. If all decryption attempts fail, the server MUST respond with
ACK|ERR|auth_failed.
2.3 Provisioning (Non-Normative)
The Encryption Key and Authorization Token SHOULD be provisioned during manufacturing or via a secure out-of-band channel. The protocol does not define a key exchange mechanism. The cipher suite SHOULD also be agreed upon during provisioning. The protocol does not include an in-band cipher negotiation mechanism; both sides must be configured to use the same cipher suite for a given device.
2.4 Optional Key Derivation (HMAC-SHA256)
Implementations MAY derive the Encryption Key from the Authorization Token and device serial number using HMAC-SHA256 instead of provisioning a separate key. This is a convenience feature — pre-provisioned keys remain fully supported and are the default.
Construction:
derive_key(token, serial, key_len):
1. hex_part = strip "at" prefix from token (if present)
2. hmac_key = UTF-8 bytes of hex_part
3. message = UTF-8 bytes of serial
4. output = HMAC-SHA256(key=hmac_key, msg=message) // 32 bytes
5. return output[0..key_len]
key_len= 16 for AES-128 cipher suites, 32 for AES-256 / ChaCha20-Poly1305- HMAC-SHA256 requires only SHA-256 (already required by §2.1 and §2.2) plus the HMAC wrapper (RFC 2104)
- The token hex part is the HMAC key (secret); the serial is the message (semi-public). This is safe because HMAC security depends on the key being secret, not the message
- SHA-256 output is 32 bytes, covering all cipher suite key sizes
Test vector (using the spec credentials from §11.1):
Token: ate2bd319014b24e0a8aca9f00aea4c0d0
Serial: sensor-01
HMAC key (UTF-8): "e2bd319014b24e0a8aca9f00aea4c0d0"
HMAC message (UTF-8): "sensor-01"
Derived key (32 bytes):
e5 05 f0 3c c9 e9 3f db cc 38 28 44 cc a3 e1 7f
df 0b b3 13 18 58 53 95 ce aa a3 9a 5d 14 19 64
First 16 bytes (AES-128): e5 05 f0 3c c9 e9 3f db cc 38 28 44 cc a3 e1 7f
Note: When using derived keys, the Authorization Token becomes the sole secret for a given device. Implementations using key derivation MUST treat the token with the same care as an Encryption Key.
2.5 Hex Utilities (Non-Normative)
SDK implementations SHOULD provide hex_to_bytes and bytes_to_hex utility functions to simplify working with pre-provisioned keys supplied as hex strings. These are not protocol-level operations but are commonly needed by integrators.