CBOR codec (RFC 8949, RFC 8742) with CBOR tags, Go struct tag options (toarray, keyasint, omitempty, omitzero), float64/32/16, big.Int, and fuzz tested.
CBOR codec (RFC 8949, RFC 8742) with CBOR tags, Go struct tag options (toarray, keyasint, omitempty, omitzero), float64/32/16, big.Int, and fuzz tested.
CBOR Codec
fxamacker/cbor is a library for encoding and decoding CBOR and CBOR Sequences.
CBOR is a trusted alternative to JSON, MessagePack, Protocol Buffers, etc. CBOR is an Internet Standard defined by IETF STD 94 (RFC 8949) and is designed to be relevant for decades.
fxamacker/cbor is used in projects by Arm Ltd., EdgeX Foundry, Flow Foundation, Fraunhofer‑AISEC, IBM, Kubernetes*, Let's Encrypt, Linux Foundation, Microsoft, Oasis Protocol, Red Hat*, Tailscale*, Veraison*, etc.
See Quick Start and Releases. UnmarshalFirst and DiagnoseFirst can decode CBOR Sequences. MarshalToBuffer and UserBufferEncMode accepts user-specified buffer.
fxamacker/cbor is a CBOR codec in full conformance with IETF STD 94 (RFC 8949). It also supports CBOR Sequences (RFC 8742) and Extended Diagnostic Notation (Appendix G of RFC 8610).
Features include full support for CBOR tags, Core Deterministic Encoding, duplicate map key detection, etc.
API is mostly same as encoding/json, plus interfaces that simplify concurrency and CBOR options.
Design balances trade-offs between security, speed, concurrency, encoded data size, usability, etc.
Highlights
Speed
Encoding and decoding is fast without using Go's unsafe package. Slower settings are opt-in. Default limits allow very fast and memory efficient rejection of malformed CBOR data.
Security
Decoder has configurable limits that defend against malicious inputs. Duplicate map key detection is supported. By contrast, encoding/gob is not designed to be hardened against adversarial inputs.
Codec passed multiple confidential security assessments in 2022. No vulnerabilities found in subset of codec in a nonconfidential security assessment prepared by NCC Group for Microsoft Corporation.
️ Data Size
Struct tag options (toarray, keyasint, omitempty, omitzero) and field tag "-" automatically reduce size of encoded structs. Encoding optionally shrinks float64→32→16 when values fit.
:jigsaw: Usability
API is mostly same as encoding/json plus interfaces that simplify concurrency for CBOR options. Encoding and decoding modes can be created at startup and reused by any goroutines.
Presets include Core Deterministic Encoding, Preferred Serialization, CTAP2 Canonical CBOR, etc.
Extensibility
Features include CBOR extension points (e.g. CBOR tags) and extensive settings. API has interfaces that allow users to create custom encoding and decoding without modifying this library.
fxamacker/cbor has configurable limits, etc. that defend against malicious CBOR data.
Notably, fxamacker/cbor is fast at rejecting malformed CBOR data.
[!NOTE]
Benchmarks rejecting 10 bytes of malicious CBOR data decoding to[]byte:
Codec Speed (ns/op) Memory Allocs fxamacker/cbor 2.7.0 47 ± 7% 32 B/op 2 allocs/op ugorji/go 1.2.12 5878187 ± 3% 67111556 B/op 13 allocs/op Faster hardware (overclocked DDR4 or DDR5) can reduce speed difference.
Benchmark details
Latest comparison for decoding CBOR data to Go
[]byte:
- Input:
[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}- go1.22.7, linux/amd64, i5-13600K (DDR4-2933, disabled e-cores)
- go test -bench=. -benchmem -count=20
Prior comparisons
Codec Speed (ns/op) Memory Allocs fxamacker/cbor 2.5.0-beta2 44.33 ± 2% 32 B/op 2 allocs/op fxamacker/cbor 0.1.0 - 2.4.0 ~44.68 ± 6% 32 B/op 2 allocs/op ugorji/go 1.2.10 5524792.50 ± 3% 67110491 B/op 12 allocs/op ugorji/go 1.1.0 - 1.2.6 runtime: out of memory: cannot allocate
- Input:
[]byte{0x9B, 0x00, 0x00, 0x42, 0xFA, 0x42, 0xFA, 0x42, 0xFA, 0x42}- go1.19.6, linux/amd64, i5-13600K (DDR4)
- go test -bench=. -benchmem -count=20
In contrast, some codecs can crash or use excessive resources while decoding bad data.
[!WARNING]
Go'sencoding/gobis not designed to be hardened against adversarial inputs.gob fatal error (out of memory) decoding 181 bytes
…Struct tags automatically reduce encoded size of structs and improve speed.
We can write less code by using struct tag options:
toarray: encode without field names (decode back to original struct)keyasint: encode field names as integers (decode back to original struct)omitempty: omit empty field when encodingomitzero: omit zero-value field when encodingAs a special case, struct field tag "-" omits the field.
NOTE: When a struct uses toarray, the encoder will ignore omitempty and omitzero to prevent position of encoded array elements from changing. This allows decoder to match encoded elements to their Go struct field.
[!NOTE]
fxamacker/cborcan encode a 3-level nested Go struct to 1 byte!
encoding/json: 18 bytes of JSONfxamacker/cbor: 1 byte of CBOREncoding 3-level nested Go struct with omitempty
…Output (DN is Diagnostic Notation):
hex(CBOR): a0 DN: {} ------------- hex(JSON): 7b22466f6f223a7b22517578223a7b7d7d7d JSON: {"Foo":{"Qux":{}}}
Install: go get github.com/fxamacker/cbor/v2 and import "github.com/fxamacker/cbor/v2".
[!TIP]
TinyGo users can try beta/experimental branch feature/cbor-tinygo-beta.
More about TinyGo feature branch
TinyGo
:warning: The
feature/cbor-tinygo-betabranch is not currently fuzz tested.Branch feature/cbor-tinygo-beta tracks fxamacker/cbor master branch and it is updated periodically. It can be compiled with both tinygo-org/tinygo (0.42.0-dev-801bd484 or newer) and golang/go compilers.
This branch requires TinyGo 0.42.0-dev-801bd484 (or newer) because TinyGo v0.41.1 does not include a required fix (tinygo-org/tinygo#5508).
This branch passes unit tests (with both TinyGo and Go compilers) and it is considered experimental.
Changes in this feature branch only affect TinyGo compiled software. Summary of changes:
- Default
DecOptions.MaxNestedLevelsis reduced to 16 (was 32). User can specify a higher limit when running with a larger stack.- Encoding error message can be different when encoding function type. For details, see tinygo-org/tinygo#4458.
NOTE: An older version of this branch tinygo-beta/v2.7.0-tinygo0.33 (based on fxamacker/cbor v2.7.0) can be used with TinyGo v0.33. It disables decoding CBOR tag data to Go interface values due to tinygo-org/tinygo#4277.
This library can encode and decode CBOR (RFC 8949) and CBOR Sequences (RFC 8742).
Configurable limits and options can be used to balance trade-offs.
Package level functions only use this library's default settings.
They provide the "default mode" of encoding and decoding.
…[!IMPORTANT]
CBOR settings allow trade-offs between speed, security, encoding size, etc.
- Different CBOR libraries may use different default settings.
- CBOR-based formats or protocols usually require specific settings.
For example, WebAuthn uses "CTAP2 Canonical CBOR" which is available as a preset.
Presets can be used as-is or as a starting point for custom settings.
// EncOptions is a struct of encoder settings.
func CoreDetEncOptions() EncOptions // RFC 8949 Core Deterministic Encoding
func PreferredUnsortedEncOptions() EncOptions // RFC 8949 Preferred Serialization
func CanonicalEncOptions() EncOptions // RFC 7049 Canonical CBOR
func CTAP2EncOptions() EncOptions // FIDO2 CTAP2 Canonical CBORPresets are used to create custom modes.
Modes are created from settings. Once created, modes have immutable settings.
Create the mode at startup and reuse it. It is safe for concurrent use.
// Create encoding mode.
opts := cbor.CoreDetEncOptions() // use preset options as a starting point
opts.Time = cbor.TimeUnix // change any settings if needed
em, err := opts.EncMode() // create an immutable encoding mode
// Reuse the encoding mode. It is safe for concurrent use.
// API matches encoding/json.
b, err := em.Marshal(v) // encode v to []byte b
encoder := em.NewEncoder(w) // create encoder with io.Writer w
err := encoder.Encode(v) // encode v to io.Writer wDefault mode and custom modes automatically apply struct tags.
UserBufferEncMode interface extends EncMode interface to add MarshalToBuffer(). It accepts a user-specified buffer instead of using built-in buffer pool.
em, err := myEncOptions.UserBufferEncMode() // create UserBufferEncMode mode
var buf bytes.Buffer
err = em.MarshalToBuffer(v, &buf) // encode v to provided bufStruct tag options (toarray, keyasint, omitempty, omitzero) reduce encoded size of structs.
As a special case, struct field tag "-" omits the field.
Example encoding with struct field tag "-"
https://go.dev/play/p/aWEIFxd7InX
…Example encoding 3-level nested Go struct to 1 byte CBOR
https://go.dev/play/p/YxwvfPdFQG2
…Output (DN is Diagnostic Notation):
hex(CBOR): a0
DN: {}
-------------
hex(JSON): 7b22466f6f223a7b22517578223a7b7d7d7d
JSON: {"Foo":{"Qux":{}}}Example using struct tag options
Struct tag options simplify use of CBOR-based protocols that require CBOR arrays or maps with integer keys.
CBOR tags are specified in a TagSet.
Custom modes can be created with a TagSet to handle CBOR tags.
em, err := opts.EncMode() //No open issues yet, or sync has not completed.