R_MUTA(3)
๐ r_muta โ the radare2 mutation/cryptography library ๐
okay bestie, gather round, because this one is a banger. It's the <r_muta.h> era of radare2's crypto/mutation stuff and it's giving โจinfrastructureโจ.
๐ SYNOPSIS ๐
#include <r_muta.h>
๐ซถ DESCRIPTION ๐ซถ
So. The r_muta facility is a whole plugin-based framework for data transformations used all over radare2. It hands you a thin, consistent API so you can list available plugins (hashers, encoders, ciphers, charset conversions, signature algorithms), create sessions, configure keys/IVs, and stream data through plugins to produce outputs. ๐
The whole design is about reusability from other core libraries โ for example, the hashing helper in libr/muta/hash/hash.c โ so callers can treat most algorithms uniformly. No cap, that's the entire vibe: one API to rule them all. ๐
๐ INITIALIZATION ๐
The context object is the global registry of available mutation plugins. Allocate it once when you need to query or create plugin sessions, and free it after all sessions are released. Simple as.
RMuta * r_muta_new(void)โ Creates and returns a new mutation context with bundled plugins registered. ๐ฆvoid r_muta_free(RMuta *cry)โ Releases the context and all internal resources.
โ ๏ธ bestie listen: Do not use a session after its parent context has been freed. That's undefined behaviour territory and she will not be nice about it. ๐
bool r_muta_add(RMuta *cry, RMutaPlugin *h)โ Registers a plugin into the context. Plugins provided in the tree are automatically added during context creation byr_muta_new, so you usually don't gotta do anything.bool r_muta_del(RMuta *cry, RMutaPlugin *h)โ Removes a plugin from the context's plugin list. bye girl ๐void r_muta_bind(RMuta *cry, RMutaBind *bnd)โ Binds RMuta functions to aRMutaBindstructure for language bindings. polyglot queen ๐
โจ PLUGIN DISCOVERY โจ
The context provides functions to discover and query available plugins. Scrolling the roster, basically. ๐
RMutaPlugin * r_muta_find(RMuta *cry, const char *algo)โ Finds a plugin by algorithm name, supports both exact name matching and implements field checking. ReturnsNULLif not found. ๐ญRMutaType r_muta_algo_type(RMuta *cry, const char *algo)โ Returns the type (hash, crypto, charset, etc.) of a specific algorithm.bool r_muta_algo_supports(RMuta *cry, const char *algo, RMutaType type)โ Checks if an algorithm supports a specific type.char * r_muta_list(RMuta *cry, RMutaType type, int mode)โ Returns a new string listing available plugins oftype(for exampleR_MUTA_TYPE_CRYPTOorR_MUTA_TYPE_HASH). Themodeparameter controls output format:'j'for JSON,'J'for JSON array,'q'for quiet, default for verbose. The returned string must be freed by the caller. ๐๏ธ
๐ธ SESSIONS ๐ธ
Plugins are used via sessions. A session is an instance of a plugin (like, an AES, or a hash) and it keeps per-operation state. The typical lifecycle is, and I'm gonna write it out exactly because it's the whole plot:
create session -> set key/iv (if applicable) -> update() -> end() -> get_output() -> free session
RMutaSession * r_muta_use(RMuta *cry, const char *algo)โ Creates a session for a plugin selected by name (example names:"aes-ecb","aes-cbc","base64","xor","sha1"). ReturnsNULLif the plugin is not found. ๐RMutaSession * r_muta_session_new(RMuta *cry, RMutaPlugin *cp)โ Creates a new session for a specific plugin instance.void r_muta_session_free(RMutaSession *cj)โ Frees session state.
๐ซง Always call this when finished with a session to avoid leaks. The memory leak is not the vibe. Free her.
๐ KEY AND IV SETUP ๐
Most symmetric ciphers require a key, and many block-based modes require an IV. Set these on the session before streaming data. Order matters, bestie.
bool r_muta_session_set_key(RMutaSession *cj, const ut8 *key, int keylen, int mode, int direction)โ Configures the cryptographic key and direction (encrypt/decrypt) for the session. The return value tells you whether the plugin accepted the key โ for example an invalid key size will fail. โint r_muta_session_get_key_size(RMutaSession *cj)โ Returns the key size required by the current algorithm.bool r_muta_session_set_iv(RMutaSession *cj, const ut8 *iv, int ivlen)โ Sets the initialization vector used by block cipher modes such as CBC.bool r_muta_session_set_subtype(RMutaSession *cj, const char *subtype)โ Sets a subtype for the session (used for algorithm variants).
๐ฅ PROCESSING ๐ฅ
Streaming APIs let you send data in chunks. Use r_muta_session_update for the intermediate chunks and r_muta_session_end for the last one โ some plugins treat end as the way to finalize padding or state. ๐ฌ
bool r_muta_session_update(RMutaSession *cj, const ut8 *buf, int len)โ Feedslenbytes frombufinto the session for processing. Returnstrueon success. โbool r_muta_session_end(RMutaSession *cj, const ut8 *buf, int len)โ Finalizes processing. Can accept a final chunk (orNULL, 0) to finish and flush internal buffers.int r_muta_session_append(RMutaSession *cj, const ut8 *buf, int len)โ Internal helper used by plugins to append produced bytes to the session output buffer. Callers usually do not need to use this directly. it's giving backstage access โจut8 * r_muta_session_decode_string(RMutaSession *cj, const ut8 *input, int len, RMutaDecodeCallback decode_fn, void *decode_ctx)โ Decodes a string using a custom decode callback function.
๐ OUTPUT ๐
After the session ends (or at any point the plugin exposes output), retrieve the produced bytes with r_muta_session_get_output. The returned buffer is heap allocated and must be freed by the caller. ๐งน
ut8 * r_muta_session_get_output(RMutaSession *cj, int *size)โ Returns a newly allocated buffer containing the processed output and sets*sizeto the buffer length. The caller is responsible forfree()ing it. periodt.
๐ HIGH-LEVEL PROCESSING ๐
For the simple use cases, the library provides unified processing functions that handle session creation and cleanup automatically. So you don't have to do the whole lifecycle dance yourself, she does it for you. main character energy. ๐
RMutaResult r_muta_process(RMuta *cry, const char *algo, const ut8 *data, int len, const ut8 *key, int key_len, const ut8 *iv, int iv_len, int direction)โ Unified processing function for all operations (hash, crypto, encode/decode). Returns anRMutaResultstructure containing the output and metadata.RMutaResult r_muta_process_simple(RMuta *cry, const char *algo, const ut8 *data, int len)โ Simple wrapper for hash and entropy operations without keys/IVs.void r_muta_result_free(RMutaResult *res)โ Frees resources allocated in anRMutaResultstructure.
๐ฆ CHARSET FUNCTIONS ๐ฆ
The library provides specialized functions for charset encoding and decoding operations. This is the international girlypop section. ๐
int r_muta_charset_parse_default(const char *str, const char *end, char *token, int token_max)โ Default parser for charset tokens, handles escape sequences, UTF-8, and special tokens.ut8 * r_muta_charset_decode(const ut8 *in, int in_len, int *out_len, const RMutaCharsetMap *table, const char *unknown_fmt)โ Decodes binary data to UTF-8 using a charset mapping table.ut8 * r_muta_charset_encode(const ut8 *in, int in_len, int *out_len, const RMutaCharsetMap *table, RMutaCharsetParserFn parser)โ Encodes UTF-8 data to binary using a charset mapping table.ut8 * r_muta_charset_encode_ex(const ut8 *in, int in_len, int *out_len, const RMutaCharsetMap *table, RMutaCharsetParserFn parser, ut8 unknown_byte)โ Extended version of charset encode with custom unknown byte handling.bool r_muta_charset_stub_update(RMutaSession *cj, const ut8 *b, int l)โ Stub update function that simply appends data to output.bool r_muta_charset_stub_end(RMutaSession *cj, const ut8 *b, int l)โ Stub end function that calls the stub update function.bool r_muta_charset_tr_update(RMutaSession *cj, const ut8 *buf, int len, const ut8 tr[256])โ Translation table update function for simple charset transformations.
๐ CRYPTOGRAPHIC FUNCTIONS ๐
Specialized cryptographic functions for specific algorithms. bespoke. custom. iconic. โญ
void r_muta_ed25519_keypair(const ut8 *seed, ut8 *privkey, ut8 *pubkey)โ Generates Ed25519 keypair from a 32-byte seed.
๐ DATA STRUCTURES ๐
๐ RMutaType Enum
Enumeration of plugin types, aka the categories, aka the friend groups:
R_MUTA_TYPE_HASHโ Hash algorithms (MD5, SHA family, CRC, etc.)R_MUTA_TYPE_BASEโ Base encoding algorithms (Base64, Base91, Bech32)R_MUTA_TYPE_CRYPTOโ Symmetric ciphers (AES, DES, Blowfish, etc.)R_MUTA_TYPE_SIGNโ Signature algorithms (Ed25519)R_MUTA_TYPE_CHARSETโ Charset conversions (ASCII, international charsets)R_MUTA_TYPE_ALLโ Special value to match all plugin types
๐ RMutaResult Structure
Result structure returned by high-level processing functions:
typedef struct r_muta_result_t {
ut8 *output; // binary output
int output_len; // length of output
int output_size; // allocated size of output buffer
double entropy; // entropy value
char *hex; // hex-encoded output
bool success; // operation succeeded
bool text_output; // output is text, not binary
} RMutaResult;
๐ Operation Constants
R_MUTA_OP_NONEโ No operation specifiedR_MUTA_OP_HASHโ Hash operationR_MUTA_OP_DECRYPTโ Decryption operationR_MUTA_OP_ENCRYPTโ Encryption operation
๐ง MODES AND DIRECTIONS ๐ง
Plugins accept modes and directions to control behavior; common values are R_CRYPTO_DIR_ENCRYPT and R_CRYPTO_DIR_DECRYPT. Modes cover block cipher modes such as ECB, CBC, OFB, and CFB.
๐ซถ Choose the direction consistently when calling r_muta_session_set_key. no flip-flopping, bestie, the cipher will know.
๐ ALGORITHMS ๐
A comprehensive set of built-in plugins is available โ the selection is honestly ate:
- Hash โ MD5, SHA family (SHA1, SHA224, SHA256, SHA384, SHA512), CRC variants, entropy calculations, ssdeep, strhash, fletcher
- Crypto โ AES (ECB, CBC, WRAP), DES, Blowfish, Serpent, SM4, XOR, RC algorithms
- Base Encoding โ Base64, Base91, Bech32, punycode
- Signature โ Ed25519 digital signatures
- Charset โ ASCII, various international charsets (Arabic ISO/Windows, Cyrillic ISO/Windows, Greek ISO/Windows, Hebrew ISO/Windows, Asian charsets like JIS7, Hiragana, Katakana), gaming charsets (Pokemon, Pokemon Red) ๐ฎ
- Transformations โ ROT, ROL, ROR, ADD, translation tables
Use r_muta_list() to discover what is available in the running build. iykyk ๐
โจ EXAMPLES โจ
okay bestie this is the part where it all comes together ๐ โ real, idiomatic, "yes this is how we actually use it" code. Let's go.
The first one is literally how libr/muta/hash/hash.c does it: algorithm-agnostic hashing, so you can pass in a plugin name and it just works. Main character energy fr.
/* Example: computing a hash using a plugin when available
* See: libr/muta/hash/hash.c
*/
RMuta *cry = r_muta_new();
RMutaSession *cj = r_muta_use (cry, name); // name like "sha1" or "md5"
int digest_size = 0;
if (cj && cj->h->type == R_MUTA_TYPE_HASH) {
r_muta_session_update (cj, data, len);
ut8 *result = r_muta_session_get_output (cj, &digest_size);
if (result) {
memcpy (ctx->digest, result, digest_size);
free (result);
}
} else {
/* fallback to internal r_hash implementation */
}
r_muta_session_free (cj);
r_muta_free (cry);
See how cute that is? Grab the plugin, check cj->h->type == R_MUTA_TYPE_HASH, feed it the data, snatch the output, copy it out, and free the buffer because the library is handing you memory you now own ๐ซถ. No plugin? No problem, slide into the internal r_hash fallback.
The AES example below walks the whole cipher-plugin lifecycle: key setup, IV setup, streaming update, finalization. Chef's kiss ๐ธ
RMuta *cry = r_muta_new();
RMutaSession *s = r_muta_use (cry, "aes-cbc");
if (!s) { /* handle error */ }
// Set a 128/192/256-bit key; direction is R_CRYPTO_DIR_ENCRYPT
ut8 key[16] = { /* ... */ };
ut8 iv[16] = { /* ... */ };
if (!r_muta_session_set_key (s, key, sizeof key, R_CRYPTO_MODE_CBC, R_CRYPTO_DIR_ENCRYPT)) {
/* invalid key or plugin refused */
}
if (!r_muta_session_set_iv (s, iv, sizeof iv)) {
/* invalid iv */
}
// Stream plaintext
r_muta_session_update (s, plaintext, plaintext_len);
// Finalize and flush
r_muta_session_end (s, NULL, 0);
int outlen = 0;
ut8 *cipher = r_muta_session_get_output (s, &outlen);
// use cipher, then free
free (cipher);
r_muta_session_free (s);
r_muta_free (cry);
ngl the important bits here: the key can be a 128/192/256-bit key, and the direction is R_CRYPTO_DIR_ENCRYPT. Both r_muta_session_set_key and r_muta_session_set_iv return falsy if something's wrong (bad key, bad iv, or the plugin just said "no ๐
") โ so check those returns, bestie. Then update, then r_muta_session_end (s, NULL, 0) to flush, then get the output. And yes, free it, and r_muta_session_free it. Clean up after yourself, it's giving โจhygieneโจ.
Simpler transformations like base64 or xor ride the exact same session API โ set_key may literally be a no-op for stateless encoders, and that's iconic of them. The XOR plugin here is showing off a small repeating key with a streamed buffer:
RMuta *cry = r_muta_new();
RMutaSession *s = r_muta_use (cry, "xor");
ut8 key[4] = {0x41, 0x42, 0x43, 0x44};
r_muta_session_set_key (s, key, 4, 0, R_CRYPTO_DIR_ENCRYPT);
r_muta_session_update (s, data, len);
r_muta_session_end (s, NULL, 0);
int outlen = 0;
ut8 *out = r_muta_session_get_output (s, &outlen);
free (out);
r_muta_session_free (s);
r_muta_free (cry);
lowkey the same shape every single time. That's the whole vibe. Consistency ate ๐
For one-shot operations where you just want the answer and not a whole relationship with a session object, the high-level processing functions come through:
RMuta *cry = r_muta_new();
RMutaResult result = r_muta_process_simple (cry, "sha256", data, len);
if (result.success) {
printf("Hash: %s\n", result.hex);
free (result.output);
free (result.hex);
}
r_muta_free (cry);
Look at result.success doing its little check-in. When it's true you get result.hex for a pretty printed string AND result.output โ and bestie, you free both ๐. The library is not your mom.
Charset encoding, converting UTF-8 into a specific charset, same energy:
RMuta *cry = r_muta_new();
RMutaSession *s = r_muta_use (cry, "charset-ascii");
if (s) {
r_muta_session_update (s, utf8_text, utf8_len);
r_muta_session_end (s, NULL, 0);
int outlen = 0;
ut8 *ascii = r_muta_session_get_output (s, &outlen);
// use ascii output
free (ascii);
r_muta_session_free (s);
}
r_muta_free (cry);
utf8 in, ascii out, memory freed, aura intact ๐ฆ
๐ NOTES ๐
Okay so the big structural tea: plugins follow a vtable pattern. RMutaPlugin exposes callbacks like set_key, update, end and get_key_size. That's the shape of it โ a table of function pointers, one plugin each, all wearing the same outfit so the caller doesn't have to know who's underneath ๐
Here's what you, the caller, should do:
- Create a single
RMutacontext per scope and reuse it for multiple sessions. Don't be out here making a new one every five seconds, it's not that kind of party. - Always call
r_muta_session_freeafter finishing with a session. Periodt. - Free the buffer returned by
r_muta_session_get_output. Every time. No exceptions, no "oh it'll be fine". - For high-level one-shot operations, prefer
r_muta_process()orr_muta_process_simple()over manual session management. Manual is fine, but why do extra work when the library will do it for you ๐ - The library supports a wide variety of algorithms, and I mean wide:
- modern ciphers: AES, Serpent, SM4
- classical ciphers: DES, Blowfish
- hash functions: SHA family, MD5, CRC
- base encodings: Base64, Base91, Bech32
- signature algorithms: Ed25519
- and extensive charset support, including international and gaming charsets ๐ฎ (yes, gaming charsets. iykyk.)
๐ SEE ALSO ๐
and that's the whole page, bestie, you made it to the end ๐ฅณ this one's from Debian, dated January 14, 2026 โ go forth and hash safely, free your buffers, and remember: the memory is yours now ๐โจ๐
๐ฆ where this page comes from
- alpine 3.24: radare2-doc 6.1.6-r0 ยท GPL-3.0-or-later AND LGPL-2.0-or-later AND LGPL-2.1-or-later
- arch rolling: radare2 6.2.2-1 ยท GPL-3.0-only AND LGPL-3.0-only
- nixos 26.05: radare2 6.1.8
- nixpkgs unstable: radare2 6.2.4
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 ยท GPL-3.0-only AND LGPL-3.0-only
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 ยท GPL-3.0-only AND LGPL-3.0-only
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 ยท GPL-3.0-only AND LGPL-3.0-only
- opensuse-leap 16.0: radare2 6.2.2-bp160.1.1 ยท GPL-3.0-only AND LGPL-3.0-only
- ubuntu stonking: radare2 6.1.8+ds-1 ยท LGPL-3.0-only
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms