R_MUTA(3)

๐Ÿ“ฆ
version 6.2.2 ยท 2 versions
  • 6.2.2 ยท alpine 3.24, arch rolling, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu stonking (latest)
  • 6.0.7 ยท ubuntu resolute
, in alpine 3.24, arch rolling, nixos 26.05, nixpkgs unstable, opensuse-leap 16.0, ubuntu stonking

๐Ÿ’– 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 by r_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 a RMutaBind structure 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. Returns NULL if 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 of type (for example R_MUTA_TYPE_CRYPTO or R_MUTA_TYPE_HASH). The mode parameter 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"). Returns NULL if 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) โ€” Feeds len bytes from buf into the session for processing. Returns true on success. โœ…
  • bool r_muta_session_end(RMutaSession *cj, const ut8 *buf, int len) โ€” Finalizes processing. Can accept a final chunk (or NULL, 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 *size to the buffer length. The caller is responsible for free()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 an RMutaResult structure 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 an RMutaResult structure.

๐Ÿฆ‹ 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 specified
  • R_MUTA_OP_HASH โ€” Hash operation
  • R_MUTA_OP_DECRYPT โ€” Decryption operation
  • R_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 RMuta context 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_free after 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() or r_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