From: Vsevolod Stakhov Date: Sat, 21 Sep 2024 13:59:12 +0000 (+0100) Subject: [Rework] Allow more flexible keypair encoding X-Git-Tag: 3.10.0~11^2 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F5144%2Fhead;p=rspamd.git [Rework] Allow more flexible keypair encoding --- diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c index 841d040b2..3064d45a0 100644 --- a/src/fuzzy_storage.c +++ b/src/fuzzy_storage.c @@ -2453,7 +2453,8 @@ rspamd_fuzzy_key_stat_iter(const unsigned char *pk_iter, struct fuzzy_key *fuzzy ucl_object_insert_key(elt, flags_ucl, "flags", 0, false); ucl_object_insert_key(elt, - rspamd_keypair_to_ucl(fuzzy_key->key, RSPAMD_KEYPAIR_DUMP_NO_SECRET | RSPAMD_KEYPAIR_DUMP_FLATTENED), + rspamd_keypair_to_ucl(fuzzy_key->key, RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_DUMP_NO_SECRET | RSPAMD_KEYPAIR_DUMP_FLATTENED), "keypair", 0, false); ucl_object_insert_key(keys_obj, elt, keyname, 0, true); } diff --git a/src/libcryptobox/keypair.c b/src/libcryptobox/keypair.c index d3f81ee2d..3556e188f 100644 --- a/src/libcryptobox/keypair.c +++ b/src/libcryptobox/keypair.c @@ -34,7 +34,7 @@ rspamd_keypair_quark(void) */ static void * rspamd_cryptobox_keypair_sk(struct rspamd_cryptobox_keypair *kp, - unsigned int *len) + size_t *len) { g_assert(kp != NULL); @@ -50,7 +50,7 @@ rspamd_cryptobox_keypair_sk(struct rspamd_cryptobox_keypair *kp, static void * rspamd_cryptobox_keypair_pk(struct rspamd_cryptobox_keypair *kp, - unsigned int *len) + size_t *len) { g_assert(kp != NULL); @@ -66,7 +66,7 @@ rspamd_cryptobox_keypair_pk(struct rspamd_cryptobox_keypair *kp, static void * rspamd_cryptobox_pubkey_pk(const struct rspamd_cryptobox_pubkey *kp, - unsigned int *len) + size_t *len) { g_assert(kp != NULL); @@ -139,7 +139,7 @@ void rspamd_cryptobox_nm_dtor(struct rspamd_cryptobox_nm *nm) void rspamd_cryptobox_keypair_dtor(struct rspamd_cryptobox_keypair *kp) { void *sk; - unsigned int len = 0; + size_t len = 0; sk = rspamd_cryptobox_keypair_sk(kp, &len); g_assert(sk != NULL && len > 0); @@ -168,7 +168,7 @@ rspamd_keypair_new(enum rspamd_cryptobox_keypair_type type) { struct rspamd_cryptobox_keypair *kp; void *pk, *sk; - unsigned int size; + size_t size; kp = rspamd_cryptobox_keypair_alloc(type); kp->type = type; @@ -241,7 +241,7 @@ rspamd_pubkey_from_base32(const char *b32, { unsigned char *decoded; gsize dlen, expected_len; - unsigned int pklen; + size_t pklen; struct rspamd_cryptobox_pubkey *pk; unsigned char *pk_data; @@ -283,7 +283,7 @@ rspamd_pubkey_from_hex(const char *hex, { unsigned char *decoded; gsize dlen, expected_len; - unsigned int pklen; + size_t pklen; struct rspamd_cryptobox_pubkey *pk; unsigned char *pk_data; @@ -325,7 +325,7 @@ rspamd_pubkey_from_bin(const unsigned char *raw, gsize len, enum rspamd_cryptobox_keypair_type type) { - unsigned int pklen; + size_t pklen; struct rspamd_cryptobox_pubkey *pk; unsigned char *pk_data; @@ -421,7 +421,7 @@ rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk, unsigned int *len) { unsigned char *ret = NULL; - unsigned int rlen; + size_t rlen; ret = rspamd_cryptobox_pubkey_pk(pk, &rlen); @@ -434,7 +434,8 @@ rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk, static void rspamd_keypair_print_component(unsigned char *data, gsize datalen, - GString *res, unsigned int how, const char *description) + GString *res, unsigned int how, const char *description, + enum rspamd_cryptobox_keypair_encoding encoding) { int olen, b32_len; @@ -442,7 +443,7 @@ rspamd_keypair_print_component(unsigned char *data, gsize datalen, rspamd_printf_gstring(res, "%s: ", description); } - if (how & RSPAMD_KEYPAIR_BASE32) { + if (encoding == RSPAMD_KEYPAIR_ENCODING_ZBASE32) { b32_len = (datalen * 8 / 5) + 2; g_string_set_size(res, res->len + b32_len); res->len -= b32_len; @@ -454,9 +455,12 @@ rspamd_keypair_print_component(unsigned char *data, gsize datalen, res->str[res->len] = '\0'; } } - else if (how & RSPAMD_KEYPAIR_HEX) { + else if (encoding == RSPAMD_KEYPAIR_ENCODING_HEX) { rspamd_printf_gstring(res, "%*xs", (int) datalen, data); } + else if (encoding == RSPAMD_KEYPAIR_ENCODING_BASE64) { + rspamd_printf_gstring(res, "%*Bs", (int) datalen, data); + } else { g_string_append_len(res, data, datalen); } @@ -467,10 +471,12 @@ rspamd_keypair_print_component(unsigned char *data, gsize datalen, } GString * -rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, unsigned int how) +rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, + enum rspamd_cryptobox_keypair_encoding encoding, + unsigned int how) { GString *res; - unsigned int len; + size_t len; gpointer p; g_assert(kp != NULL); @@ -479,28 +485,30 @@ rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, unsigned int how) if ((how & RSPAMD_KEYPAIR_PUBKEY)) { p = rspamd_cryptobox_keypair_pk(kp, &len); - rspamd_keypair_print_component(p, len, res, how, "Public key"); + rspamd_keypair_print_component(p, len, res, how, "Public key", encoding); } if ((how & RSPAMD_KEYPAIR_PRIVKEY)) { p = rspamd_cryptobox_keypair_sk(kp, &len); - rspamd_keypair_print_component(p, len, res, how, "Private key"); + rspamd_keypair_print_component(p, len, res, how, "Private key", encoding); } if ((how & RSPAMD_KEYPAIR_ID_SHORT)) { rspamd_keypair_print_component(kp->id, RSPAMD_KEYPAIR_SHORT_ID_LEN, - res, how, "Short key ID"); + res, how, "Short key ID", encoding); } if ((how & RSPAMD_KEYPAIR_ID)) { - rspamd_keypair_print_component(kp->id, sizeof(kp->id), res, how, "Key ID"); + rspamd_keypair_print_component(kp->id, sizeof(kp->id), res, how, "Key ID", encoding); } return res; } GString * -rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, unsigned int how) +rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, + enum rspamd_cryptobox_keypair_encoding encoding, + unsigned int how) { GString *res; - unsigned int len; + size_t len; gpointer p; g_assert(pk != NULL); @@ -509,15 +517,15 @@ rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, unsigned int how) if ((how & RSPAMD_KEYPAIR_PUBKEY)) { p = rspamd_cryptobox_pubkey_pk(pk, &len); - rspamd_keypair_print_component(p, len, res, how, "Public key"); + rspamd_keypair_print_component(p, len, res, how, "Public key", encoding); } if ((how & RSPAMD_KEYPAIR_ID_SHORT)) { rspamd_keypair_print_component(pk->id, RSPAMD_KEYPAIR_SHORT_ID_LEN, - res, how, "Short key ID"); + res, how, "Short key ID", encoding); } if ((how & RSPAMD_KEYPAIR_ID)) { rspamd_keypair_print_component(pk->id, sizeof(pk->id), res, how, - "Key ID"); + "Key ID", encoding); } return res; @@ -527,7 +535,7 @@ const unsigned char * rspamd_keypair_component(struct rspamd_cryptobox_keypair *kp, unsigned int ncomp, unsigned int *len) { - unsigned int rlen = 0; + size_t rlen = 0; const unsigned char *ret = NULL; g_assert(kp != NULL); @@ -558,11 +566,11 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) const ucl_object_t *privkey, *pubkey, *elt; const char *str; enum rspamd_cryptobox_keypair_type type = RSPAMD_KEYPAIR_KEX; - gboolean is_hex = FALSE; + enum rspamd_cryptobox_keypair_encoding encoding = RSPAMD_KEYPAIR_ENCODING_DEFAULT; struct rspamd_cryptobox_keypair *kp; - unsigned int len; - gsize ucl_len; - int dec_len; + size_t len; + size_t ucl_len; + size_t dec_len; gpointer target; if (ucl_object_type(obj) != UCL_OBJECT) { @@ -605,7 +613,10 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) str = ucl_object_tostring(elt); if (g_ascii_strcasecmp(str, "hex") == 0) { - is_hex = TRUE; + encoding = RSPAMD_KEYPAIR_ENCODING_HEX; + } + else if (g_ascii_strcasecmp(str, "base64") == 0) { + encoding = RSPAMD_KEYPAIR_ENCODING_BASE64; } /* TODO: handle errors */ } @@ -618,13 +629,29 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) target = rspamd_cryptobox_keypair_sk(kp, &len); str = ucl_object_tolstring(privkey, &ucl_len); - if (is_hex) { + switch (encoding) { + case RSPAMD_KEYPAIR_ENCODING_HEX: dec_len = rspamd_decode_hex_buf(str, ucl_len, target, len); - } - else { + break; + case RSPAMD_KEYPAIR_ENCODING_ZBASE32: dec_len = rspamd_decode_base32_buf(str, ucl_len, target, len, RSPAMD_BASE32_DEFAULT); + break; + case RSPAMD_KEYPAIR_ENCODING_BASE64: + dec_len = rspamd_cryptobox_base64_decode(str, ucl_len, target, &len); + break; + case RSPAMD_KEYPAIR_ENCODING_BINARY: + if (len >= ucl_len) { + memcpy(target, str, ucl_len); + dec_len = ucl_len; + } + else { + memcpy(target, str, len); + dec_len = len; + } + break; } + if (dec_len != (int) len) { rspamd_keypair_unref(kp); @@ -634,11 +661,26 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) target = rspamd_cryptobox_keypair_pk(kp, &len); str = ucl_object_tolstring(pubkey, &ucl_len); - if (is_hex) { + switch (encoding) { + case RSPAMD_KEYPAIR_ENCODING_HEX: dec_len = rspamd_decode_hex_buf(str, ucl_len, target, len); - } - else { + break; + case RSPAMD_KEYPAIR_ENCODING_ZBASE32: dec_len = rspamd_decode_base32_buf(str, ucl_len, target, len, RSPAMD_BASE32_DEFAULT); + break; + case RSPAMD_KEYPAIR_ENCODING_BASE64: + dec_len = rspamd_cryptobox_base64_decode(str, ucl_len, target, &len); + break; + case RSPAMD_KEYPAIR_ENCODING_BINARY: + if (len >= ucl_len) { + memcpy(target, str, ucl_len); + dec_len = ucl_len; + } + else { + memcpy(target, str, len); + dec_len = len; + } + break; } if (dec_len != (int) len) { @@ -660,24 +702,15 @@ rspamd_keypair_from_ucl(const ucl_object_t *obj) ucl_object_t * rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp, + enum rspamd_cryptobox_keypair_encoding encoding, enum rspamd_keypair_dump_flags flags) { ucl_object_t *ucl_out, *elt; - int how = 0; GString *keypair_out; - const char *encoding; + const char *encoding_str = NULL; g_assert(kp != NULL); - if (flags & RSPAMD_KEYPAIR_DUMP_HEX) { - how |= RSPAMD_KEYPAIR_HEX; - encoding = "hex"; - } - else { - how |= RSPAMD_KEYPAIR_BASE32; - encoding = "base32"; - } - if (flags & RSPAMD_KEYPAIR_DUMP_FLATTENED) { ucl_out = ucl_object_typed_new(UCL_OBJECT); elt = ucl_out; @@ -688,10 +721,17 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp, ucl_object_insert_key(ucl_out, elt, "keypair", 0, false); } + if (encoding == RSPAMD_KEYPAIR_ENCODING_HEX) { + encoding_str = "hex"; + } + else if (encoding == RSPAMD_KEYPAIR_ENCODING_BASE64) { + encoding_str = "base64"; + } + /* XXX: maybe support binary here ? */ /* pubkey part */ - keypair_out = rspamd_keypair_print(kp, - RSPAMD_KEYPAIR_PUBKEY | how); + keypair_out = rspamd_keypair_print(kp, encoding, + RSPAMD_KEYPAIR_PUBKEY | flags); ucl_object_insert_key(elt, ucl_object_fromlstring(keypair_out->str, keypair_out->len), "pubkey", 0, false); @@ -699,8 +739,8 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp, if (!(flags & RSPAMD_KEYPAIR_DUMP_NO_SECRET)) { /* privkey part */ - keypair_out = rspamd_keypair_print(kp, - RSPAMD_KEYPAIR_PRIVKEY | how); + keypair_out = rspamd_keypair_print(kp, encoding, + RSPAMD_KEYPAIR_PRIVKEY | flags); ucl_object_insert_key(elt, ucl_object_fromlstring(keypair_out->str, keypair_out->len), "privkey", 0, false); @@ -708,15 +748,18 @@ rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp, } keypair_out = rspamd_keypair_print(kp, - RSPAMD_KEYPAIR_ID | how); + encoding, + RSPAMD_KEYPAIR_ID | flags); ucl_object_insert_key(elt, ucl_object_fromlstring(keypair_out->str, keypair_out->len), "id", 0, false); g_string_free(keypair_out, TRUE); - ucl_object_insert_key(elt, - ucl_object_fromstring(encoding), - "encoding", 0, false); + if (encoding_str) { + ucl_object_insert_key(elt, + ucl_object_fromstring(encoding_str), + "encoding", 0, false); + } ucl_object_insert_key(elt, ucl_object_fromstring("curve25519"), diff --git a/src/libcryptobox/keypair.h b/src/libcryptobox/keypair.h index 97b46cbf5..80f4c4bd7 100644 --- a/src/libcryptobox/keypair.h +++ b/src/libcryptobox/keypair.h @@ -181,29 +181,8 @@ const unsigned char *rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk, #define RSPAMD_KEYPAIR_ID 0x4 /** Print short key id */ #define RSPAMD_KEYPAIR_ID_SHORT 0x8 -/** Encode output with base 32 */ -#define RSPAMD_KEYPAIR_BASE32 0x10 /** Human readable output */ #define RSPAMD_KEYPAIR_HUMAN 0x20 -#define RSPAMD_KEYPAIR_HEX 0x40 - -/** - * Print keypair encoding it if needed - * @param key key to print - * @param how flags that specifies printing behaviour - * @return newly allocated string with keypair - */ -GString *rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, - unsigned int how); - -/** - * Print pubkey encoding it if needed - * @param key key to print - * @param how flags that specifies printing behaviour - * @return newly allocated string with keypair - */ -GString *rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, - unsigned int how); /** Get keypair pubkey ID */ #define RSPAMD_KEYPAIR_COMPONENT_ID 0 @@ -232,17 +211,45 @@ struct rspamd_cryptobox_keypair *rspamd_keypair_from_ucl(const ucl_object_t *obj enum rspamd_keypair_dump_flags { RSPAMD_KEYPAIR_DUMP_DEFAULT = 0, - RSPAMD_KEYPAIR_DUMP_HEX = 1u << 0u, RSPAMD_KEYPAIR_DUMP_NO_SECRET = 1u << 1u, RSPAMD_KEYPAIR_DUMP_FLATTENED = 1u << 2u, }; +enum rspamd_cryptobox_keypair_encoding { + RSPAMD_KEYPAIR_ENCODING_ZBASE32 = 0, + RSPAMD_KEYPAIR_ENCODING_HEX = 1, + RSPAMD_KEYPAIR_ENCODING_BASE64 = 2, + RSPAMD_KEYPAIR_ENCODING_BINARY = 3, + RSPAMD_KEYPAIR_ENCODING_DEFAULT = RSPAMD_KEYPAIR_ENCODING_ZBASE32, +}; + + +/** + * Print pubkey encoding it if needed + * @param key key to print + * @param how flags that specifies printing behaviour + * @return newly allocated string with keypair + */ +GString *rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, + enum rspamd_cryptobox_keypair_encoding encoding, + unsigned int how); +/** + * Print keypair encoding it if needed + * @param key key to print + * @param how flags that specifies printing behaviour + * @return newly allocated string with keypair + */ +GString *rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, + enum rspamd_cryptobox_keypair_encoding encoding, + unsigned int how); /** * Converts keypair to ucl object * @param kp * @return */ + ucl_object_t *rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp, + enum rspamd_cryptobox_keypair_encoding encoding, enum rspamd_keypair_dump_flags flags); diff --git a/src/libserver/http/http_connection.c b/src/libserver/http/http_connection.c index 1ae9bb034..baf37a385 100644 --- a/src/libserver/http/http_connection.c +++ b/src/libserver/http/http_connection.c @@ -1987,9 +1987,11 @@ int rspamd_http_message_write_header(const char *mime_type, gboolean encrypted, GString *b32_key, *b32_id; b32_key = rspamd_keypair_print(priv->local_key, - RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32); + RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_PUBKEY); b32_id = rspamd_pubkey_print(peer_key, - RSPAMD_KEYPAIR_ID_SHORT | RSPAMD_KEYPAIR_BASE32); + RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_ID_SHORT); /* XXX: add some fuzz here */ rspamd_printf_fstring(&*buf, "Key: %v=%v\r\n", b32_id, b32_key); g_string_free(b32_key, TRUE); diff --git a/src/libserver/maps/map.c b/src/libserver/maps/map.c index 631455755..43a9d5d86 100644 --- a/src/libserver/maps/map.c +++ b/src/libserver/maps/map.c @@ -685,7 +685,8 @@ rspamd_map_check_sig_pk_mem(const unsigned char *sig, if (ret) { b32_key = rspamd_pubkey_print(pk, - RSPAMD_KEYPAIR_BASE32 | RSPAMD_KEYPAIR_PUBKEY); + RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_PUBKEY); msg_info_map("verified signature for %s using trusted key %v", map->name, b32_key); g_string_free(b32_key, TRUE); @@ -728,7 +729,8 @@ rspamd_map_check_file_sig(const char *fname, /* We just check pk against the trusted db of keys */ b32_key = rspamd_pubkey_print(pk, - RSPAMD_KEYPAIR_BASE32 | RSPAMD_KEYPAIR_PUBKEY); + RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_PUBKEY); g_assert(b32_key != NULL); if (g_hash_table_lookup(map->cfg->trusted_keys, b32_key->str) == NULL) { diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c index c9cac1562..3fa7d7d4f 100644 --- a/src/lua/lua_cryptobox.c +++ b/src/lua/lua_cryptobox.c @@ -503,7 +503,7 @@ lua_cryptobox_keypair_gc(lua_State *L) } /*** - * @method keypair:totable([hex=false]]) + * @method keypair:totable([encoding="zbase32"]) * Converts keypair to table (not very safe due to memory leftovers) */ static int @@ -512,16 +512,39 @@ lua_cryptobox_keypair_totable(lua_State *L) LUA_TRACE_POINT; struct rspamd_cryptobox_keypair *kp = lua_check_cryptobox_keypair(L, 1); ucl_object_t *obj; - gboolean hex = FALSE; + enum rspamd_cryptobox_keypair_encoding encoding = RSPAMD_KEYPAIR_ENCODING_DEFAULT; int ret = 1; if (kp != NULL) { if (lua_isboolean(L, 2)) { - hex = lua_toboolean(L, 2); + if (lua_toboolean(L, 2)) { + encoding = RSPAMD_KEYPAIR_ENCODING_HEX; + } + } + else if (lua_isstring(L, 2)) { + const char *enc = lua_tostring(L, 2); + + if (g_ascii_strcasecmp(enc, "hex") == 0) { + encoding = RSPAMD_KEYPAIR_ENCODING_HEX; + } + else if (g_ascii_strcasecmp(enc, "zbase32") == 0 || + g_ascii_strcasecmp(enc, "default") == 0 || + g_ascii_strcasecmp(enc, "base32") == 0) { + encoding = RSPAMD_KEYPAIR_ENCODING_ZBASE32; + } + else if (g_ascii_strcasecmp(enc, "base64") == 0) { + encoding = RSPAMD_KEYPAIR_ENCODING_BASE64; + } + else if (g_ascii_strcasecmp(enc, "binary") == 0) { + encoding = RSPAMD_KEYPAIR_ENCODING_BINARY; + } + else { + return luaL_error(L, "unknown encoding (known are: hex, zbase32/default, base64, binary: %s", enc); + } } - obj = rspamd_keypair_to_ucl(kp, hex ? RSPAMD_KEYPAIR_DUMP_HEX : RSPAMD_KEYPAIR_DUMP_DEFAULT); + obj = rspamd_keypair_to_ucl(kp, encoding, RSPAMD_KEYPAIR_DUMP_DEFAULT); ret = ucl_object_push_lua(L, obj, true); ucl_object_unref(obj); diff --git a/src/lua/lua_map.c b/src/lua/lua_map.c index 1cc2ce1bd..062613bd7 100644 --- a/src/lua/lua_map.c +++ b/src/lua/lua_map.c @@ -1256,8 +1256,8 @@ lua_map_get_sign_key(lua_State *L) bk = g_ptr_array_index(map->map->backends, i); if (bk->trusted_pubkey) { - ret = rspamd_pubkey_print(bk->trusted_pubkey, - RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32); + ret = rspamd_pubkey_print(bk->trusted_pubkey, RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_PUBKEY); } else { ret = NULL; diff --git a/src/rspamadm/signtool.c b/src/rspamadm/signtool.c index ddc3d45df..6d60e6700 100644 --- a/src/rspamadm/signtool.c +++ b/src/rspamadm/signtool.c @@ -366,7 +366,8 @@ rspamadm_sign_file(const char *fname, struct rspamd_cryptobox_keypair *kp) } else { b32_pk = rspamd_keypair_print(kp, - RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32); + RSPAMD_KEYPAIR_ENCODING_DEFAULT, + RSPAMD_KEYPAIR_PUBKEY); if (b32_pk) { rspamd_fprintf(pub_fp, "%v", b32_pk);