radare2/libr/crypto/crypto.c
2022-09-26 18:23:07 +02:00

228 lines
5.2 KiB
C

/* radare - LGPL - Copyright 2009-2022 - pancake */
#include "r_crypto.h"
#include "r_hash.h"
#include "config.h"
#include "r_util/r_assert.h"
R_LIB_VERSION (r_crypto);
static RCryptoPlugin *crypto_static_plugins[] = {
R_CRYPTO_STATIC_PLUGINS
};
R_API void r_crypto_init(RCrypto *cry) {
r_return_if_fail (cry);
int i;
cry->user = NULL;
cry->plugins = r_list_newf (NULL);
for (i = 0; crypto_static_plugins[i]; i++) {
RCryptoPlugin *p = R_NEW0 (RCryptoPlugin);
if (p) {
memcpy (p, crypto_static_plugins[i], sizeof (RCryptoPlugin));
r_crypto_add (cry, p);
}
}
// TODO register hash algorithms
}
R_API bool r_crypto_add(RCrypto *cry, RCryptoPlugin *h) {
r_return_val_if_fail (cry && cry->plugins && h, false);
r_list_append (cry->plugins, h);
return true;
}
R_API bool r_crypto_del(RCrypto *cry, RCryptoPlugin *h) {
r_return_val_if_fail (cry && h, false);
r_list_delete_data (cry->plugins, h);
return true;
}
R_API RCrypto *r_crypto_new(void) {
RCrypto *cry = R_NEW0 (RCrypto);
r_crypto_init (cry);
return cry;
}
R_API void r_crypto_job_free(RCryptoJob *cj) {
if (cj) {
if (cj->h->fini) {
cj->h->fini (cj);
}
free (cj->output);
free (cj->key);
free (cj->iv);
free (cj);
}
}
R_API void r_crypto_free(RCrypto *cry) {
if (cry) {
#if 0
RListIter *iter;
RCryptoPlugin *p;
r_list_foreach (cry->plugins, iter, p) {
if (p->fini) {
p->fini (cry, p);
}
}
#endif
r_list_free (cry->plugins);
free (cry);
}
}
R_API RCryptoJob *r_crypto_use(RCrypto *cry, const char *algo) {
r_return_val_if_fail (cry && algo, false);
RListIter *iter, *iter2;
RCryptoPlugin *h;
r_list_foreach (cry->plugins, iter, h) {
if (h && R_STR_ISNOTEMPTY (h->implements)) {
char *impls = strdup (h->implements);
RList *l = r_str_split_list (impls, ",", 0);
const char *s;
r_list_foreach (l, iter2, s) {
if (!strcmp (s, algo)) {
cry->h = h;
r_list_free (l);
return r_crypto_job_new (cry, h);
}
}
r_list_free (l);
free (impls);
}
// XXX deprecate
if (h && h->check && h->check (algo)) {
// R_DEPRECATE cry->h = h;
return r_crypto_job_new (cry, h);
}
}
return NULL;
}
R_API bool r_crypto_job_set_key(RCryptoJob *cj, const ut8* key, int keylen, int mode, int direction) {
r_return_val_if_fail (cj, false);
if (keylen < 0) {
keylen = strlen ((const char *)key);
}
if (!cj->h || !cj->h->set_key) {
return false;
}
cj->key_len = keylen;
cj->key = calloc (1, cj->key_len);
return cj->h->set_key (cj, key, keylen, mode, direction);
}
R_API int r_crypto_job_get_key_size(RCryptoJob *cj) {
r_return_val_if_fail (cj, false);
return (cj->h && cj->h->get_key_size)?
cj->h->get_key_size (cj): 0;
}
R_API bool r_crypto_job_set_iv(RCryptoJob *cj, const ut8 *iv, int ivlen) {
r_return_val_if_fail (cj, false);
return (cj->h && cj->h->set_iv)?
cj->h->set_iv (cj, iv, ivlen): 0;
}
// return the number of bytes written in the output buffer
R_API bool r_crypto_job_update(RCryptoJob *cj, const ut8 *buf, int len) {
r_return_val_if_fail (cj, 0);
return (cj->h && cj->h->update)? cj->h->update (cj, buf, len): 0;
}
R_API RCryptoJob *r_crypto_job_new(RCrypto *cry, RCryptoPlugin *cp) {
RCryptoJob *cj = R_NEW0 (RCryptoJob);
if (R_UNLIKELY (cj)) {
cj->h = cp;
cj->c = cry;
}
return cj;
}
R_API bool r_crypto_job_end(RCryptoJob *cj, const ut8 *buf, int len) {
r_return_val_if_fail (cj, 0);
return (cj->h && cj->h->end)? cj->h->end (cj, buf, len): 0;
}
// TODO: internal api?? used from plugins? TODO: use r_buf here
R_API int r_crypto_job_append(RCryptoJob *cj, const ut8 *buf, int len) {
r_return_val_if_fail (cj&& buf, -1);
if (cj->output_len+len > cj->output_size) {
cj->output_size += 4096 + len;
cj->output = realloc (cj->output, cj->output_size);
}
memcpy (cj->output + cj->output_len, buf, len);
cj->output_len += len;
return cj->output_len;
}
R_API ut8 *r_crypto_job_get_output(RCryptoJob *cj, int *size) {
r_return_val_if_fail (cj, NULL);
if (cj->output_size < 1) {
return NULL;
}
ut8 *buf = calloc (1, cj->output_size);
if (!buf) {
return NULL;
}
if (size) {
*size = cj->output_len;
memcpy (buf, cj->output, *size);
} else {
size_t newlen = 4096;
ut8 *newbuf = realloc (buf, newlen);
if (!newbuf) {
free (buf);
return NULL;
}
buf = newbuf;
cj->output = newbuf;
cj->output_len = 0;
cj->output_size = newlen;
return NULL;
}
return buf;
}
R_API void r_crypto_list(RCrypto *cry, PrintfCallback cb_printf, int mode) {
if (!cb_printf) {
cb_printf = (PrintfCallback)printf;
}
RListIter *iter;
RCryptoPlugin *cp;
r_list_foreach (cry->plugins, iter, cp) {
switch (mode) {
case 'q':
cb_printf ("%s\n", cp->name);
break;
default:
{
char mode = cp->type? cp->type: 'c';
const char *license = cp->license? cp->license: "LGPL";
const char *desc = r_str_get (cp->desc);
const char *author = r_str_get (cp->author);
cb_printf ("%c %12s %5s %s %s\n", mode, cp->name, license, desc, author);
}
break;
}
}
// TODO: move all those static hashes into crypto plugins
int i;
for (i = 0; i < 64; i++) {
ut64 bits = ((ut64)1) << i;
const char *name = r_hash_name (bits);
if R_STR_ISEMPTY (name) {
continue;
}
switch (mode) {
case 'q':
cb_printf ("%s\n", name);
break;
default:
cb_printf ("h %12s\n", name);
break;
}
}
}