CBOR Encoding/Decoding Skill
Use this skill when you need to interpret, validate, or transform CBOR payloads and their
representations (hex, diagnostic notation, annotated hex). When cbor-hex is unclear, use the
locally installed cbor-diag tool for authoritative decoding.
References
Tooling
cbor-diag converts between bytes, hex, and diagnostic notation.
Supported inputs:
--from auto|hex|bytes|diag
--to annotated|hex|bytes|diag|compact|debug
--seq for CBOR sequence (cbor-seq)
Workflow
- Identify the representation you have (raw bytes, hex string, or diagnostic notation).
- If you have cbor-hex, decode it to diagnostic notation:
cbor-diag --from hex --to diag
- If you have diagnostic notation and need canonical bytes/hex:
cbor-diag --from diag --to hex
- If you need a readable byte-level explanation:
cbor-diag --from hex --to annotated
- For multiple concatenated CBOR items, add
--seq.
Interpretation Notes
- Hex input ignores whitespace and
# comments; keep payloads clean but comments are allowed.
- Diagnostic notation follows RFC 7049; arrays, maps, tags, and byte strings are expressed
explicitly in diag form.
- Use
--to compact if you need a minimal diagnostic string for round-tripping or tests.
Quick Recognition (Appendix A/B)
Use these Appendix A examples to quickly identify common CBOR blobs before decoding:
Integers and simple values:
00 => 0
01 => 1
0a => 10
17 => 23
18 18 => 24
18 19 => 25
18 64 => 100
19 03 e8 => 1000
18 ff => 255
19 ff ff => 65535
1a 00 0f 42 40 => 1000000
1b 00 00 00 e8 d4 a5 10 00 => 1000000000000
1b ff ff ff ff ff ff ff ff => 18446744073709551615
c2 49 01 00 00 00 00 00 00 00 00 => 18446744073709551616
20 => -1
29 => -10
38 63 => -100
39 03 e7 => -1000
3b ff ff ff ff ff ff ff ff => -18446744073709551616
c3 49 01 00 00 00 00 00 00 00 00 => -18446744073709551617
f4 => false
f5 => true
f6 => null
f7 => undefined
f0 => simple(16)
f8 18 => simple(24)
f8 ff => simple(255)
Floating-point values:
f9 00 00 => 0.0
f9 80 00 => -0.0
f9 3c 00 => 1.0
f9 3e 00 => 1.5
fb 3f f1 99 99 99 99 99 9a => 1.1
f9 7c 00 => Infinity
f9 7e 00 => NaN
f9 fc 00 => -Infinity
Strings and bytes:
60 => ""
61 61 => "a"
64 49 45 54 46 => "IETF"
40 => h''
44 01 02 03 04 => h'01020304'
Arrays and maps:
80 => []
83 01 02 03 => [1, 2, 3]
82 61 61 a1 61 62 61 63 => ["a", {"b": "c"}]
98 19 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 18 18 19
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
a0 => {}
a2 01 02 03 04 => {1: 2, 3: 4}
a2 61 61 01 61 62 82 02 03 => {"a": 1, "b": [2, 3]}
a5 61 61 61 41 61 62 61 42 61 63 61 43 61 64 61 44 61 65 61 45
=> {"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
Indefinite-length items:
5f 42 01 02 43 03 04 05 ff => (_ h'0102', h'030405')
7f 65 73 74 72 65 61 64 65 6d 69 6e 67 ff => (_ "strea", "ming")
9f ff => [_ ]
9f 01 82 02 03 9f 04 05 ff ff => [_ 1, [2, 3], [_ 4, 5]]
bf 61 61 01 61 62 9f 02 03 ff ff => {_ "a": 1, "b": [_ 2, 3]}
bf 63 46 75 6e f5 63 41 6d 74 21 ff => {_ "Fun": true, "Amt": -2}
Tags:
c0 74 32 30 31 33 2d 30 33 2d 32 31 54 32 30 3a 30 34 3a 30 30 5a
=> 0("2013-03-21T20:04:00Z")
c1 1a 51 4b 67 b0 => 1(1363896240)
c1 fb 41 d4 52 d9 ec 20 00 00 => 1(1363896240.5)
c2 42 01 02 => 2(h'0102')
c4 82 21 19 6a b3 => 4([-2, 27315])
c5 82 20 03 => 5([-1, 3])
d7 44 01 02 03 04 => 23(h'01020304')
d8 18 45 64 49 45 54 46 => 24(h'6449455446')
d8 20 76 68 74 74 70 3a 2f 2f 77 77 77 2e 65 78 61 6d 70 6c 65 2e 63 6f 6d
=> 32("http://www.example.com")
Appendix B notation cues:
- Byte strings use
h'...' (hex) or b64'...' (base64).
- Tags are
tag(value).
- Indefinite-length items use
_, e.g. [_ 1, 2] or (_ "a", "b").
- Unnamed simple values use
simple(value).
Appendix B jump table clues (common prefixes):
0x00..0x17: small unsigned ints (0..23)
0x18/19/1a/1b: unsigned ints with 1/2/4/8 following bytes
0x20..0x37: small negative ints (-1..-24)
0x38/39/3a/3b: negative ints with 1/2/4/8 following bytes
0x40..0x57: byte strings (0..23 bytes)
0x58/59/5a/5b: byte strings with 1/2/4/8 length bytes
0x5f: byte string (indefinite length, terminated by ff)
0x60..0x77: text strings (0..23 bytes)
0x78/79/7a/7b: text strings with 1/2/4/8 length bytes
0x7f: text string (indefinite length, terminated by ff)
0x80..0x97: arrays (0..23 items)
0x9f: array (indefinite length, terminated by ff)
0xa0..0xb7: maps (0..23 pairs)
0xbf: map (indefinite length, terminated by ff)
0xc0..0xdb: tags (major type 6)
0xf4..0xf7: false/true/null/undefined
0xff: break for indefinite-length items
Common tag IDs (major type 6):
0: date/time string (RFC 3339)
1: epoch-based date/time
2: positive bignum (byte string)
3: negative bignum (byte string)
4: decimal fraction (array [exp, mantissa])
5: bigfloat (array [exp, mantissa])
21/22/23: expected base64url/base64/base16 conversion
24: embedded CBOR data item (byte string)
32: URI
33/34: base64url/base64 text
35: regular expression
36: MIME message
55799: self-describe CBOR
Examples
Decode hex to diag:
cbor-diag --from hex --to diag <<< '83010203'
Expected output:
[1, 2, 3]
Encode diag to hex:
cbor-diag --from diag --to hex <<< '["a", {"b": "c"}]'
Expected output:
826161a161626163
Annotate hex for explanation:
cbor-diag --from hex --to annotated <<< 'a26161016162820203'
Expected output:
a2 # map(2)
61 # text(1)
61 # "a"
01 # unsigned(1)
61 # text(1)
62 # "b"
82 # array(2)
02 # unsigned(2)
03 # unsigned(3)
Common Pitfalls
- Confusing CBOR hex (encoded bytes) with a hex string contained inside CBOR. Decode to diag to
confirm types.
- Treating concatenated CBOR items as a single item; use
--seq if the input is a sequence.
Additional Guidance
- Canonicalization: the same logical value can be encoded multiple ways; decoding to diag and
re-encoding may not preserve original bytes if encoding indicators differed.
- Sequences:
--seq only works with raw bytes input; avoid --from when using it.
- Tags: preserve
tag(value) even when the semantic meaning is unknown; tags are optional hints.
Sequence example (raw bytes):
printf '\x01\x02\x03' | cbor-diag --to diag --seq
Expected output:
1
2
3
1---2name: cbor-encoding-decoding3description: Guidance for encoding/decoding CBOR and interpreting cbor-hex/diag using cbor-diag.4---56# CBOR Encoding/Decoding Skill78Use this skill when you need to interpret, validate, or transform CBOR payloads and their9representations (hex, diagnostic notation, annotated hex). When cbor-hex is unclear, use the10locally installed `cbor-diag` tool for authoritative decoding.1112## References13- RFC 7049 diagnostic notation: https://datatracker.ietf.org/doc/html/rfc7049#section-61415## Tooling16`cbor-diag` converts between bytes, hex, and diagnostic notation.1718Supported inputs:19- `--from auto|hex|bytes|diag`20- `--to annotated|hex|bytes|diag|compact|debug`21- `--seq` for CBOR sequence (cbor-seq)2223## Workflow241. Identify the representation you have (raw bytes, hex string, or diagnostic notation).252. If you have cbor-hex, decode it to diagnostic notation:26 - `cbor-diag --from hex --to diag`273. If you have diagnostic notation and need canonical bytes/hex:28 - `cbor-diag --from diag --to hex`294. If you need a readable byte-level explanation:30 - `cbor-diag --from hex --to annotated`315. For multiple concatenated CBOR items, add `--seq`.3233## Interpretation Notes34- Hex input ignores whitespace and `#` comments; keep payloads clean but comments are allowed.35- Diagnostic notation follows RFC 7049; arrays, maps, tags, and byte strings are expressed36 explicitly in diag form.37- Use `--to compact` if you need a minimal diagnostic string for round-tripping or tests.3839## Quick Recognition (Appendix A/B)40Use these Appendix A examples to quickly identify common CBOR blobs before decoding:4142Integers and simple values:43- `00` => `0`44- `01` => `1`45- `0a` => `10`46- `17` => `23`47- `18 18` => `24`48- `18 19` => `25`49- `18 64` => `100`50- `19 03 e8` => `1000`51- `18 ff` => `255`52- `19 ff ff` => `65535`53- `1a 00 0f 42 40` => `1000000`54- `1b 00 00 00 e8 d4 a5 10 00` => `1000000000000`55- `1b ff ff ff ff ff ff ff ff` => `18446744073709551615`56- `c2 49 01 00 00 00 00 00 00 00 00` => `18446744073709551616`57- `20` => `-1`58- `29` => `-10`59- `38 63` => `-100`60- `39 03 e7` => `-1000`61- `3b ff ff ff ff ff ff ff ff` => `-18446744073709551616`62- `c3 49 01 00 00 00 00 00 00 00 00` => `-18446744073709551617`63- `f4` => `false`64- `f5` => `true`65- `f6` => `null`66- `f7` => `undefined`67- `f0` => `simple(16)`68- `f8 18` => `simple(24)`69- `f8 ff` => `simple(255)`7071Floating-point values:72- `f9 00 00` => `0.0`73- `f9 80 00` => `-0.0`74- `f9 3c 00` => `1.0`75- `f9 3e 00` => `1.5`76- `fb 3f f1 99 99 99 99 99 9a` => `1.1`77- `f9 7c 00` => `Infinity`78- `f9 7e 00` => `NaN`79- `f9 fc 00` => `-Infinity`8081Strings and bytes:82- `60` => `""`83- `61 61` => `"a"`84- `64 49 45 54 46` => `"IETF"`85- `40` => `h''`86- `44 01 02 03 04` => `h'01020304'`8788Arrays and maps:89- `80` => `[]`90- `83 01 02 03` => `[1, 2, 3]`91- `82 61 61 a1 61 62 61 63` => `["a", {"b": "c"}]`92- `98 19 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 18 18 19`93 => `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]`94- `a0` => `{}`95- `a2 01 02 03 04` => `{1: 2, 3: 4}`96- `a2 61 61 01 61 62 82 02 03` => `{"a": 1, "b": [2, 3]}`97- `a5 61 61 61 41 61 62 61 42 61 63 61 43 61 64 61 44 61 65 61 45`98 => `{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}`99100Indefinite-length items:101- `5f 42 01 02 43 03 04 05 ff` => `(_ h'0102', h'030405')`102- `7f 65 73 74 72 65 61 64 65 6d 69 6e 67 ff` => `(_ "strea", "ming")`103- `9f ff` => `[_ ]`104- `9f 01 82 02 03 9f 04 05 ff ff` => `[_ 1, [2, 3], [_ 4, 5]]`105- `bf 61 61 01 61 62 9f 02 03 ff ff` => `{_ "a": 1, "b": [_ 2, 3]}`106- `bf 63 46 75 6e f5 63 41 6d 74 21 ff` => `{_ "Fun": true, "Amt": -2}`107108Tags:109- `c0 74 32 30 31 33 2d 30 33 2d 32 31 54 32 30 3a 30 34 3a 30 30 5a`110 => `0("2013-03-21T20:04:00Z")`111- `c1 1a 51 4b 67 b0` => `1(1363896240)`112- `c1 fb 41 d4 52 d9 ec 20 00 00` => `1(1363896240.5)`113- `c2 42 01 02` => `2(h'0102')`114- `c4 82 21 19 6a b3` => `4([-2, 27315])`115- `c5 82 20 03` => `5([-1, 3])`116- `d7 44 01 02 03 04` => `23(h'01020304')`117- `d8 18 45 64 49 45 54 46` => `24(h'6449455446')`118- `d8 20 76 68 74 74 70 3a 2f 2f 77 77 77 2e 65 78 61 6d 70 6c 65 2e 63 6f 6d`119 => `32("http://www.example.com")`120121Appendix B notation cues:122- Byte strings use `h'...'` (hex) or `b64'...'` (base64).123- Tags are `tag(value)`.124- Indefinite-length items use `_`, e.g. `[_ 1, 2]` or `(_ "a", "b")`.125- Unnamed simple values use `simple(value)`.126127Appendix B jump table clues (common prefixes):128- `0x00..0x17`: small unsigned ints (0..23)129- `0x18/19/1a/1b`: unsigned ints with 1/2/4/8 following bytes130- `0x20..0x37`: small negative ints (-1..-24)131- `0x38/39/3a/3b`: negative ints with 1/2/4/8 following bytes132- `0x40..0x57`: byte strings (0..23 bytes)133- `0x58/59/5a/5b`: byte strings with 1/2/4/8 length bytes134- `0x5f`: byte string (indefinite length, terminated by `ff`)135- `0x60..0x77`: text strings (0..23 bytes)136- `0x78/79/7a/7b`: text strings with 1/2/4/8 length bytes137- `0x7f`: text string (indefinite length, terminated by `ff`)138- `0x80..0x97`: arrays (0..23 items)139- `0x9f`: array (indefinite length, terminated by `ff`)140- `0xa0..0xb7`: maps (0..23 pairs)141- `0xbf`: map (indefinite length, terminated by `ff`)142- `0xc0..0xdb`: tags (major type 6)143- `0xf4..0xf7`: false/true/null/undefined144- `0xff`: break for indefinite-length items145146Common tag IDs (major type 6):147- `0`: date/time string (RFC 3339)148- `1`: epoch-based date/time149- `2`: positive bignum (byte string)150- `3`: negative bignum (byte string)151- `4`: decimal fraction (array [exp, mantissa])152- `5`: bigfloat (array [exp, mantissa])153- `21/22/23`: expected base64url/base64/base16 conversion154- `24`: embedded CBOR data item (byte string)155- `32`: URI156- `33/34`: base64url/base64 text157- `35`: regular expression158- `36`: MIME message159- `55799`: self-describe CBOR160161## Examples162Decode hex to diag:163```bash164cbor-diag --from hex --to diag <<< '83010203'165```166Expected output:167```text168[1, 2, 3]169```170171Encode diag to hex:172```bash173cbor-diag --from diag --to hex <<< '["a", {"b": "c"}]'174```175Expected output:176```text177826161a161626163178```179180Annotate hex for explanation:181```bash182cbor-diag --from hex --to annotated <<< 'a26161016162820203'183```184Expected output:185```text186a2 # map(2)187 61 # text(1)188 61 # "a"189 01 # unsigned(1)190 61 # text(1)191 62 # "b"192 82 # array(2)193 02 # unsigned(2)194 03 # unsigned(3)195```196197## Common Pitfalls198- Confusing CBOR hex (encoded bytes) with a hex string contained inside CBOR. Decode to diag to199 confirm types.200- Treating concatenated CBOR items as a single item; use `--seq` if the input is a sequence.201202## Additional Guidance203- Canonicalization: the same logical value can be encoded multiple ways; decoding to diag and204 re-encoding may not preserve original bytes if encoding indicators differed.205- Sequences: `--seq` only works with raw bytes input; avoid `--from` when using it.206- Tags: preserve `tag(value)` even when the semantic meaning is unknown; tags are optional hints.207208Sequence example (raw bytes):209```bash210printf '\x01\x02\x03' | cbor-diag --to diag --seq211```212Expected output:213```text214121521622172183219```