radare2/libr/crypto/crypto.c
2021-09-28 10:40:22 +02:00

210 lines
4.8 KiB
C

/* radare - LGPL - Copyright 2009-2017 - pancake */
#include "r_crypto.h"
#include "config.h"
R_LIB_VERSION (r_crypto);
static const struct {
const char *name;
RCryptoSelector bit;
} crypto_name_bytes[] = {
{ "all", UT64_MAX },
{ "rc2", R_CRYPTO_RC2 },
{ "rc4", R_CRYPTO_RC4 },
{ "rc6", R_CRYPTO_RC6 },
{ "aes-ecb", R_CRYPTO_AES_ECB },
{ "aes-cbc", R_CRYPTO_AES_CBC },
{ "aes-wrap", R_CRYPTO_AES_WRAP },
{ "ror", R_CRYPTO_ROR },
{ "rol", R_CRYPTO_ROL },
{ "rot", R_CRYPTO_ROT },
{ "blowfish", R_CRYPTO_BLOWFISH },
{ "cps2", R_CRYPTO_CPS2 },
{ "des-ecb", R_CRYPTO_DES_ECB },
{ "xor", R_CRYPTO_XOR },
{ "serpent-ecb", R_CRYPTO_SERPENT },
{ NULL, 0 }
};
static const struct {
const char *name;
RCryptoSelector bit;
} codec_name_bytes[] = {
{ "all", UT64_MAX },
{ "base64", R_CODEC_B64 },
{ "base91", R_CODEC_B91 },
{ "punycode", R_CODEC_PUNYCODE },
{ NULL, 0 }
};
R_API const char *r_crypto_name(const RCryptoSelector bit) {
size_t i;
for (i = 1; crypto_name_bytes[i].bit; i++) {
if (bit & crypto_name_bytes[i].bit) {
return crypto_name_bytes[i].name;
}
}
return "";
}
R_API const char *r_crypto_codec_name(const RCryptoSelector bit) {
size_t i;
for (i = 1; codec_name_bytes[i].bit; i++) {
if (bit & codec_name_bytes[i].bit) {
return codec_name_bytes[i].name;
}
}
return "";
}
static RCryptoPlugin *crypto_static_plugins[] = {
R_CRYPTO_STATIC_PLUGINS
};
R_API RCrypto *r_crypto_init(RCrypto *cry, int hard) {
int i;
if (cry) {
cry->iv = NULL;
cry->key = NULL;
cry->key_len = 0;
cry->user = NULL;
if (hard) {
// first call initializes the output_* variables
r_crypto_get_output (cry, NULL);
cry->plugins = r_list_newf (NULL);
for (i = 0; crypto_static_plugins[i]; i++) {
RCryptoPlugin *p = R_NEW0 (RCryptoPlugin);
if (!p) {
free (cry);
return NULL;
}
memcpy (p, crypto_static_plugins[i], sizeof (RCryptoPlugin));
r_crypto_add (cry, p);
}
}
}
return cry;
}
R_API int r_crypto_add(RCrypto *cry, RCryptoPlugin *h) {
// add a check ?
r_list_append (cry->plugins, h);
return true;
}
R_API int r_crypto_del(RCrypto *cry, RCryptoPlugin *h) {
r_list_delete_data (cry->plugins, h);
return true;
}
R_API struct r_crypto_t *r_crypto_new(void) {
RCrypto *cry = R_NEW0 (RCrypto);
return r_crypto_init (cry, true);
}
R_API struct r_crypto_t *r_crypto_as_new(struct r_crypto_t *cry) {
RCrypto *c = R_NEW0 (RCrypto);
if (c) {
r_crypto_init (c, false); // soft init
memcpy (&c->plugins, &cry->plugins, sizeof (cry->plugins));
}
return c;
}
R_API struct r_crypto_t *r_crypto_free(RCrypto *cry) {
// TODO: call the destructor function of the plugin to destroy the *user pointer if needed
r_list_free (cry->plugins);
free (cry->output);
free (cry->key);
free (cry->iv);
free (cry);
return NULL;
}
R_API bool r_crypto_use(RCrypto *cry, const char *algo) {
RListIter *iter;
RCryptoPlugin *h;
r_list_foreach (cry->plugins, iter, h) {
if (h && h->use && h->use (algo)) {
cry->h = h;
return cry->h != NULL;
}
}
return false;
}
R_API bool r_crypto_set_key(RCrypto *cry, const ut8* key, int keylen, int mode, int direction) {
if (keylen < 0) {
keylen = strlen ((const char *)key);
}
if (!cry || !cry->h || !cry->h->set_key) {
return false;
}
cry->key_len = keylen;
cry->key = calloc (1, cry->key_len);
return cry->h->set_key (cry, key, keylen, mode, direction);
}
R_API int r_crypto_get_key_size(RCrypto *cry) {
return (cry && cry->h && cry->h->get_key_size)?
cry->h->get_key_size (cry): 0;
}
R_API bool r_crypto_set_iv(RCrypto *cry, 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
R_API int r_crypto_update(RCrypto *cry, const ut8 *buf, int len) {
return (cry && cry->h && cry->h->update)?
cry->h->update (cry, buf, len): 0;
}
R_API int r_crypto_final(RCrypto *cry, 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 r_buf here
R_API int r_crypto_append(RCrypto *cry, const ut8 *buf, int len) {
if (!cry || !buf) {
return -1;
}
if (cry->output_len+len > cry->output_size) {
cry->output_size += 4096 + len;
cry->output = realloc (cry->output, cry->output_size);
}
memcpy (cry->output + cry->output_len, buf, len);
cry->output_len += len;
return cry->output_len;
}
R_API ut8 *r_crypto_get_output(RCrypto *cry, int *size) {
if (cry->output_size < 1) {
return NULL;
}
ut8 *buf = calloc (1, cry->output_size);
if (!buf) {
return NULL;
}
if (size) {
*size = cry->output_len;
memcpy (buf, cry->output, *size);
} else {
/* initialize */
const int size = 4096;
cry->output = realloc (buf, size);
if (!cry->output) {
free (buf);
return NULL;
}
cry->output_len = 0;
cry->output_size = size;
return NULL;
}
return buf;
}