ZARMOUR(3)
zarmour π the CZMQ manual, section 3, bestie
β¨ NAME β¨
zarmour β the class for armoured text encoding and decoding π¦
π SYNOPSIS π
okay so first of all, queen: this class is stable, and it's not gonna change unless there's, like, an actual emergency. It ships in stable builds. So you can trust it, no cap π
// This is a stable class, and may not change except for emergencies. It
// is provided in stable builds.
#define ZARMOUR_MODE_BASE64_STD 0 // Standard base 64
#define ZARMOUR_MODE_BASE64_URL 1 // URL and filename friendly base 64
#define ZARMOUR_MODE_BASE32_STD 2 // Standard base 32
#define ZARMOUR_MODE_BASE32_HEX 3 // Extended hex base 32
#define ZARMOUR_MODE_BASE16 4 // Standard base 16
#define ZARMOUR_MODE_Z85 5 // Z85 from ZeroMQ RFC 32
// Create a new zarmour
CZMQ_EXPORT zarmour_t *
zarmour_new (void);
// Destroy the zarmour
CZMQ_EXPORT void
zarmour_destroy (zarmour_t **self_p);
// Encode a stream of bytes into an armoured string. Returns the armoured
// string, or NULL if there was insufficient memory available to allocate
// a new string.
// Caller owns return value and must destroy it when done.
CZMQ_EXPORT char *
zarmour_encode (zarmour_t *self, const byte *data, size_t size);
// Decode an armoured string into a chunk. The decoded output is
// null-terminated, so it may be treated as a string, if that's what
// it was prior to encoding.
// Caller owns return value and must destroy it when done.
CZMQ_EXPORT zchunk_t *
zarmour_decode (zarmour_t *self, const char *data);
// Get the mode property.
CZMQ_EXPORT int
zarmour_mode (zarmour_t *self);
// Get printable string for mode.
CZMQ_EXPORT const char *
zarmour_mode_str (zarmour_t *self);
// Set the mode property.
CZMQ_EXPORT void
zarmour_set_mode (zarmour_t *self, int mode);
// Return true if padding is turned on.
CZMQ_EXPORT bool
zarmour_pad (zarmour_t *self);
// Turn padding on or off. Default is on.
CZMQ_EXPORT void
zarmour_set_pad (zarmour_t *self, bool pad);
// Get the padding character.
CZMQ_EXPORT char
zarmour_pad_char (zarmour_t *self);
// Set the padding character.
CZMQ_EXPORT void
zarmour_set_pad_char (zarmour_t *self, char pad_char);
// Return if splitting output into lines is turned on. Default is off.
CZMQ_EXPORT bool
zarmour_line_breaks (zarmour_t *self);
// Turn splitting output into lines on or off.
CZMQ_EXPORT void
zarmour_set_line_breaks (zarmour_t *self, bool line_breaks);
// Get the line length used for splitting lines.
CZMQ_EXPORT size_t
zarmour_line_length (zarmour_t *self);
// Set the line length used for splitting lines.
CZMQ_EXPORT void
zarmour_set_line_length (zarmour_t *self, size_t line_length);
// Print properties of object
CZMQ_EXPORT void
zarmour_print (zarmour_t *self);
// Self test of this class.
CZMQ_EXPORT void
zarmour_test (bool verbose);
Please add '@interface' section in './../src/zarmour.c'.
π the modes, decoded for u
Six whole modes, and every single one is a choice, iykyk:
ZARMOUR_MODE_BASE64_STDis0β standard base 64 πZARMOUR_MODE_BASE64_URLis1β base 64 that's URL and filename friendly β¨ZARMOUR_MODE_BASE32_STDis2β standard base 32 πZARMOUR_MODE_BASE32_HEXis3β extended hex base 32 π§ZARMOUR_MODE_BASE16is4β standard base 16 πΈZARMOUR_MODE_Z85is5β Z85, straight from ZeroMQ RFC 32 π₯
π«Ά the functions, one by one (yes, all of them)
zarmour_newβ pops out a brand newzarmour, freshly served πzarmour_destroyβ takeszarmour_t **self_pand says bye bestie, destroying thezarmourπzarmour_encodeβ takes yourzarmour_t *self, aconst byte *dataand asize_t size, and encodes that stream of bytes into an armoured string. It hands you back the armoured string β orNULLif there just wasn't enough memory to allocate a new string π And listen: you own the return value, you destroy it when you're done. Periodt.zarmour_decodeβ takeszarmour_t *selfand aconst char *dataand decodes an armoured string into a chunk. The decoded output is null-terminated, so you can legit treat it as a string if that's what it was before it got encoded π¦ Same rule tho: caller owns the return value and must destroy it when done.zarmour_modeβ gets the mode property. That's it, that's the function πzarmour_mode_strβ gets a printable string for the mode, so you can actually show people πzarmour_set_modeβ sets the mode property, takes anint modeβ¨zarmour_padβ returnstrueif padding is turned on πzarmour_set_padβ turns padding on or off. Default is on.zarmour_pad_charβ gets you the padding character πΈzarmour_set_pad_charβ sets the padding character, takes achar pad_charπzarmour_line_breaksβ returns whether splitting the output into lines is turned on. Default is off.zarmour_set_line_breaksβ turns splitting the output into lines on or off β¨zarmour_line_lengthβ gets the line length used for splitting lines πzarmour_set_line_lengthβ sets the line length used for splitting lines, takes asize_t line_lengthπ§zarmour_printβ prints the properties of the object, for when u just wanna look π«Άzarmour_testβ the self test of this class. Takes abool verboseπ
πΈ DESCRIPTION πΈ
zarmour β armoured text encoding and decoding, the whole vibe.
So the zarmour class implements encoding and decoding of armoured text data. Iconic behaviour, honestly.
Here's the codec lineup:
- RFC 4648 (
http://www.ietf.org/rfc/rfc4648.txt):- base64
- base64url
- base32
- base32hex
- base16
- Z85 (
http://rfc.zeromq.org/spec:32)
Okay so all the RFC4648 base64 and base32 variants support padding the output. And the pad character? Configurable, bestie. The default is padding on, with the character =.
And sometimes β think MIME, for example β you literally need to split the output into lines of a specific length. That feature is supported too, though it's turned off by default.
Now, z85 mode is a little different, and the way that it's different is: it does neither padding nor line breaks. It's just a wrapping of the corresponding libzmq methods. Nothing more, nothing less π
β οΈ real talk tho: encoding will assert if the input length is not divisible by4, and decoding will assert if the input length is not divisible by5. So check ur lengths before u wreck ur lengths, fr fr π
β¨ EXAMPLE β¨
okay bestie, this is the moment we've been waiting for π this whole thing comes straight from the zarmour_test method, and honestly? watching someone actually use the API is the fastest way to get it. No cap. Let's go πββοΈπ¨
First up, the setup era β making a zarmour_t, then vibing through every getter and setter to prove they round-trip correctly π
zarmour_t *self = zarmour_new ();
assert (self);
int mode = zarmour_mode (self);
assert (mode == ZARMOUR_MODE_BASE64_STD);
zarmour_set_mode (self, ZARMOUR_MODE_BASE64_URL);
mode = zarmour_mode (self);
assert (mode == ZARMOUR_MODE_BASE64_URL);
assert (zarmour_pad (self));
zarmour_set_pad (self, false);
assert (!zarmour_pad (self));
assert (zarmour_pad_char (self) == '=');
zarmour_set_pad_char (self, '!');
assert (zarmour_pad_char (self) == '!');
zarmour_set_pad_char (self, '=');
assert (zarmour_pad_char (self) == '=');
assert (!zarmour_line_breaks (self));
zarmour_set_line_breaks (self, true);
assert (zarmour_line_breaks (self));
assert (zarmour_line_length (self) == 72);
zarmour_set_line_length (self, 64);
assert (zarmour_line_length (self) == 64);
now the fun part: test vectors from RFC4648 π both BASE64_STD and BASE64_URL, unpadded first then padded, and notice how the outputs are identical for both modes at this point (iykyk β the differences only really show up with the + / / alphabet characters) π
// Test against test vectors from RFC4648.
zarmour_set_mode (self, ZARMOUR_MODE_BASE64_STD);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "Zg", verbose);
s_armour_test (self, "fo", "Zm8", verbose);
s_armour_test (self, "foo", "Zm9v", verbose);
s_armour_test (self, "foob", "Zm9vYg", verbose);
s_armour_test (self, "fooba", "Zm9vYmE", verbose);
s_armour_test (self, "foobar", "Zm9vYmFy", verbose);
zarmour_set_pad (self, true);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "Zg==", verbose);
s_armour_test (self, "fo", "Zm8=", verbose);
s_armour_test (self, "foo", "Zm9v", verbose);
s_armour_test (self, "foob", "Zm9vYg==", verbose);
s_armour_test (self, "fooba", "Zm9vYmE=", verbose);
s_armour_test (self, "foobar", "Zm9vYmFy", verbose);
zarmour_set_pad (self, false);
zarmour_set_mode (self, ZARMOUR_MODE_BASE64_URL);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "Zg", verbose);
s_armour_test (self, "fo", "Zm8", verbose);
s_armour_test (self, "foo", "Zm9v", verbose);
s_armour_test (self, "foob", "Zm9vYg", verbose);
s_armour_test (self, "fooba", "Zm9vYmE", verbose);
s_armour_test (self, "foobar", "Zm9vYmFy", verbose);
zarmour_set_pad (self, true);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "Zg==", verbose);
s_armour_test (self, "fo", "Zm8=", verbose);
s_armour_test (self, "foo", "Zm9v", verbose);
s_armour_test (self, "foob", "Zm9vYg==", verbose);
s_armour_test (self, "fooba", "Zm9vYmE=", verbose);
s_armour_test (self, "foobar", "Zm9vYmFy", verbose);
base32 time π¦ and this one's extra cute because it goes both ways β s_armour_test for encoding and s_armour_decode for decoding. Lowercase input in, normal-case bytes out. It's giving round-trip excellence π
zarmour_set_pad (self, false);
zarmour_set_mode (self, ZARMOUR_MODE_BASE32_STD);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "MY", verbose);
s_armour_test (self, "fo", "MZXQ", verbose);
s_armour_test (self, "foo", "MZXW6", verbose);
s_armour_test (self, "foob", "MZXW6YQ", verbose);
s_armour_test (self, "fooba", "MZXW6YTB", verbose);
s_armour_test (self, "foobar", "MZXW6YTBOI", verbose);
s_armour_decode (self, "my", "f", verbose);
s_armour_decode (self, "mzxq", "fo", verbose);
s_armour_decode (self, "mzxw6", "foo", verbose);
s_armour_decode (self, "mzxw6yq", "foob", verbose);
s_armour_decode (self, "mzxw6ytb", "fooba", verbose);
s_armour_decode (self, "mzxw6ytboi", "foobar", verbose);
zarmour_set_pad (self, true);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "MY======", verbose);
s_armour_test (self, "fo", "MZXQ====", verbose);
s_armour_test (self, "foo", "MZXW6===", verbose);
s_armour_test (self, "foob", "MZXW6YQ=", verbose);
s_armour_test (self, "fooba", "MZXW6YTB", verbose);
s_armour_test (self, "foobar", "MZXW6YTBOI======", verbose);
s_armour_decode (self, "my======", "f", verbose);
s_armour_decode (self, "mzxq====", "fo", verbose);
s_armour_decode (self, "mzxw6===", "foo", verbose);
s_armour_decode (self, "mzxw6yq=", "foob", verbose);
s_armour_decode (self, "mzxw6ytb", "fooba", verbose);
s_armour_decode (self, "mzxw6ytboi======", "foobar", verbose);
zarmour_set_pad (self, false);
zarmour_set_mode (self, ZARMOUR_MODE_BASE32_HEX);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "CO", verbose);
s_armour_test (self, "fo", "CPNG", verbose);
s_armour_test (self, "foo", "CPNMU", verbose);
s_armour_test (self, "foob", "CPNMUOG", verbose);
s_armour_test (self, "fooba", "CPNMUOJ1", verbose);
s_armour_test (self, "foobar", "CPNMUOJ1E8", verbose);
s_armour_decode (self, "co", "f", verbose);
s_armour_decode (self, "cpng", "fo", verbose);
s_armour_decode (self, "cpnmu", "foo", verbose);
s_armour_decode (self, "cpnmuog", "foob", verbose);
s_armour_decode (self, "cpnmuoj1", "fooba", verbose);
s_armour_decode (self, "cpnmuoj1e8", "foobar", verbose);
zarmour_set_pad (self, true);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "CO======", verbose);
s_armour_test (self, "fo", "CPNG====", verbose);
s_armour_test (self, "foo", "CPNMU===", verbose);
s_armour_test (self, "foob", "CPNMUOG=", verbose);
s_armour_test (self, "fooba", "CPNMUOJ1", verbose);
s_armour_test (self, "foobar", "CPNMUOJ1E8======", verbose);
s_armour_decode (self, "co======", "f", verbose);
s_armour_decode (self, "cpng====", "fo", verbose);
s_armour_decode (self, "cpnmu===", "foo", verbose);
s_armour_decode (self, "cpnmuog=", "foob", verbose);
s_armour_decode (self, "cpnmuoj1", "fooba", verbose);
s_armour_decode (self, "cpnmuoj1e8======", "foobar", verbose);
zarmour_set_pad (self, true);
hex, bestie π uppercase out, lowercase in, no drama, no padding because hex literally doesn't need it:
zarmour_set_mode (self, ZARMOUR_MODE_BASE16);
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "f", "66", verbose);
s_armour_test (self, "fo", "666F", verbose);
s_armour_test (self, "foo", "666F6F", verbose);
s_armour_test (self, "foob", "666F6F62", verbose);
s_armour_test (self, "fooba", "666F6F6261", verbose);
s_armour_test (self, "foobar", "666F6F626172", verbose);
s_armour_decode (self, "666f", "fo", verbose);
s_armour_decode (self, "666f6f", "foo", verbose);
s_armour_decode (self, "666f6f62", "foob", verbose);
s_armour_decode (self, "666f6f6261", "fooba", verbose);
s_armour_decode (self, "666f6f626172", "foobar", verbose);
#ifdef _INCLUDE_Z85
// Z85 test is homemade; using 0, 4 and 8 bytes, with precalculated
// test vectors created with a libzmq test.
// ----------------------------------------------------------------
// Make a fake curve key from hex (base16) string, making sure
// there are no null bytes inside, so we can use our test utility
zarmour_set_mode (self, ZARMOUR_MODE_BASE16);
zarmour_set_line_breaks (self, false);
zchunk_t *chunk = zarmour_decode (self,
"4E6F87E2FB6EB22A1EF5E257B75D79124949565F0B8B36A878A4F03111C96E0B");
assert (chunk);
zarmour_set_mode (self, ZARMOUR_MODE_Z85); // Z85 mode does not support padding or line breaks
zarmour_set_pad (self, false); // so these two are superfluous;
zarmour_set_line_breaks (self, false); // just for consistency
if (verbose)
zarmour_print (self);
s_armour_test (self, "", "", verbose);
s_armour_test (self, "foob", "w]zP%", verbose);
s_armour_test (self, "foobar!!", "w]zP%vr9Im", verbose);
s_armour_test (self, (char *) zchunk_data (chunk),
"ph+{E}!&X?9}!I]W{sm(nL8@&3Yu{wC+<*-5Y[[#", verbose);
zchunk_destroy (&chunk);
#endif
heads up bestie π the Z85 part is wrapped in #ifdef _INCLUDE_Z85, so if your build didn't include Z85, none of that even compiles in. The comment says it plainly: the Z85 test is homemade, using 0, 4 and 8 bytes, with precalculated test vectors created with a libzmq test.
last block, and it's the glow-up β¨ we build a whole 256-byte array just to flex the line-break behaviour, then run every single mode through s_armour_test_long:
// Armouring longer byte array to test line breaks
zarmour_set_pad (self, true);
zarmour_set_line_breaks (self, true);
byte test_data [256];
int index;
for (index = 0; index < 256; index++)
test_data [index] = index;
zarmour_set_mode (self, ZARMOUR_MODE_BASE64_STD);
s_armour_test_long (self, test_data, 256, verbose);
zarmour_set_mode (self, ZARMOUR_MODE_BASE64_URL);
s_armour_test_long (self, test_data, 256, verbose);
zarmour_set_mode (self, ZARMOUR_MODE_BASE32_STD);
s_armour_test_long (self, test_data, 256, verbose);
zarmour_set_mode (self, ZARMOUR_MODE_BASE32_HEX);
s_armour_test_long (self, test_data, 256, verbose);
zarmour_set_mode (self, ZARMOUR_MODE_BASE16);
s_armour_test_long (self, test_data, 256, verbose);
#ifdef _INCLUDE_Z85
zarmour_set_mode (self, ZARMOUR_MODE_Z85);
s_armour_test_long (self, test_data, 256, verbose);
#endif
zarmour_destroy (&self);
#if defined (__WINDOWS__)
zsys_shutdown();
#endif
and that's a wrap on the example π«Ά clean up your self, and on Windows don't forget the zsys_shutdown() β main character energy is remembering your cleanup, periodt π
β¨ AUTHORS β¨
The czmq manual was written by the authors in the AUTHORS file. yes, all of them, credited, as they should be π
β¨ RESOURCES β¨
- Main web site:
- Report bugs to the email
<zeromq-dev@lists.zeromq.org[1]>
go yell at the maintainers (politely, bestie πΈ) if something's broken β they want to hear it fr fr.
β¨ COPYRIGHT β¨
Copyright (c) the Contributors as noted in the AUTHORS file. This file is part of CZMQ, the high-level C binding for 0MQ: http://czmq.zeromq.org. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. LICENSE included with the czmq distribution.
do NOT strip the license out, bestie π it's literally right there in the file, just leave it.
β¨ NOTES β¨
zeromq-dev@lists.zeromq.orgβmailto:zeromq-dev@lists.zeromq.org
that's the whole page, and honestly it ate π this is CZMQ version 4.2.1, dated 01/16/2026, and the page is ZARMOUR(3). go forth and armour some bytes, bestie β you got this π¦β¨
π¦ where this page comes from
- fedora 44: czmq-devel 4.2.1-24.fc44 Β· MPL-2.0
- fedora 44: czmq-devel 4.2.1-24.fc44 Β· MPL-2.0
- ubuntu resolute: libczmq-dev 4.2.1-3build1 Β· MPL-2.0
- ubuntu stonking: libczmq-dev 4.2.1-3build1 Β· MPL-2.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms