* Rename librz/util/ubase64.c into librz/util/base64.c for consistency #5216 * Add Doxygen documentation to function in librz/util/base85.c #5216 * Add unit-tests for librz/util/base85.c #5216 * Refactor base85 API and internal functions #5216 base85 was using a FILE as an input and it used to print its result to STDOUT, which was very bad for having unit-testing or to use it to extend rz-hash functionality, since the solution I really had was through using pipes which isn't ideal as much as the refactoring one. * Extend rz-hash with base85 #5126 * Fix formatting #5216 * Extract base36 decoding function from subprojects/rzwinkd/iob_net.c to librz/util/base36.c #5216 - Also, added Doxygen docs to rz_base36_decode function * Added rz_base36_encode_dyn #5216 - this function encode a u64 value to it's char[13+1] base36 counterpart - later, it will be helpful in expanding the funcitionality of rz-hash - added its Doxygen docs * Expand rz-hash with base36 encoding/decoding #5216 * Refactor rz_base36_decode to return a suitable error code like -1 #5216 - that should help testing it later for valid and invalid decodings - keeping the original behaviour as it was in subprojects/rzwinkd/iob_net.c * Add unit-tests for base36 encoding & decoding functions #5216 * Fix formatting #5216 * Fix base36.h header file guards #5216 * Add base32 encoding & decoding #5216 added their Doxygen Docs as well * Add base32 encoding and decoding unti-tests #5216 * Expand rz-hash with base32 encoding/decoding functionality #5216 * Fix formatting #5216 * Fix add base32 to codec_name_bytes #5216 * Fix base32 docs #5216 * Add base16 encoding/decoding functions #5216 - added their Doxygen docs as well. * Add base16 unit-tests #5216 * Fix test_base85 conversions warnings #5216 * Expand rz-hash with base16 encoding/decoding functionality #5216 * Fix formatting #5216 * Fix doxygen docs #5216 * Restore subprojects/rizin-shell-parser/parser.c to match origin/dev * Fix the order by baseXX * Fix base16 - invert the logic in calculate_src_length * Fix base16 - intialize variables in rz_base16_encode * Fix base16 - null terminate the output buffer of rz_base16_encode_dyn * Fix base16 - get rid of unnecessary else in rz_base16_decode * Fix base16 - use `len & 1` instead of `(len % 2) != 0` * Fix base32 - invert the logic in calculate_src_length * Fix base32 - compress two return statments by using `rz_return_val_if_fail(src && dest, 0);` * Fix base32 - null terminate the output of rz_base32_encode * Fix base32 - get rid of unnecessary else in rz_base32_decode add more parentheses to split addition from mult for better clarity * Fix base32 - intialize variables in rz_base32_encode_dyn * Fix base36 - intialize `tmp` variable in rz_base36_encode_dyn * Fix base36 - use RZ_LOG_ERROR instead of eprintf * Fix base36 - use RZ_NULLABLE for the API interface * Fix base85 - use RZ_OUT & RZ_NULLABLE for the API interface * Fix base85 - use RZ_LOG_ERROR instead of eprintf * Fix base85 - use size_t instead of int for decode_tuple_buf * Fix base85 - remove unused varaible, `out_len`, in rz_base85_encode_dyn * Fix base85 - correct decode buffer size calculation The previous rz_base85_dec_buflen() underestimated the worst‑case output size (3 bytes per 4 input chars), causing overflows when using ‘z’/’y’ abbreviations. Update it to allocate 4 bytes per input character plus one for the NUL terminator, eliminating heap-buffer-overflow errors. * Fix formatting * Fix base85-test - use `newlines` variable to make sure line breaks were inserted as expected * Fix base85-test - remove unnecessary includes * Fix rz-hash test - updated rz-hash -L expected result * Fix crypto_base36 - use RZ_LOG_ERROR instead of eprintf * Fix base16 - compress rz_return_val_if_fail statements and move before locals * Update base16 - use hex.c existing encoding/decoding logic - base16.c encoding/decoding functions are now wrappers for hex.c `rz_hex_bin2str` and `rz_hex_str2bin` functions - updated related base16 unit testing and documentation - updated the integraion with rz-hash binary (or crypto_base16) * Fix formatting * Add documentation to rz_hex_bin2str * Fix base85 - add missing `reutrn` docs to rz_base85_encode function * Fix base85 - use RZ_NONNULL for dest and src function instead of RZ_NULLABLE * Fix base36 - use RZ_NONNULL for dest and src function instead of RZ_NULLABLE * Fix base16 - use RZ_NONNULL for dest and src function instead of RZ_NULLABLE * Fix base32 - use RZ_NONNULL for dest and src function instead of RZ_NULLABLE * Fix base16 - add missig checks for invalid inputs in rz_base16_encode & rz_base16_encode_dyn * Fix base32 - add missing checks for bad encoding * Fix - add missing SPDX * Fix Formatting * Add rz_base36_encode & rz_base36_decode_dyn functions to base36 API
248 lines
6.6 KiB
C
248 lines
6.6 KiB
C
// SPDX-FileCopyrightText: 2009-2017 pancake <pancake@nopcode.org>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_crypto.h>
|
|
#include <rz_lib.h>
|
|
#include <rz_util.h>
|
|
#include "rz_crypto_plugins.h"
|
|
|
|
#define RZ_CRYPTO_OUTPUT_SIZE 4096
|
|
|
|
RZ_LIB_VERSION(rz_crypto);
|
|
|
|
static RzCryptoPlugin *crypto_static_plugins[] = { RZ_CRYPTO_STATIC_PLUGINS };
|
|
|
|
static const struct {
|
|
const char *name;
|
|
RzCryptoSelector bit;
|
|
} crypto_name_bytes[] = {
|
|
{ "all", UT64_MAX },
|
|
{ "rc2", RZ_CRYPTO_RC2 },
|
|
{ "rc4", RZ_CRYPTO_RC4 },
|
|
{ "rc6", RZ_CRYPTO_RC6 },
|
|
{ "aes-ecb", RZ_CRYPTO_AES_ECB },
|
|
{ "aes-cbc", RZ_CRYPTO_AES_CBC },
|
|
{ "ror", RZ_CRYPTO_ROR },
|
|
{ "rol", RZ_CRYPTO_ROL },
|
|
{ "rot", RZ_CRYPTO_ROT },
|
|
{ "blowfish", RZ_CRYPTO_BLOWFISH },
|
|
{ "cps2", RZ_CRYPTO_CPS2 },
|
|
{ "des-ecb", RZ_CRYPTO_DES_ECB },
|
|
{ "xor", RZ_CRYPTO_XOR },
|
|
{ "serpent-ecb", RZ_CRYPTO_SERPENT },
|
|
{ "sm4-ecb", RZ_CRYPTO_SM4_ECB },
|
|
};
|
|
|
|
static const struct {
|
|
const char *name;
|
|
RzCryptoSelector bit;
|
|
} codec_name_bytes[] = {
|
|
{ "all", UT64_MAX },
|
|
{ "base16", RZ_CODEC_B16 },
|
|
{ "base32", RZ_CODEC_B32 },
|
|
{ "base36", RZ_CODEC_B36 },
|
|
{ "base64", RZ_CODEC_B64 },
|
|
{ "base85", RZ_CODEC_B85 },
|
|
{ "base91", RZ_CODEC_B91 },
|
|
{ "punycode", RZ_CODEC_PUNYCODE },
|
|
};
|
|
|
|
RZ_API RZ_BORROW const char *rz_crypto_name(const RzCryptoSelector bit) {
|
|
size_t i;
|
|
for (i = 1; i < RZ_ARRAY_SIZE(crypto_name_bytes); i++) {
|
|
if (bit == crypto_name_bytes[i].bit) {
|
|
return crypto_name_bytes[i].name;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
RZ_API RZ_BORROW const char *rz_crypto_codec_name(const RzCryptoSelector bit) {
|
|
size_t i;
|
|
for (i = 1; i < RZ_ARRAY_SIZE(codec_name_bytes); i++) {
|
|
if (bit == codec_name_bytes[i].bit) {
|
|
return codec_name_bytes[i].name;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
RZ_API RZ_BORROW const RzCryptoPlugin *rz_crypto_plugin_by_index(RZ_NONNULL RzCrypto *cry, size_t index) {
|
|
rz_return_val_if_fail(cry, NULL);
|
|
|
|
RzIterator *it = ht_sp_as_iter(cry->plugins);
|
|
RzCryptoPlugin **val;
|
|
size_t i = 0;
|
|
|
|
rz_iterator_foreach(it, val) {
|
|
const RzCryptoPlugin *plugin = *val;
|
|
if (i == index) {
|
|
rz_iterator_free(it);
|
|
return plugin;
|
|
}
|
|
i++;
|
|
}
|
|
rz_iterator_free(it);
|
|
return NULL;
|
|
}
|
|
|
|
RZ_API bool rz_crypto_plugin_add(RZ_NONNULL RzCrypto *cry, RZ_NONNULL RzCryptoPlugin *plugin) {
|
|
rz_return_val_if_fail(cry && plugin, false);
|
|
if (!ht_sp_insert(cry->plugins, plugin->name, plugin)) {
|
|
RZ_LOG_WARN("Plugin '%s' was already added.\n", plugin->name);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
RZ_API bool rz_crypto_plugin_del(RZ_NONNULL RzCrypto *cry, RZ_NONNULL RzCryptoPlugin *plugin) {
|
|
rz_return_val_if_fail(cry && plugin, false);
|
|
if (cry->h == plugin && cry->h->fini) {
|
|
cry->h->fini(cry);
|
|
cry->h = NULL;
|
|
}
|
|
ht_sp_delete(cry->plugins, plugin->name);
|
|
return true;
|
|
}
|
|
|
|
RZ_API RZ_OWN RzCrypto *rz_crypto_new(void) {
|
|
RzCrypto *cry = RZ_NEW0(RzCrypto);
|
|
if (!cry) {
|
|
goto rz_crypto_new_bad;
|
|
}
|
|
|
|
cry->output_size = RZ_CRYPTO_OUTPUT_SIZE;
|
|
cry->output = malloc(RZ_CRYPTO_OUTPUT_SIZE);
|
|
if (!cry->output) {
|
|
goto rz_crypto_new_bad;
|
|
}
|
|
|
|
cry->plugins = ht_sp_new(HT_STR_DUP, NULL, NULL);
|
|
if (!cry->plugins) {
|
|
goto rz_crypto_new_bad;
|
|
}
|
|
for (size_t i = 0; i < RZ_ARRAY_SIZE(crypto_static_plugins); ++i) {
|
|
if (!ht_sp_insert(cry->plugins, crypto_static_plugins[i]->name, crypto_static_plugins[i])) {
|
|
RZ_LOG_WARN("Plugin '%s' was already added.\n", crypto_static_plugins[i]->name);
|
|
}
|
|
}
|
|
return cry;
|
|
|
|
rz_crypto_new_bad:
|
|
RZ_LOG_ERROR("[!] crypto: failed to allocate\n");
|
|
rz_crypto_free(cry);
|
|
return NULL;
|
|
}
|
|
|
|
RZ_API void rz_crypto_free(RZ_NULLABLE RzCrypto *cry) {
|
|
if (!cry) {
|
|
return;
|
|
}
|
|
if (cry->h && cry->h->fini && !cry->h->fini(cry)) {
|
|
RZ_LOG_ERROR("[!] crypto: error terminating '%s' plugin\n", cry->h->name);
|
|
}
|
|
ht_sp_free(cry->plugins);
|
|
free(cry->output);
|
|
free(cry->key);
|
|
free(cry->iv);
|
|
free(cry);
|
|
}
|
|
|
|
/**
|
|
* \brief Reset the internal state of RzCrypto.
|
|
*
|
|
* Prepare the RzCrypto instance to be run on a new input. This includes
|
|
* resetting the current plugin, the output, key, iv.
|
|
*
|
|
* \param cry RzCrypto reference
|
|
*/
|
|
RZ_API void rz_crypto_reset(RZ_NONNULL RzCrypto *cry) {
|
|
rz_return_if_fail(cry);
|
|
|
|
if (cry->h && cry->h->fini && !cry->h->fini(cry)) {
|
|
RZ_LOG_ERROR("[!] crypto: error terminating '%s' plugin\n", cry->h->name);
|
|
}
|
|
cry->h = NULL;
|
|
RZ_FREE(cry->key);
|
|
RZ_FREE(cry->iv);
|
|
cry->output_len = 0;
|
|
}
|
|
|
|
RZ_API bool rz_crypto_use(RZ_NONNULL RzCrypto *cry, RZ_NONNULL const char *algo) {
|
|
rz_return_val_if_fail(cry && algo, false);
|
|
RzIterator *it = ht_sp_as_iter(cry->plugins);
|
|
RzCryptoPlugin **val;
|
|
if (cry->h && cry->h->fini && !cry->h->fini(cry)) {
|
|
RZ_LOG_ERROR("[!] crypto: error terminating '%s' plugin\n", cry->h->name);
|
|
}
|
|
rz_iterator_foreach(it, val) {
|
|
RzCryptoPlugin *h = *val;
|
|
rz_warn_if_fail(h && h->use);
|
|
if (h && h->use(algo)) {
|
|
if (h->init && !h->init(cry)) {
|
|
RZ_LOG_ERROR("[!] crypto: error initializing '%s' plugin\n", cry->h->name);
|
|
rz_iterator_free(it);
|
|
return false;
|
|
}
|
|
|
|
cry->h = h;
|
|
rz_iterator_free(it);
|
|
return true;
|
|
}
|
|
}
|
|
rz_iterator_free(it);
|
|
return false;
|
|
}
|
|
|
|
RZ_API bool rz_crypto_set_key(RZ_NULLABLE RzCrypto *cry, RZ_NULLABLE const ut8 *key, int keylen, int mode, int direction) {
|
|
if (keylen < 0) {
|
|
keylen = key ? strlen((const char *)key) : 0;
|
|
}
|
|
if (!cry || !cry->h || !cry->h->set_key) {
|
|
return false;
|
|
}
|
|
return cry->h->set_key(cry, key, keylen, mode, direction);
|
|
}
|
|
|
|
RZ_API bool rz_crypto_set_iv(RZ_NULLABLE RzCrypto *cry, RZ_NULLABLE const ut8 *iv, int ivlen) {
|
|
return (cry && cry->h && cry->h->set_iv) ? cry->h->set_iv(cry, iv, ivlen) : 0;
|
|
}
|
|
|
|
// return the number of bytes written in the output buffer
|
|
RZ_API int rz_crypto_update(RZ_NULLABLE RzCrypto *cry, RZ_NULLABLE const ut8 *buf, int len) {
|
|
return (cry && cry->h && cry->h->update) ? cry->h->update(cry, buf, len) : 0;
|
|
}
|
|
|
|
RZ_API int rz_crypto_final(RZ_NULLABLE RzCrypto *cry, RZ_NULLABLE const ut8 *buf, int len) {
|
|
return (cry && cry->h && cry->h->final) ? cry->h->final(cry, buf, len) : 0;
|
|
}
|
|
|
|
// TODO: internal api?? used from plugins? TODO: use rz_buf here
|
|
RZ_API int rz_crypto_append(RZ_NONNULL RzCrypto *cry, RZ_NONNULL const ut8 *buf, int len) {
|
|
rz_return_val_if_fail(cry && buf, -1);
|
|
if (cry->output_len + len > cry->output_size) {
|
|
cry->output_size += 4096 + len;
|
|
cry->output = realloc(cry->output, cry->output_size);
|
|
}
|
|
if (!cry->output) {
|
|
rz_warn_if_reached();
|
|
cry->output_size = 0;
|
|
return 0;
|
|
}
|
|
memcpy(cry->output + cry->output_len, buf, len);
|
|
cry->output_len += len;
|
|
return cry->output_len;
|
|
}
|
|
|
|
RZ_API RZ_BORROW const ut8 *rz_crypto_get_output(RZ_NONNULL RzCrypto *cry, RZ_NULLABLE int *size) {
|
|
rz_return_val_if_fail(cry, NULL);
|
|
if (cry->output_size < 1 || !cry->output) {
|
|
if (size) {
|
|
*size = 0;
|
|
}
|
|
return NULL;
|
|
}
|
|
if (size) {
|
|
*size = cry->output_len;
|
|
}
|
|
return cry->output;
|
|
}
|