diff --git a/librz/core/cmd_write.c b/librz/core/cmd_write.c index 562bc4fe15..f838ad1493 100644 --- a/librz/core/cmd_write.c +++ b/librz/core/cmd_write.c @@ -203,13 +203,12 @@ static bool encrypt_or_decrypt_block(RzCore *core, const char *algo, const char rz_crypto_final(cry, NULL, 0); int result_size = 0; - ut8 *result = rz_crypto_get_output(cry, &result_size); + const ut8 *result = rz_crypto_get_output(cry, &result_size); if (result) { if (!rz_core_write_at(core, core->offset, result, result_size)) { eprintf("rz_core_write_at failed at 0x%08" PFMT64x "\n", core->offset); } eprintf("Written %d byte(s)\n", result_size); - free(result); } } else { eprintf("Invalid key\n"); diff --git a/librz/crypto/crypto.c b/librz/crypto/crypto.c index 1f01da9cb9..6806082460 100644 --- a/librz/crypto/crypto.c +++ b/librz/crypto/crypto.c @@ -1,8 +1,11 @@ // SPDX-FileCopyrightText: 2009-2017 pancake // SPDX-License-Identifier: LGPL-3.0-only -#include "rz_crypto.h" +#include #include "config.h" +#include + +#define RZ_CRYPTO_OUTPUT_SIZE 4096 RZ_LIB_VERSION(rz_crypto); @@ -24,7 +27,6 @@ static const struct { { "des-ecb", RZ_CRYPTO_DES_ECB }, { "xor", RZ_CRYPTO_XOR }, { "serpent-ecb", RZ_CRYPTO_SERPENT }, - { NULL, 0 } }; static const struct { @@ -35,13 +37,12 @@ static const struct { { "base64", RZ_CODEC_B64 }, { "base91", RZ_CODEC_B91 }, { "punycode", RZ_CODEC_PUNYCODE }, - { NULL, 0 } }; RZ_API const char *rz_crypto_name(const RzCryptoSelector bit) { size_t i; - for (i = 1; crypto_name_bytes[i].bit; i++) { - if (bit & crypto_name_bytes[i].bit) { + for (i = 1; i < RZ_ARRAY_SIZE(crypto_name_bytes); i++) { + if (bit == crypto_name_bytes[i].bit) { return crypto_name_bytes[i].name; } } @@ -50,8 +51,8 @@ RZ_API const char *rz_crypto_name(const RzCryptoSelector bit) { RZ_API const char *rz_crypto_codec_name(const RzCryptoSelector bit) { size_t i; - for (i = 1; codec_name_bytes[i].bit; i++) { - if (bit & codec_name_bytes[i].bit) { + for (i = 1; i < RZ_ARRAY_SIZE(codec_name_bytes); i++) { + if (bit == codec_name_bytes[i].bit) { return codec_name_bytes[i].name; } } @@ -62,31 +63,6 @@ static RzCryptoPlugin *crypto_static_plugins[] = { RZ_CRYPTO_STATIC_PLUGINS }; -RZ_API RzCrypto *rz_crypto_init(RzCrypto *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 - rz_crypto_get_output(cry, NULL); - cry->plugins = rz_list_newf(NULL); - for (i = 0; crypto_static_plugins[i]; i++) { - RzCryptoPlugin *p = RZ_NEW0(RzCryptoPlugin); - if (!p) { - free(cry); - return NULL; - } - memcpy(p, crypto_static_plugins[i], sizeof(RzCryptoPlugin)); - rz_crypto_add(cry, p); - } - } - } - return cry; -} - RZ_API int rz_crypto_add(RzCrypto *cry, RzCryptoPlugin *h) { // add a check ? rz_list_append(cry->plugins, h); @@ -98,22 +74,43 @@ RZ_API int rz_crypto_del(RzCrypto *cry, RzCryptoPlugin *h) { return true; } -RZ_API struct rz_crypto_t *rz_crypto_new(void) { +RZ_API RzCrypto *rz_crypto_new(void) { RzCrypto *cry = RZ_NEW0(RzCrypto); - return rz_crypto_init(cry, true); -} - -RZ_API struct rz_crypto_t *rz_crypto_as_new(struct rz_crypto_t *cry) { - RzCrypto *c = RZ_NEW0(RzCrypto); - if (c) { - rz_crypto_init(c, false); // soft init - memcpy(&c->plugins, &cry->plugins, sizeof(cry->plugins)); + if (!cry) { + goto rz_crypto_new_bad; } - return c; + + cry->output_size = RZ_CRYPTO_OUTPUT_SIZE; + cry->output = malloc(RZ_CRYPTO_OUTPUT_SIZE); + if (!cry->output) { + goto rz_crypto_new_bad; + } + + cry->plugins = rz_list_newf((RzListFree)free); + if (!cry->plugins) { + goto rz_crypto_new_bad; + } + + for (ut32 i = 0; crypto_static_plugins[i]; i++) { + RzCryptoPlugin *p = RZ_NEW0(RzCryptoPlugin); + if (!p) { + goto rz_crypto_new_bad; + } + memcpy(p, crypto_static_plugins[i], sizeof(RzCryptoPlugin)); + rz_crypto_add(cry, p); + } + return cry; + +rz_crypto_new_bad: + RZ_LOG_ERROR("[!] crypto: failed to allocate\n"); + rz_crypto_free(cry); + return NULL; } RZ_API struct rz_crypto_t *rz_crypto_free(RzCrypto *cry) { - // TODO: call the destructor function of the plugin to destroy the *user pointer if needed + if (cry->h && cry->h->fini && !cry->h->fini(cry)) { + RZ_LOG_ERROR("[!] crypto: error terminating '%s' plugin\n", cry->h->name); + } rz_list_free(cry->plugins); free(cry->output); free(cry->key); @@ -125,12 +122,19 @@ RZ_API struct rz_crypto_t *rz_crypto_free(RzCrypto *cry) { RZ_API bool rz_crypto_use(RzCrypto *cry, const char *algo) { RzListIter *iter; RzCryptoPlugin *h; + if (cry->h && cry->h->fini && !cry->h->fini(cry)) { + RZ_LOG_ERROR("[!] crypto: error terminating '%s' plugin\n", cry->h->name); + } rz_list_foreach (cry->plugins, iter, h) { - if (h && h->use && h->use(algo)) { + 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); + return false; + } + cry->h = h; - cry->key_len = h->get_key_size(cry); - cry->key = calloc(1, cry->key_len); - return cry->key != NULL; + return true; } } return false; @@ -146,10 +150,6 @@ RZ_API bool rz_crypto_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mod return cry->h->set_key(cry, key, keylen, mode, direction); } -RZ_API int rz_crypto_get_key_size(RzCrypto *cry) { - return (cry && cry->h && cry->h->get_key_size) ? cry->h->get_key_size(cry) : 0; -} - RZ_API bool rz_crypto_set_iv(RzCrypto *cry, const ut8 *iv, int ivlen) { return (cry && cry->h && cry->h->set_iv) ? cry->h->set_iv(cry, iv, ivlen) : 0; } @@ -172,34 +172,25 @@ RZ_API int rz_crypto_append(RzCrypto *cry, const ut8 *buf, int len) { 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 ut8 *rz_crypto_get_output(RzCrypto *cry, int *size) { - if (cry->output_size < 1) { - return NULL; - } - ut8 *buf = calloc(1, cry->output_size); - if (!buf) { +RZ_API const ut8 *rz_crypto_get_output(RzCrypto *cry, int *size) { + if (cry->output_size < 1 || !cry->output) { + if (size) { + *size = 0; + } 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; + return cry->output; } diff --git a/librz/crypto/p/crypto_aes.c b/librz/crypto/p/crypto_aes.c index d585e34ccd..13f59d43c8 100644 --- a/librz/crypto/p/crypto_aes.c +++ b/librz/crypto/p/crypto_aes.c @@ -5,23 +5,26 @@ #include #include "crypto_aes_algo.h" -// TODO: avoid globals -static struct aes_state st = { { 0 } }; - static bool aes_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { + rz_return_val_if_fail(cry->user && key, false); + aes_state_t *st = (aes_state_t *)cry->user; + if (!(keylen == 128 / 8 || keylen == 192 / 8 || keylen == 256 / 8)) { return false; } - st.key_size = keylen; - st.rounds = 6 + (int)(keylen / 4); - st.columns = (int)(keylen / 4); - memcpy(st.key, key, keylen); + st->key_size = keylen; + st->rounds = 6 + (int)(keylen / 4); + st->columns = (int)(keylen / 4); + memcpy(st->key, key, keylen); cry->dir = direction; return true; } static int aes_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + aes_state_t *st = (aes_state_t *)cry->user; + + return st->key_size; } static bool aes_use(const char *algo) { @@ -31,6 +34,13 @@ static bool aes_use(const char *algo) { #define BLOCK_SIZE 16 static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, 0); + aes_state_t *st = (aes_state_t *)cry->user; + + if (len < 1) { + return false; + } + // Pad to the block size, do not append dummy block const int diff = (BLOCK_SIZE - (len % BLOCK_SIZE)) % BLOCK_SIZE; const int size = len + diff; @@ -54,15 +64,15 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { ibuf[len] = 8; //0b1000; } - if (cry->dir == 0) { + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { for (i = 0; i < blocks; i++) { const int delta = BLOCK_SIZE * i; - aes_encrypt(&st, ibuf + delta, obuf + delta); + aes_encrypt(st, ibuf + delta, obuf + delta); } - } else if (cry->dir > 0) { + } else { for (i = 0; i < blocks; i++) { const int delta = BLOCK_SIZE * i; - aes_decrypt(&st, ibuf + delta, obuf + delta); + aes_decrypt(st, ibuf + delta, obuf + delta); } } @@ -78,13 +88,29 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool aes_ecb_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(aes_state_t); + return cry->user != NULL; +} + +static bool aes_ecb_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_aes = { .name = "aes-ecb", .set_key = aes_set_key, .get_key_size = aes_get_key_size, .use = aes_use, .update = update, - .final = final + .final = final, + .init = aes_ecb_init, + .fini = aes_ecb_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_aes_algo.c b/librz/crypto/p/crypto_aes_algo.c index 596f906a5c..b28177f855 100644 --- a/librz/crypto/p/crypto_aes_algo.c +++ b/librz/crypto/p/crypto_aes_algo.c @@ -1,19 +1,11 @@ -// original code from: -//==================== -// advanced encryption standard -// author: karl malbrain, malbrain@yahoo.com -// -// adapted from Christophe Devine's tables -// and George Anescu's c++ code. +// SPDX-FileCopyrightText: Karl Malbrain +// SPDX-License-Identifier: MS-PL #include "crypto_aes_algo.h" -#define Nb 4 // number of columns in the state & expanded key - -// #define Nk 4 // number of columns in a key -// #define Nr 10 // number of rounds in encryption -// #define AES_KEY (4 * Nk) -// #define ROUND_KEY_COUNT ((Nr + 1) * 4) +#define Nb 4 // number of columns in the state & expanded key +#define Nr 16 // max number of rounds in encryption +#define Nk 8 // max number of columns in a key static const ut8 Rcon[30] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, @@ -22,45 +14,30 @@ static const ut8 Rcon[30] = { 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; -// Expand a user-supplied key material into a session key. -// key - The 128/192/256-bit user-key to use. -//expkey[2][Nr + 1][Nb] -//void aes_expkey (const struct aes_state *st, ut32 ***expkey) { //expkey[2][st->rounds + 1][Nb]) { -#if defined(__GNUC__) -void aes_expkey(const struct aes_state *st, ut32 expkey[2][st->rounds + 1][Nb]) -#else -// XXX this is wrong, but at least it compiles -#ifdef _MSC_VER -#pragma message("AES broken for non-gcc compilers") -#else -#warning AES broken for non-gcc compilers -#endif -#define Nr_AES256 (6 + ((256 / 8) / 4)) -void aes_expkey(const struct aes_state *st, ut32 expkey[2][Nr_AES256 + 1][Nb]) -#endif -{ - // ut32 expkey[2][st->rounds + 1][Nb]; - // memcpy (&expkey, _expkey, 2 * (st->rounds + 1) * Nb); - int ROUND_KEY_COUNT = 4 * (1 + st->rounds); -#ifdef _MSC_VER - ut32 *tk = (ut32 *)malloc(sizeof(ut32) * st->columns); -#else - ut32 tk[st->columns]; -#endif +typedef struct { + ut32 key0[Nr][Nb]; + ut32 key1[Nr][Nb]; +} expkey_t; + +void aes_expkey(const aes_state_t *st, expkey_t *ek) { + rz_return_if_fail(st->rounds <= Nr && st->columns <= Nk); // This can't happen + + int round_key_count = 4 * (1 + st->rounds); + ut32 tk[Nk]; + ut32 tt; st32 idx = 0, t = 0; const ut8 *key = st->key; st32 i, j, r; - for (i = 0; i <= st->rounds; i++) { for (j = 0; j < Nb; j++) { - expkey[0][i][j] = 0; + ek->key0[i][j] = 0; } } for (i = 0; i <= st->rounds; i++) { for (j = 0; j < Nb; j++) { - expkey[1][i][j] = 0; + ek->key1[i][j] = 0; } } @@ -73,12 +50,12 @@ void aes_expkey(const struct aes_state *st, ut32 expkey[2][Nr_AES256 + 1][Nb]) } // Copy values into round key arrays - for (j = 0; j < st->columns && t < ROUND_KEY_COUNT; j++, t++) { - expkey[0][t / Nb][t % Nb] = tk[j]; - expkey[1][st->rounds - (t / Nb)][t % Nb] = tk[j]; + for (j = 0; j < st->columns && t < round_key_count; j++, t++) { + ek->key0[t / Nb][t % Nb] = tk[j]; + ek->key1[st->rounds - (t / Nb)][t % Nb] = tk[j]; } - while (t < ROUND_KEY_COUNT) { + while (t < round_key_count) { // Extrapolate using phi (the round key evolution function) tt = tk[st->columns - 1]; tk[0] ^= Sbox[(ut8)(tt >> 16)] << 24 ^ Sbox[(ut8)(tt >> 8)] << 16 ^ @@ -102,35 +79,29 @@ void aes_expkey(const struct aes_state *st, ut32 expkey[2][Nr_AES256 + 1][Nb]) } // Copy values into round key arrays - for (j = 0; j < st->columns && t < ROUND_KEY_COUNT; j++, t++) { - expkey[0][t / Nb][t % Nb] = tk[j]; - expkey[1][st->rounds - (t / Nb)][t % Nb] = tk[j]; + for (j = 0; j < st->columns && t < round_key_count; j++, t++) { + ek->key0[t / Nb][t % Nb] = tk[j]; + ek->key1[st->rounds - (t / Nb)][t % Nb] = tk[j]; } } // Inverse MixColumn where needed for (r = 1; r < st->rounds; r++) { for (j = 0; j < Nb; j++) { - tt = expkey[1][r][j]; - expkey[1][r][j] = U0[(ut8)(tt >> 24)] ^ U1[(ut8)(tt >> 16)] ^ + tt = ek->key1[r][j]; + ek->key1[r][j] = U0[(ut8)(tt >> 24)] ^ U1[(ut8)(tt >> 16)] ^ U2[(ut8)(tt >> 8)] ^ U3[(ut8)tt]; } } -#ifdef _MSC_VER - free(tk); -#endif } // Convenience method to encrypt exactly one block of plaintext, assuming // Rijndael's default block size (128-bit). // in - The plaintext // result - The ciphertext generated from a plaintext using the key -void aes_encrypt(struct aes_state *st, ut8 *in, ut8 *result) { -#if defined(_MSC_VER) || defined(__TINYC__) - ut32 expkey[2][Nr_AES256 + 1][Nb]; -#else - ut32 expkey[2][st->rounds + 1][Nb]; -#endif - aes_expkey(st, expkey); +void aes_encrypt(aes_state_t *st, ut8 *in, ut8 *result) { + expkey_t ek = { 0 }; + + aes_expkey(st, &ek); ut32 t0, t1, t2, t3, tt; ut32 a0, a1, a2, a3, r; @@ -139,25 +110,25 @@ void aes_encrypt(struct aes_state *st, ut8 *in, ut8 *result) { t0 |= *in++ << 16; t0 |= *in++ << 8; t0 |= *in++; - t0 ^= expkey[0][0][0]; + t0 ^= ek.key0[0][0]; t1 = *in++ << 24; t1 |= *in++ << 16; t1 |= *in++ << 8; t1 |= *in++; - t1 ^= expkey[0][0][1]; + t1 ^= ek.key0[0][1]; t2 = *in++ << 24; t2 |= *in++ << 16; t2 |= *in++ << 8; t2 |= *in++; - t2 ^= expkey[0][0][2]; + t2 ^= ek.key0[0][2]; t3 = *in++ << 24; t3 |= *in++ << 16; t3 |= *in++ << 8; t3 |= *in++; - t3 ^= expkey[0][0][3]; + t3 ^= ek.key0[0][3]; // Apply Round Transforms for (r = 1; r < st->rounds; r++) { @@ -169,33 +140,33 @@ void aes_encrypt(struct aes_state *st, ut8 *in, ut8 *result) { FT3[(ut8)t1]); a3 = (FT0[(ut8)(t3 >> 24)] ^ FT1[(ut8)(t0 >> 16)] ^ FT2[(ut8)(t1 >> 8)] ^ FT3[(ut8)t2]); - t0 = a0 ^ expkey[0][r][0]; - t1 = a1 ^ expkey[0][r][1]; - t2 = a2 ^ expkey[0][r][2]; - t3 = a3 ^ expkey[0][r][3]; + t0 = a0 ^ ek.key0[r][0]; + t1 = a1 ^ ek.key0[r][1]; + t2 = a2 ^ ek.key0[r][2]; + t3 = a3 ^ ek.key0[r][3]; } // Last Round is special - tt = expkey[0][st->rounds][0]; + tt = ek.key0[st->rounds][0]; result[0] = Sbox[(ut8)(t0 >> 24)] ^ (ut8)(tt >> 24); result[1] = Sbox[(ut8)(t1 >> 16)] ^ (ut8)(tt >> 16); result[2] = Sbox[(ut8)(t2 >> 8)] ^ (ut8)(tt >> 8); result[3] = Sbox[(ut8)t3] ^ (ut8)tt; - tt = expkey[0][st->rounds][1]; + tt = ek.key0[st->rounds][1]; result[4] = Sbox[(ut8)(t1 >> 24)] ^ (ut8)(tt >> 24); result[5] = Sbox[(ut8)(t2 >> 16)] ^ (ut8)(tt >> 16); result[6] = Sbox[(ut8)(t3 >> 8)] ^ (ut8)(tt >> 8); result[7] = Sbox[(ut8)t0] ^ (ut8)tt; - tt = expkey[0][st->rounds][2]; + tt = ek.key0[st->rounds][2]; result[8] = Sbox[(ut8)(t2 >> 24)] ^ (ut8)(tt >> 24); result[9] = Sbox[(ut8)(t3 >> 16)] ^ (ut8)(tt >> 16); result[10] = Sbox[(ut8)(t0 >> 8)] ^ (ut8)(tt >> 8); result[11] = Sbox[(ut8)t1] ^ (ut8)tt; - tt = expkey[0][st->rounds][3]; + tt = ek.key0[st->rounds][3]; result[12] = Sbox[(ut8)(t3 >> 24)] ^ (ut8)(tt >> 24); result[13] = Sbox[(ut8)(t0 >> 16)] ^ (ut8)(tt >> 16); result[14] = Sbox[(ut8)(t1 >> 8)] ^ (ut8)(tt >> 8); @@ -206,14 +177,10 @@ void aes_encrypt(struct aes_state *st, ut8 *in, ut8 *result) { // Rijndael's default block size (128-bit). // in - The ciphertext. // result - The plaintext generated from a ciphertext using the session key. -void aes_decrypt(struct aes_state *st, ut8 *in, ut8 *result) { -#if defined(_MSC_VER) || defined(__TINYC__) - ut32 expkey[2][Nr_AES256 + 1][Nb]; -#else - ut32 expkey[2][st->rounds + 1][Nb]; -#endif +void aes_decrypt(aes_state_t *st, ut8 *in, ut8 *result) { + expkey_t ek = { 0 }; - aes_expkey(st, expkey); + aes_expkey(st, &ek); ut32 t0, t1, t2, t3, tt; ut32 a0, a1, a2, a3, r; @@ -222,25 +189,25 @@ void aes_decrypt(struct aes_state *st, ut8 *in, ut8 *result) { t0 |= *in++ << 16; t0 |= *in++ << 8; t0 |= *in++; - t0 ^= expkey[1][0][0]; + t0 ^= ek.key1[0][0]; t1 = *in++ << 24; t1 |= *in++ << 16; t1 |= *in++ << 8; t1 |= *in++; - t1 ^= expkey[1][0][1]; + t1 ^= ek.key1[0][1]; t2 = *in++ << 24; t2 |= *in++ << 16; t2 |= *in++ << 8; t2 |= *in++; - t2 ^= expkey[1][0][2]; + t2 ^= ek.key1[0][2]; t3 = *in++ << 24; t3 |= *in++ << 16; t3 |= *in++ << 8; t3 |= *in++; - t3 ^= expkey[1][0][3]; + t3 ^= ek.key1[0][3]; // Apply round transforms for (r = 1; r < st->rounds; r++) { @@ -248,32 +215,32 @@ void aes_decrypt(struct aes_state *st, ut8 *in, ut8 *result) { a1 = (RT0[(ut8)(t1 >> 24)] ^ RT1[(ut8)(t0 >> 16)] ^ RT2[(ut8)(t3 >> 8)] ^ RT3[(ut8)t2]); a2 = (RT0[(ut8)(t2 >> 24)] ^ RT1[(ut8)(t1 >> 16)] ^ RT2[(ut8)(t0 >> 8)] ^ RT3[(ut8)t3]); a3 = (RT0[(ut8)(t3 >> 24)] ^ RT1[(ut8)(t2 >> 16)] ^ RT2[(ut8)(t1 >> 8)] ^ RT3[(ut8)t0]); - t0 = a0 ^ expkey[1][r][0]; - t1 = a1 ^ expkey[1][r][1]; - t2 = a2 ^ expkey[1][r][2]; - t3 = a3 ^ expkey[1][r][3]; + t0 = a0 ^ ek.key1[r][0]; + t1 = a1 ^ ek.key1[r][1]; + t2 = a2 ^ ek.key1[r][2]; + t3 = a3 ^ ek.key1[r][3]; } // Last Round is special - tt = expkey[1][st->rounds][0]; + tt = ek.key1[st->rounds][0]; result[0] = InvSbox[(ut8)(t0 >> 24)] ^ (ut8)(tt >> 24); result[1] = InvSbox[(ut8)(t3 >> 16)] ^ (ut8)(tt >> 16); result[2] = InvSbox[(ut8)(t2 >> 8)] ^ (ut8)(tt >> 8); result[3] = InvSbox[(ut8)t1] ^ (ut8)tt; - tt = expkey[1][st->rounds][1]; + tt = ek.key1[st->rounds][1]; result[4] = InvSbox[(ut8)(t1 >> 24)] ^ (ut8)(tt >> 24); result[5] = InvSbox[(ut8)(t0 >> 16)] ^ (ut8)(tt >> 16); result[6] = InvSbox[(ut8)(t3 >> 8)] ^ (ut8)(tt >> 8); result[7] = InvSbox[(ut8)t2] ^ (ut8)tt; - tt = expkey[1][st->rounds][2]; + tt = ek.key1[st->rounds][2]; result[8] = InvSbox[(ut8)(t2 >> 24)] ^ (ut8)(tt >> 24); result[9] = InvSbox[(ut8)(t1 >> 16)] ^ (ut8)(tt >> 16); result[10] = InvSbox[(ut8)(t0 >> 8)] ^ (ut8)(tt >> 8); result[11] = InvSbox[(ut8)t3] ^ (ut8)tt; - tt = expkey[1][st->rounds][3]; + tt = ek.key1[st->rounds][3]; result[12] = InvSbox[(ut8)(t3 >> 24)] ^ (ut8)(tt >> 24); result[13] = InvSbox[(ut8)(t2 >> 16)] ^ (ut8)(tt >> 16); result[14] = InvSbox[(ut8)(t1 >> 8)] ^ (ut8)(tt >> 8); diff --git a/librz/crypto/p/crypto_aes_algo.h b/librz/crypto/p/crypto_aes_algo.h index a2a697d599..2c5ecbd371 100644 --- a/librz/crypto/p/crypto_aes_algo.h +++ b/librz/crypto/p/crypto_aes_algo.h @@ -1,16 +1,20 @@ +// SPDX-FileCopyrightText: karl malbrain +// SPDX-License-Identifier: MS-PL + #ifndef CRYPTO_AES_ALGO_H #define CRYPTO_AES_ALGO_H #include +#include #include #include -struct aes_state { +typedef struct aes_state { ut8 key[32]; int key_size; int columns; int rounds; -}; +} aes_state_t; /* forward tables */ @@ -267,7 +271,7 @@ static const ut32 U3[256] = { UT }; #undef V #undef UT -void aes_encrypt(struct aes_state *, ut8 *, ut8 *); -void aes_decrypt(struct aes_state *, ut8 *, ut8 *); +void aes_encrypt(aes_state_t *st, ut8 *in, ut8 *result); +void aes_decrypt(aes_state_t *st, ut8 *in, ut8 *result); #endif diff --git a/librz/crypto/p/crypto_aes_cbc.c b/librz/crypto/p/crypto_aes_cbc.c index 6a8dadd60b..a12af0b7fd 100644 --- a/librz/crypto/p/crypto_aes_cbc.c +++ b/librz/crypto/p/crypto_aes_cbc.c @@ -7,32 +7,44 @@ #define BLOCK_SIZE 16 -static struct aes_state st; -static bool iv_set = 0; -static ut8 iv[32]; +typedef struct aes_cbc_context_t { + aes_state_t st; + bool iv_set; + ut8 iv[32]; +} AesCbcCtx; static bool aes_cbc_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { + rz_return_val_if_fail(cry->user && key, false); + if (!(keylen == 128 / 8 || keylen == 192 / 8 || keylen == 256 / 8)) { return false; } - st.key_size = keylen; - st.rounds = 6 + (int)(keylen / 4); - st.columns = (int)(keylen / 4); - memcpy(st.key, key, keylen); + AesCbcCtx *ctx = (AesCbcCtx *)cry->user; + + ctx->st.key_size = keylen; + ctx->st.rounds = 6 + (int)(keylen / 4); + ctx->st.columns = (int)(keylen / 4); + memcpy(ctx->st.key, key, keylen); cry->dir = direction; return true; } static int aes_cbc_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + AesCbcCtx *ctx = (AesCbcCtx *)cry->user; + + return ctx->st.key_size; } static bool aes_cbc_set_iv(RzCrypto *cry, const ut8 *iv_src, int ivlen) { + rz_return_val_if_fail(cry->user && iv_src, false); + AesCbcCtx *ctx = (AesCbcCtx *)cry->user; + if (ivlen != BLOCK_SIZE) { return false; } - memcpy(iv, iv_src, BLOCK_SIZE); - iv_set = 1; + memcpy(ctx->iv, iv_src, BLOCK_SIZE); + ctx->iv_set = true; return true; } @@ -41,7 +53,14 @@ static bool aes_cbc_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { - if (!iv_set) { + rz_return_val_if_fail(cry->user, false); + AesCbcCtx *ctx = (AesCbcCtx *)cry->user; + + if (len < 1) { + return false; + } + + if (!ctx->iv_set) { eprintf("IV not set. Use -I [iv]\n"); return false; } @@ -68,21 +87,21 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { } int i, j; - if (cry->dir == 0) { + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { for (i = 0; i < blocks; i++) { for (j = 0; j < BLOCK_SIZE; j++) { - ibuf[i * BLOCK_SIZE + j] ^= iv[j]; + ibuf[i * BLOCK_SIZE + j] ^= ctx->iv[j]; } - aes_encrypt(&st, ibuf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); - memcpy(iv, obuf + BLOCK_SIZE * i, BLOCK_SIZE); + aes_encrypt(&ctx->st, ibuf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); + memcpy(ctx->iv, obuf + BLOCK_SIZE * i, BLOCK_SIZE); } - } else if (cry->dir == 1) { + } else { for (i = 0; i < blocks; i++) { - aes_decrypt(&st, ibuf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); + aes_decrypt(&ctx->st, ibuf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); for (j = 0; j < BLOCK_SIZE; j++) { - obuf[i * BLOCK_SIZE + j] ^= iv[j]; + obuf[i * BLOCK_SIZE + j] ^= ctx->iv[j]; } - memcpy(iv, buf + BLOCK_SIZE * i, BLOCK_SIZE); + memcpy(ctx->iv, buf + BLOCK_SIZE * i, BLOCK_SIZE); } } @@ -96,6 +115,20 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool aes_cbc_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(AesCbcCtx); + return cry->user != NULL; +} + +static bool aes_cbc_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_aes_cbc = { .name = "aes-cbc", .set_key = aes_cbc_set_key, @@ -103,7 +136,9 @@ RzCryptoPlugin rz_crypto_plugin_aes_cbc = { .set_iv = aes_cbc_set_iv, .use = aes_cbc_use, .update = update, - .final = final + .final = final, + .init = aes_cbc_init, + .fini = aes_cbc_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_base64.c b/librz/crypto/p/crypto_base64.c index d98762f331..6ac554676d 100644 --- a/librz/crypto/p/crypto_base64.c +++ b/librz/crypto/p/crypto_base64.c @@ -19,16 +19,20 @@ static bool base64_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + if (len < 1) { + return false; + } + int olen = 0; ut8 *obuf = NULL; - if (cry->dir == 0) { + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { olen = ((len + 2) / 3) * 4; obuf = malloc(olen + 1); if (!obuf) { return false; } rz_base64_encode((char *)obuf, (const ut8 *)buf, len); - } else if (cry->dir == 1) { + } else { olen = 4 + ((len / 4) * 3); if (len > 0) { olen -= (buf[len - 1] == '=') ? ((buf[len - 2] == '=') ? 2 : 1) : 0; diff --git a/librz/crypto/p/crypto_base91.c b/librz/crypto/p/crypto_base91.c index b1ec2c3501..7f934634bc 100644 --- a/librz/crypto/p/crypto_base91.c +++ b/librz/crypto/p/crypto_base91.c @@ -21,6 +21,10 @@ static bool base91_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + if (len < 1) { + return false; + } + int olen = INSIZE; if (!cry || !buf || len < 1) { return false; @@ -29,7 +33,7 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { if (!obuf) { return false; } - if (cry->dir == 0) { + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { olen = rz_base91_encode((char *)obuf, (const ut8 *)buf, len); } else if (cry->dir == 1) { olen = rz_base91_decode(obuf, (const char *)buf, len); diff --git a/librz/crypto/p/crypto_blowfish.c b/librz/crypto/p/crypto_blowfish.c index 2aabef072d..c9bbb22dc0 100644 --- a/librz/crypto/p/crypto_blowfish.c +++ b/librz/crypto/p/crypto_blowfish.c @@ -6,6 +6,7 @@ #include #include #include +#include #define BLOCK_SIZE 8 @@ -240,7 +241,7 @@ static void blowfish_decrypt(struct blowfish_state *const state, const ut8 *inbu } } -static bool blowfish_init(struct blowfish_state *const state, const ut8 *key, int keylen) { +static bool blowfish_init_state(struct blowfish_state *const state, const ut8 *key, int keylen) { if (!state || !key || keylen > 56) { return false; } @@ -280,15 +281,19 @@ static bool blowfish_init(struct blowfish_state *const state, const ut8 *key, in return true; } -static struct blowfish_state st = { { 0 } }; - static bool blowfish_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { + rz_return_val_if_fail(cry->user && key, false); + struct blowfish_state *st = (struct blowfish_state *)cry->user; + cry->dir = direction; - return blowfish_init(&st, key, keylen); + return blowfish_init_state(st, key, keylen); } static int blowfish_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct blowfish_state *st = (struct blowfish_state *)cry->user; + + return st->key_size; } static bool blowfish_use(const char *algo) { @@ -296,17 +301,20 @@ static bool blowfish_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { - if (!cry || !buf) { + rz_return_val_if_fail(cry->user, false); + struct blowfish_state *st = (struct blowfish_state *)cry->user; + + if (!buf || len < 1) { return false; } ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - if (cry->dir == 0) { - blowfish_crypt(&st, buf, obuf, len); - } else if (cry->dir == 1) { - blowfish_decrypt(&st, buf, obuf, len); + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { + blowfish_crypt(st, buf, obuf, len); + } else { + blowfish_decrypt(st, buf, obuf, len); } rz_crypto_append(cry, obuf, len); free(obuf); @@ -317,6 +325,20 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool blowfish_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct blowfish_state); + return cry->user != NULL; +} + +static bool blowfish_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_blowfish = { .name = "blowfish", .license = "LGPL3", @@ -324,7 +346,9 @@ RzCryptoPlugin rz_crypto_plugin_blowfish = { .get_key_size = blowfish_get_key_size, .use = blowfish_use, .update = update, - .final = final + .final = final, + .init = blowfish_init, + .fini = blowfish_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_cps2.c b/librz/crypto/p/crypto_cps2.c index 25edb11a5b..813b8aea2b 100644 --- a/librz/crypto/p/crypto_cps2.c +++ b/librz/crypto/p/crypto_cps2.c @@ -14,6 +14,7 @@ #include #include +#include // license:BSD-3-Clause // copyright-holders:Paul Leaman, Andreas Naive, Nicola Salmoria,Charles MacDonald @@ -2884,9 +2885,10 @@ main(cps_state,cps2crypt) { } #endif -static ut32 cps2key[2] = { 0 }; - static bool set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { + rz_return_val_if_fail(cry->user && key, false); + ut32 *cps2key = (ut32 *)cry->user; + cry->dir = direction; if (keylen == 8) { /* fix key endianness */ @@ -2908,7 +2910,14 @@ static bool cps2_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + ut32 *cps2key = (ut32 *)cry->user; + ut8 *output = calloc(1, len); + if (!output) { + return false; + } + /* TODO : control decryption errors */ cps2_crypt(cry->dir, (const ut16 *)buf, (ut16 *)output, len, cps2key, UPPER_LIMIT); rz_crypto_append(cry, output, len); @@ -2916,12 +2925,28 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { return true; } +static bool cps2_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEWS0(ut32, 2); + return cry->user != NULL; +} + +static bool cps2_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_cps2 = { .name = "cps2", .set_key = set_key, .get_key_size = get_key_size, .use = cps2_use, - .update = update + .update = update, + .init = cps2_init, + .fini = cps2_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_des.c b/librz/crypto/p/crypto_des.c index 6a318d03e6..b57c21769b 100644 --- a/librz/crypto/p/crypto_des.c +++ b/librz/crypto/p/crypto_des.c @@ -15,8 +15,6 @@ struct des_state { int i; }; -static struct des_state st = { { 0 } }; - static ut32 be32(const ut8 *buf4) { ut32 val = buf4[0] << 8; val |= buf4[1]; @@ -79,6 +77,9 @@ static int des_decrypt(struct des_state *st, const ut8 *input, ut8 *output) { } static bool des_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { + rz_return_val_if_fail(cry->user && key, 0); + struct des_state *st = (struct des_state *)cry->user; + ut32 keylo, keyhi, i; if (keylen != DES_KEY_SIZE) { return false; @@ -87,22 +88,24 @@ static bool des_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int keylo = be32(key); keyhi = be32(key + 4); - st.key_size = DES_KEY_SIZE; - st.rounds = 16; - cry->dir = direction; // = direction == 0; + st->key_size = DES_KEY_SIZE; + st->rounds = 16; + cry->dir = direction; // key permutation to derive round keys rz_des_permute_key(&keylo, &keyhi); for (i = 0; i < 16; i++) { // filling round keys space - rz_des_round_key(i, &st.keylo[i], &st.keyhi[i], &keylo, &keyhi); + rz_des_round_key(i, &st->keylo[i], &st->keyhi[i], &keylo, &keyhi); } return true; } static int des_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct des_state *st = (struct des_state *)cry->user; + return st->key_size; } static bool des_use(const char *algo) { @@ -110,6 +113,9 @@ static bool des_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + struct des_state *st = (struct des_state *)cry->user; + if (len <= 0) { return false; } @@ -139,15 +145,15 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { // } int i; - if (cry->dir) { + if (cry->dir == RZ_CRYPTO_DIR_DECRYPT) { for (i = 0; i < blocks; i++) { ut32 next = (DES_BLOCK_SIZE * i); - des_decrypt(&st, ibuf + next, obuf + next); + des_decrypt(st, ibuf + next, obuf + next); } } else { for (i = 0; i < blocks; i++) { ut32 next = (DES_BLOCK_SIZE * i); - des_encrypt(&st, ibuf + next, obuf + next); + des_encrypt(st, ibuf + next, obuf + next); } } @@ -161,13 +167,28 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool des_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + cry->user = RZ_NEW0(struct des_state); + return cry->user != NULL; +} + +static bool des_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_des = { .name = "des-ecb", .set_key = des_set_key, .get_key_size = des_get_key_size, .use = des_use, .update = update, - .final = final + .final = final, + .init = des_init, + .fini = des_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_punycode.c b/librz/crypto/p/crypto_punycode.c index aa1731d1d7..dd01ea0501 100644 --- a/librz/crypto/p/crypto_punycode.c +++ b/librz/crypto/p/crypto_punycode.c @@ -5,10 +5,8 @@ #include #include -static int flag = 0; - static bool punycode_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - flag = direction; + cry->dir = direction; return true; } @@ -21,9 +19,13 @@ static bool punycode_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + if (len < 1 || !buf) { + return false; + } + char *obuf; int olen; - if (flag) { + if (cry->dir == RZ_CRYPTO_DIR_DECRYPT) { obuf = rz_punycode_decode((const char *)buf, len, &olen); } else { obuf = rz_punycode_encode(buf, len, &olen); diff --git a/librz/crypto/p/crypto_rc2.c b/librz/crypto/p/crypto_rc2.c index 5647434c8f..c852add0c9 100644 --- a/librz/crypto/p/crypto_rc2.c +++ b/librz/crypto/p/crypto_rc2.c @@ -1,5 +1,6 @@ #include #include +#include #define BITS 1024 #define RC2_KEY_SIZE 64 // bytes @@ -435,17 +436,19 @@ static void rc2_crypt(struct rc2_state *state, const ut8 *inbuf, ut8 *outbuf, in /////////////////////////////////////////////////////////// -static struct rc2_state state; -static int flag = 0; - static bool rc2_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - flag = direction; - state.key_size = 1024; - return rc2_expandKey(&state, key, keylen); + rz_return_val_if_fail(cry->user && key, false); + struct rc2_state *state = (struct rc2_state *)cry->user; + + cry->dir = direction; + state->key_size = 1024; + return rc2_expandKey(state, key, keylen); } static int rc2_get_key_size(RzCrypto *cry) { - return state.key_size; + rz_return_val_if_fail(cry->user, 0); + struct rc2_state *state = (struct rc2_state *)cry->user; + return state->key_size; } static bool rc2_use(const char *algo) { @@ -453,14 +456,17 @@ static bool rc2_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + struct rc2_state *state = (struct rc2_state *)cry->user; + ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - if (flag == 0) { - rc2_crypt(&state, buf, obuf, len); - } else if (flag == 1) { - rc2_dcrypt(&state, buf, obuf, len); + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { + rc2_crypt(state, buf, obuf, len); + } else { + rc2_dcrypt(state, buf, obuf, len); } rz_crypto_append(cry, obuf, len); free(obuf); @@ -471,13 +477,29 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool rc2_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct rc2_state); + return cry->user != NULL; +} + +static bool rc2_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_rc2 = { .name = "rc2", .set_key = rc2_set_key, .get_key_size = rc2_get_key_size, .use = rc2_use, .update = update, - .final = final + .final = final, + .init = rc2_init, + .fini = rc2_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_rc4.c b/librz/crypto/p/crypto_rc4.c index fa4649c56a..b4e47866f1 100644 --- a/librz/crypto/p/crypto_rc4.c +++ b/librz/crypto/p/crypto_rc4.c @@ -3,6 +3,7 @@ #include #include +#include struct rc4_state { ut8 perm[256]; @@ -24,7 +25,7 @@ static __inline void swap_bytes(ut8 *a, ut8 *b) { * which can have arbitrary length. */ -static bool rc4_init(struct rc4_state *const state, const ut8 *key, int keylen) { +static bool rc4_init_state(struct rc4_state *const state, const ut8 *key, int keylen) { ut8 j; int i; @@ -72,14 +73,18 @@ static void rc4_crypt(struct rc4_state *const state, const ut8 *inbuf, ut8 *outb /////////////////////////////////////////////////////////// -static struct rc4_state st; - static bool rc4_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - return rc4_init(&st, key, keylen); + rz_return_val_if_fail(cry->user && key, false); + struct rc4_state *st = (struct rc4_state *)cry->user; + + return rc4_init_state(st, key, keylen); } static int rc4_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct rc4_state *st = (struct rc4_state *)cry->user; + + return st->key_size; } static bool rc4_use(const char *algo) { @@ -87,11 +92,14 @@ static bool rc4_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + struct rc4_state *st = (struct rc4_state *)cry->user; + ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - rc4_crypt(&st, buf, obuf, len); + rc4_crypt(st, buf, obuf, len); rz_crypto_append(cry, obuf, len); free(obuf); return false; @@ -101,13 +109,29 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool rc4_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct rc4_state); + return cry->user != NULL; +} + +static bool rc4_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_rc4 = { .name = "rc4", .set_key = rc4_set_key, .get_key_size = rc4_get_key_size, .use = rc4_use, .update = update, - .final = final + .final = final, + .init = rc4_init, + .fini = rc4_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_rc6.c b/librz/crypto/p/crypto_rc6.c index 0c63352841..b6ce63604a 100644 --- a/librz/crypto/p/crypto_rc6.c +++ b/librz/crypto/p/crypto_rc6.c @@ -4,6 +4,7 @@ //Implemented AES version of RC6. keylen = 16, 23, or 32 bytes; w = 32; and r = 20. #include #include +#include #define Pw 0xb7e15163 #define Qw 0x9e3779b9 @@ -18,33 +19,28 @@ struct rc6_state { int key_size; }; -static bool flag; - -static bool rc6_init(struct rc6_state *const state, const ut8 *key, int keylen, int direction) { +static bool rc6_init_state(struct rc6_state *const state, const ut8 *key, int keylen) { if (keylen != 128 / 8 && keylen != 192 / 8 && keylen != 256 / 8) { return false; } - flag = (direction != 0); - int u = w / 8; int c = keylen / u; int t = 2 * r + 4; -#ifdef _MSC_VER - ut32 *L = (ut32 *)malloc(sizeof(ut32) * c); -#else - ut32 L[c]; -#endif + + ut32 *L = RZ_NEWS(ut32, c); + if (!L) { + rz_warn_if_reached(); + return false; + } + ut32 A = 0, B = 0, k = 0, j = 0; ut32 v = 3 * t; //originally v = 2 * ((c > t) ? c : t); - int i, off; + int i; - for (i = 0, off = 0; i < c; i++) { - L[i] = ((key[off++] & 0xff)); - L[i] |= ((key[off++] & 0xff) << 8); - L[i] |= ((key[off++] & 0xff) << 16); - L[i] |= ((key[off++] & 0xff) << 24); + for (i = 0; i < c; i++) { + L[i] = rz_read_at_le32(key, i * 4); } (state->S)[0] = Pw; @@ -60,9 +56,8 @@ static bool rc6_init(struct rc6_state *const state, const ut8 *key, int keylen, } state->key_size = keylen / 8; -#ifdef _MSC_VER + free(L); -#endif return true; } @@ -71,12 +66,8 @@ static void rc6_encrypt(struct rc6_state *const state, const ut8 *inbuf, ut8 *ou ut32 aux; ut32 data[BLOCK_SIZE / 4]; int i; - int off = 0; for (i = 0; i < BLOCK_SIZE / 4; i++) { - data[i] = ((inbuf[off++] & 0xff)); - data[i] |= ((inbuf[off++] & 0xff) << 8); - data[i] |= ((inbuf[off++] & 0xff) << 16); - data[i] |= ((inbuf[off++] & 0xff) << 24); + data[i] = rz_read_at_le32(inbuf, i * 4); } ut32 A = data[0], B = data[1], C = data[2], D = data[3]; @@ -155,14 +146,20 @@ static void rc6_decrypt(struct rc6_state *const state, const ut8 *inbuf, ut8 *ou } } -static struct rc6_state st; - static bool rc6_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - return rc6_init(&st, key, keylen, direction); + rz_return_val_if_fail(cry->user && key, false); + struct rc6_state *st = (struct rc6_state *)cry->user; + + cry->dir = direction; + + return rc6_init_state(st, key, keylen); } static int rc6_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct rc6_state *st = (struct rc6_state *)cry->user; + + return st->key_size; } static bool rc6_use(const char *algo) { @@ -170,6 +167,9 @@ static bool rc6_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + struct rc6_state *st = (struct rc6_state *)cry->user; + if (len % BLOCK_SIZE != 0) { //let user handle with with pad. eprintf("Input should be multiple of 128bit.\n"); return false; @@ -183,13 +183,13 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { } int i; - if (flag) { + if (cry->dir == RZ_CRYPTO_DIR_DECRYPT) { for (i = 0; i < blocks; i++) { - rc6_decrypt(&st, buf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); + rc6_decrypt(st, buf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); } } else { for (i = 0; i < blocks; i++) { - rc6_encrypt(&st, buf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); + rc6_encrypt(st, buf + BLOCK_SIZE * i, obuf + BLOCK_SIZE * i); } } @@ -202,13 +202,29 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool rc6_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct rc6_state); + return cry->user != NULL; +} + +static bool rc6_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_rc6 = { .name = "rc6", .set_key = rc6_set_key, .get_key_size = rc6_get_key_size, .use = rc6_use, .update = update, - .final = final + .final = final, + .init = rc6_init, + .fini = rc6_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_rol.c b/librz/crypto/p/crypto_rol.c index 6c54bbfb9a..a447e00e53 100644 --- a/librz/crypto/p/crypto_rol.c +++ b/librz/crypto/p/crypto_rol.c @@ -3,6 +3,7 @@ #include #include +#include #define NAME "rol" @@ -13,7 +14,7 @@ struct rol_state { int key_size; }; -static bool rol_init(struct rol_state *const state, const ut8 *key, int keylen) { +static bool rol_init_state(struct rol_state *const state, const ut8 *key, int keylen) { if (!state || !key || keylen < 1 || keylen > MAX_rol_KEY_SIZE) { return false; } @@ -34,16 +35,19 @@ static void rol_crypt(struct rol_state *const state, const ut8 *inbuf, ut8 *outb } } -static struct rol_state st; -static int flag = 0; - static bool rol_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - flag = direction; - return rol_init(&st, key, keylen); + rz_return_val_if_fail(cry->user && key, false); + struct rol_state *st = (struct rol_state *)cry->user; + + cry->dir = direction; + return rol_init_state(st, key, keylen); } static int rol_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct rol_state *st = (struct rol_state *)cry->user; + + return st->key_size; } static bool rol_use(const char *algo) { @@ -51,20 +55,37 @@ static bool rol_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { - if (flag) { - eprintf("Use ROR\n"); + rz_return_val_if_fail(cry->user, false); + struct rol_state *st = (struct rol_state *)cry->user; + + if (cry->dir) { + eprintf("Use ROR algorithm to decrypt\n"); return false; } ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - rol_crypt(&st, buf, obuf, len); + rol_crypt(st, buf, obuf, len); rz_crypto_append(cry, obuf, len); free(obuf); return true; } +static bool rol_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct rol_state); + return cry->user != NULL; +} + +static bool rol_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_rol = { .name = NAME, .set_key = rol_set_key, @@ -72,6 +93,8 @@ RzCryptoPlugin rz_crypto_plugin_rol = { .use = rol_use, .update = update, .final = update, + .init = rol_init, + .fini = rol_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_ror.c b/librz/crypto/p/crypto_ror.c index ddab9e6162..9c5c9b9814 100644 --- a/librz/crypto/p/crypto_ror.c +++ b/librz/crypto/p/crypto_ror.c @@ -1,5 +1,6 @@ #include #include +#include #define NAME "ror" @@ -10,7 +11,7 @@ struct ror_state { int key_size; }; -static bool ror_init(struct ror_state *const state, const ut8 *key, int keylen) { +static bool ror_init_state(struct ror_state *const state, const ut8 *key, int keylen) { if (!state || !key || keylen < 1 || keylen > MAX_ror_KEY_SIZE) { return false; } @@ -31,16 +32,19 @@ static void ror_crypt(struct ror_state *const state, const ut8 *inbuf, ut8 *outb } } -static struct ror_state st; -static int flag = 0; - static bool ror_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - flag = direction; - return ror_init(&st, key, keylen); + rz_return_val_if_fail(cry->user && key, false); + struct ror_state *st = (struct ror_state *)cry->user; + + cry->dir = direction; + return ror_init_state(st, key, keylen); } static int ror_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct ror_state *st = (struct ror_state *)cry->user; + + return st->key_size; } static bool ror_use(const char *algo) { @@ -48,20 +52,37 @@ static bool ror_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { - if (flag) { - eprintf("USE ROL\n"); + rz_return_val_if_fail(cry->user, false); + struct ror_state *st = (struct ror_state *)cry->user; + + if (cry->dir) { + eprintf("Use ROL algorithm to decrypt\n"); return false; } ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - ror_crypt(&st, buf, obuf, len); + ror_crypt(st, buf, obuf, len); rz_crypto_append(cry, obuf, len); free(obuf); return true; } +static bool ror_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct ror_state); + return cry->user != NULL; +} + +static bool ror_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_ror = { .name = NAME, .set_key = ror_set_key, @@ -69,6 +90,8 @@ RzCryptoPlugin rz_crypto_plugin_ror = { .use = ror_use, .update = update, .final = update, + .init = ror_init, + .fini = ror_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_rot.c b/librz/crypto/p/crypto_rot.c index da1d0f4c41..a4fd814045 100644 --- a/librz/crypto/p/crypto_rot.c +++ b/librz/crypto/p/crypto_rot.c @@ -3,6 +3,7 @@ #include #include +#include int mod(int a, int b) { if (b < 0) { @@ -15,7 +16,7 @@ int mod(int a, int b) { return ret; } -static bool rot_init(ut8 *rotkey, const ut8 *key, int keylen) { +static bool rot_init_state(ut8 *rotkey, const ut8 *key, int keylen) { if (rotkey && key && keylen > 0) { int i = atoi((const char *)key); *rotkey = (ut8)mod(i, 26); @@ -53,12 +54,17 @@ static void rot_decrypt(ut8 key, const ut8 *inbuf, ut8 *outbuf, int buflen) { } } -static ut8 rot_key; -static int flag = 0; - static bool rot_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - flag = direction; - return rot_init(&rot_key, key, keylen); + rz_return_val_if_fail(cry->user && key, false); + ut8 *rot_key = (ut8 *)cry->user; + + if (keylen > (sizeof(ut8) * 8) || keylen < 0) { + return false; + } + + cry->dir = direction; + + return rot_init_state(rot_key, key, keylen); } static int rot_get_key_size(RzCrypto *cry) { @@ -71,14 +77,17 @@ static bool rot_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + ut8 *rot_key = (ut8 *)cry->user; + ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - if (flag == 0) { - rot_crypt(rot_key, buf, obuf, len); - } else if (flag == 1) { - rot_decrypt(rot_key, buf, obuf, len); + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { + rot_crypt(*rot_key, buf, obuf, len); + } else { + rot_decrypt(*rot_key, buf, obuf, len); } rz_crypto_append(cry, obuf, len); free(obuf); @@ -89,13 +98,29 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool rol_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(ut8); + return cry->user != NULL; +} + +static bool rol_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_rot = { .name = "rot", .set_key = rot_set_key, .get_key_size = rot_get_key_size, .use = rot_use, .update = update, - .final = final + .final = final, + .init = rol_init, + .fini = rol_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_serpent.c b/librz/crypto/p/crypto_serpent.c index c2e8a9c29b..69235f366e 100644 --- a/librz/crypto/p/crypto_serpent.c +++ b/librz/crypto/p/crypto_serpent.c @@ -2,22 +2,24 @@ #include #include "crypto_serpent_algo.h" -static struct serpent_state st = { { 0 } }; - static bool serpent_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - eprintf("key_size: %d\n", keylen); + rz_return_val_if_fail(cry->user && key, false); + serpent_state_t *st = (serpent_state_t *)cry->user; + if ((keylen != 128 / 8) && (keylen != 192 / 8) && (keylen != 256 / 8)) { return false; } - st.key_size = keylen * 8; - eprintf("key_size: %d\n", st.key_size); - memcpy(st.key, key, keylen); + st->key_size = keylen * 8; + memcpy(st->key, key, keylen); cry->dir = direction; return true; } static int serpent_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + serpent_state_t *st = (serpent_state_t *)cry->user; + + return st->key_size; } static bool serpent_use(const char *algo) { @@ -27,6 +29,12 @@ static bool serpent_use(const char *algo) { #define BLOCK_SIZE 16 static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, 0); + serpent_state_t *st = (serpent_state_t *)cry->user; + if (len < 1) { + return false; + } + // Pad to the block size, do not append dummy block const int diff = (BLOCK_SIZE - (len % BLOCK_SIZE)) % BLOCK_SIZE; const int size = len + diff; @@ -59,17 +67,17 @@ static bool update(RzCrypto *cry, const ut8 *buf, int len) { ibuf[len / 4] = rz_read_le32(tail); } - if (cry->dir == 0) { + if (cry->dir == RZ_CRYPTO_DIR_ENCRYPT) { for (i = 0; i < blocks; i++) { // delta in number of ut32 const int delta = (BLOCK_SIZE * i) / 4; - serpent_encrypt(&st, ibuf + delta, tmp + delta); + serpent_encrypt(st, ibuf + delta, tmp + delta); } - } else if (cry->dir > 0) { + } else { for (i = 0; i < blocks; i++) { // delta in number of ut32 const int delta = (BLOCK_SIZE * i) / 4; - serpent_decrypt(&st, ibuf + delta, tmp + delta); + serpent_decrypt(st, ibuf + delta, tmp + delta); } } @@ -94,13 +102,29 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool serpent_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(serpent_state_t); + return cry->user != NULL; +} + +static bool serpent_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_serpent = { .name = "serpent-ecb", .set_key = serpent_set_key, .get_key_size = serpent_get_key_size, .use = serpent_use, .update = update, - .final = final + .final = final, + .init = serpent_init, + .fini = serpent_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/crypto/p/crypto_serpent_algo.c b/librz/crypto/p/crypto_serpent_algo.c index 664c3f2f90..04ca18ea12 100644 --- a/librz/crypto/p/crypto_serpent_algo.c +++ b/librz/crypto/p/crypto_serpent_algo.c @@ -87,9 +87,8 @@ void apply_FP(ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]) { } } -void serpent_keyschedule(struct serpent_state st, - ut32 subkeys[NB_SUBKEYS * DW_BY_BLOCK]) { - rz_return_if_fail((st.key_size == 128) || (st.key_size == 192) || (st.key_size == 256)); +void serpent_keyschedule(const serpent_state_t *st, ut32 subkeys[NB_SUBKEYS * DW_BY_BLOCK]) { + rz_return_if_fail((st->key_size == 128) || (st->key_size == 192) || (st->key_size == 256)); ut32 tmpkeys[DW_BY_BLOCK * NB_SUBKEYS + DW_BY_USERKEY] = { 0 }; const ut32 phi = 0x9e3779b9; @@ -97,13 +96,13 @@ void serpent_keyschedule(struct serpent_state st, ut8 in, out; int i, j, l; - for (i = 0; i < st.key_size / 32; i++) { - tmpkeys[i] = st.key[i]; + for (i = 0; i < st->key_size / 32; i++) { + tmpkeys[i] = st->key[i]; } // Padding key - if (st.key_size != 256) { - tmpkeys[st.key_size / 32] = 1; + if (st->key_size != 256) { + tmpkeys[st->key_size / 32] = 1; } for (i = DW_BY_USERKEY; i < NB_SUBKEYS * DW_BY_BLOCK + DW_BY_USERKEY; i++) { @@ -127,8 +126,7 @@ void serpent_keyschedule(struct serpent_state st, // Apply IP on every subkey for (i = 0; i < NB_SUBKEYS; i++) { - apply_IP(&subkeys[i * DW_BY_BLOCK], - &tmpkeys[DW_BY_USERKEY + i * DW_BY_BLOCK]); + apply_IP(&subkeys[i * DW_BY_BLOCK], &tmpkeys[DW_BY_USERKEY + i * DW_BY_BLOCK]); } memcpy(subkeys, tmpkeys + DW_BY_USERKEY, 132 * sizeof(ut32)); @@ -216,13 +214,13 @@ void apply_round_inv(int round, ut32 block[DW_BY_BLOCK], apply_xor(block, subkeys + 4 * round); } -void serpent_encrypt(struct serpent_state *st, ut32 in[DW_BY_BLOCK], +void serpent_encrypt(serpent_state_t *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]) { int i; ut32 subkeys[DW_BY_BLOCK * NB_SUBKEYS] = { 0 }; ut32 tmp_block[DW_BY_BLOCK] = { 0 }; - serpent_keyschedule(*st, subkeys); + serpent_keyschedule(st, subkeys); apply_IP(in, tmp_block); for (i = 0; i < NB_ROUNDS; i++) { @@ -231,13 +229,13 @@ void serpent_encrypt(struct serpent_state *st, ut32 in[DW_BY_BLOCK], apply_FP(tmp_block, out); } -void serpent_decrypt(struct serpent_state *st, ut32 in[DW_BY_BLOCK], +void serpent_decrypt(serpent_state_t *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]) { int i; ut32 subkeys[DW_BY_BLOCK * NB_SUBKEYS] = { 0 }; ut32 tmp_block[DW_BY_BLOCK] = { 0 }; - serpent_keyschedule(*st, subkeys); + serpent_keyschedule(st, subkeys); apply_IP(in, tmp_block); for (i = NB_ROUNDS - 1; i >= 0; i--) { diff --git a/librz/crypto/p/crypto_serpent_algo.h b/librz/crypto/p/crypto_serpent_algo.h index a70e0c360b..9e5beaaeac 100644 --- a/librz/crypto/p/crypto_serpent_algo.h +++ b/librz/crypto/p/crypto_serpent_algo.h @@ -2,16 +2,17 @@ #define CRYPTO_SERPENT_ALGO_H #include +#include #define DW_BY_BLOCK 4 #define DW_BY_USERKEY 8 #define NB_ROUNDS 32 #define NB_SUBKEYS 33 #define NIBBLES_BY_SUBKEY 32 -struct serpent_state { +typedef struct serpent_state { ut32 key[8]; int key_size; -}; +} serpent_state_t; /* * st: A pointer to a serpent_state structure containing the key and the key size. @@ -19,7 +20,7 @@ struct serpent_state { * out: When the function returns, the block of data encrypted by serpent * with the key contained in st. */ -void serpent_encrypt(struct serpent_state *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]); +void serpent_encrypt(serpent_state_t *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]); /* * st: A pointer to a serpent_state structure containing the key and the key size. @@ -27,14 +28,13 @@ void serpent_encrypt(struct serpent_state *st, ut32 in[DW_BY_BLOCK], ut32 out[DW * out: When the function returns, the block of data decrypted by serpent * with the key contained in st. */ -void serpent_decrypt(struct serpent_state *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]); +void serpent_decrypt(serpent_state_t *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK]); /* * st: A serpent_state structure containing the key and the key size. * subkeys: When the function returns, an array of double words containings * all the subkeys needed for the encryptio/dcryption with serpent. */ -void serpent_keyschedule(struct serpent_state st, - ut32 subkeys[NB_SUBKEYS * DW_BY_BLOCK]); +void serpent_keyschedule(const serpent_state_t *st, ut32 subkeys[NB_SUBKEYS * DW_BY_BLOCK]); #endif diff --git a/librz/crypto/p/crypto_xor.c b/librz/crypto/p/crypto_xor.c index 57d30d498d..6e722a6f49 100644 --- a/librz/crypto/p/crypto_xor.c +++ b/librz/crypto/p/crypto_xor.c @@ -3,6 +3,7 @@ #include #include +#include #define MAX_xor_KEY_SIZE 32768 @@ -11,34 +12,39 @@ struct xor_state { int key_size; }; -static struct xor_state st; - -static bool xor_init(struct xor_state *const state, const ut8 *key, int keylen) { +static bool xor_init_state(struct xor_state *const state, const ut8 *key, int keylen) { if (!state || !key || keylen < 1) { // || keylen > MAX_xor_KEY_SIZE) { return false; } state->key_size = keylen; state->key = malloc(keylen); + if (!state->key) { + return false; + } memcpy(state->key, key, keylen); return true; } -/* - * Encrypt/Decrypt xor state buffer using the supplied key - */ - +// Encrypt/Decrypt xor state buffer using the supplied key static void xor_crypt(struct xor_state *const state, const ut8 *inbuf, ut8 *outbuf, int buflen) { int i; //index for input for (i = 0; i < buflen; i++) { outbuf[i] = inbuf[i] ^ state->key[(i % state->key_size)]; } } + static bool xor_set_key(RzCrypto *cry, const ut8 *key, int keylen, int mode, int direction) { - return xor_init(&st, key, keylen); + rz_return_val_if_fail(cry->user, 0); + struct xor_state *st = (struct xor_state *)cry->user; + + return xor_init_state(st, key, keylen); } static int xor_get_key_size(RzCrypto *cry) { - return st.key_size; + rz_return_val_if_fail(cry->user, 0); + struct xor_state *st = (struct xor_state *)cry->user; + + return st->key_size; } static bool xor_use(const char *algo) { @@ -46,11 +52,14 @@ static bool xor_use(const char *algo) { } static bool update(RzCrypto *cry, const ut8 *buf, int len) { + rz_return_val_if_fail(cry->user, false); + struct xor_state *st = (struct xor_state *)cry->user; + ut8 *obuf = calloc(1, len); if (!obuf) { return false; } - xor_crypt(&st, buf, obuf, len); + xor_crypt(st, buf, obuf, len); rz_crypto_append(cry, obuf, len); free(obuf); return true; @@ -60,13 +69,33 @@ static bool final(RzCrypto *cry, const ut8 *buf, int len) { return update(cry, buf, len); } +static bool xor_init(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + + cry->user = RZ_NEW0(struct xor_state); + return cry->user != NULL; +} + +static bool xor_fini(RzCrypto *cry) { + rz_return_val_if_fail(cry, false); + struct xor_state *state = (struct xor_state *)cry->user; + + if (state) { + free(state->key); + } + free(cry->user); + return true; +} + RzCryptoPlugin rz_crypto_plugin_xor = { .name = "xor", .set_key = xor_set_key, .get_key_size = xor_get_key_size, .use = xor_use, .update = update, - .final = final + .final = final, + .init = xor_init, + .fini = xor_fini, }; #ifndef RZ_PLUGIN_INCORE diff --git a/librz/hash/entropy.c b/librz/hash/entropy.c index c5d184101a..a4c5b5caa9 100644 --- a/librz/hash/entropy.c +++ b/librz/hash/entropy.c @@ -1,13 +1,6 @@ // SPDX-FileCopyrightText: 2009 pancake // SPDX-License-Identifier: LGPL-3.0-only -/* - * This code was done - * by an anonymous gnome - * ------------------------ - * That's pure mathematics, so no sense to adding a license here. - */ - #include #include #include "rz_types.h" @@ -29,8 +22,10 @@ RZ_API double rz_hash_entropy(const ut8 *data, ut64 size) { } return h; } + RZ_API double rz_hash_entropy_fraction(const ut8 *data, ut64 size) { - return size ? rz_hash_entropy(data, size) / - log2((double)RZ_MIN(size, 256)) - : 0; + if (size) { + return rz_hash_entropy(data, size) / log2((double)RZ_MIN(size, 256)); + } + return 0; } diff --git a/librz/hash/hash.c b/librz/hash/hash.c index 31c1202952..ee8475fbaf 100644 --- a/librz/hash/hash.c +++ b/librz/hash/hash.c @@ -27,9 +27,6 @@ static const struct { { "hamdist", RZ_HASH_HAMDIST }, { "pcprint", RZ_HASH_PCPRINT }, { "mod255", RZ_HASH_MOD255 }, - // {"base64", RZ_HASH_BASE64}, - // {"base91", RZ_HASH_BASE91}, - // {"punycode", RZ_HASH_PUNYCODE}, { "luhn", RZ_HASH_LUHN }, { "fletcher8", RZ_HASH_FLETCHER8 }, @@ -108,7 +105,6 @@ static const struct { { /* CRC-64/XZ */ "crc64xz", RZ_HASH_CRC64_XZ }, { /* CRC-64/ISO */ "crc64iso", RZ_HASH_CRC64_ISO }, #endif /* #if RZ_HAVE_CRC64_EXTRA */ - { NULL, 0 } }; /* returns 0-100 */ @@ -177,9 +173,9 @@ RZ_API ut8 rz_hash_deviation(const ut8 *b, ut64 len) { } RZ_API const char *rz_hash_name(ut64 bit) { - int i; - for (i = 1; hash_name_bytes[i].bit; i++) { - if (bit & hash_name_bytes[i].bit) { + size_t i; + for (i = 1; i < RZ_ARRAY_SIZE(hash_name_bytes); i++) { + if (bit == hash_name_bytes[i].bit) { return hash_name_bytes[i].name; } } @@ -289,7 +285,7 @@ RZ_API int rz_hash_size(ut64 algo) { /* Converts a comma separated list of names to the respective bit combination */ RZ_API ut64 rz_hash_name_to_bits(const char *name) { char tmp[128]; - int i; + size_t i; const char *ptr = name; ut64 ret = 0; @@ -306,7 +302,7 @@ RZ_API ut64 rz_hash_name_to_bits(const char *name) { /* Safety net */ tmp[i] = '\0'; - for (i = 0; hash_name_bytes[i].name; i++) { + for (i = 0; i < RZ_ARRAY_SIZE(hash_name_bytes); i++) { if (!strcmp(tmp, hash_name_bytes[i].name)) { ret |= hash_name_bytes[i].bit; break; @@ -327,7 +323,7 @@ RZ_API void rz_hash_do_spice(RzHash *ctx, ut64 algo, int loops, RzHashSeed *seed int i, len, hlen = rz_hash_size(algo); for (i = 0; i < loops; i++) { if (seed) { - if (seed->prefix) { + if (seed->as_prefix) { memcpy(buf, seed->buf, seed->len); memcpy(buf + seed->len, ctx->digest, hlen); } else { diff --git a/librz/hash/state.c b/librz/hash/state.c index 7356c9f938..c29905002b 100644 --- a/librz/hash/state.c +++ b/librz/hash/state.c @@ -30,7 +30,7 @@ RZ_API void rz_hash_do_begin(RzHash *ctx, ut64 flags) { rz_md4_init(&ctx->md4); } if_has_flag(RZ_HASH_MD5) { - rz_hash_do_md5(ctx, NULL, -1); + MD5_Init(&ctx->md5); } if_has_flag(RZ_HASH_SHA1) { rz_sha1_init(&ctx->sha1); @@ -47,12 +47,194 @@ RZ_API void rz_hash_do_begin(RzHash *ctx, ut64 flags) { ctx->rst = false; } +#define HANDLE_CRC_PRESET(rbits, aname) \ + do { \ + if (algobit & RZ_HASH_##aname) { \ + ut##rbits res = rz_hash_crc_preset(buf, len, CRC_PRESET_##aname); \ + rz_write_be##rbits(ctx->digest, res); \ + } \ + } while (0) + +RZ_API void rz_hash_do_update(RzHash *ctx, ut64 algobit, const ut8 *buf, ut64 len) { + if (algobit & RZ_HASH_MD4) { + rz_md4_update(&ctx->md4, buf, len); + } + if (algobit & RZ_HASH_MD5) { + MD5_Update(&ctx->md5, buf, len); + } + if (algobit & RZ_HASH_SHA1) { + rz_sha1_update(&ctx->sha1, buf, len); + } + if (algobit & RZ_HASH_SHA256) { + SHA256_Update(&ctx->sha256, buf, len); + } + if (algobit & RZ_HASH_SHA384) { + SHA384_Update(&ctx->sha384, buf, len); + } + if (algobit & RZ_HASH_SHA512) { + SHA512_Update(&ctx->sha512, buf, len); + } + if (algobit & RZ_HASH_XXHASH) { + ut32 res = rz_hash_xxhash(buf, len); + rz_write_le32(ctx->digest, res); + } + if (algobit & RZ_HASH_FLETCHER8) { + ut8 res = rz_hash_fletcher8(buf, len); + rz_write_le8(ctx->digest, res); + } + if (algobit & RZ_HASH_FLETCHER16) { + ut16 res = rz_hash_fletcher16(buf, len); + rz_write_le16(ctx->digest, res); + } + if (algobit & RZ_HASH_FLETCHER32) { + ut32 res = rz_hash_fletcher32(buf, len); + rz_write_le32(ctx->digest, res); + } + if (algobit & RZ_HASH_FLETCHER64) { + ut64 res = rz_hash_fletcher64(buf, len); + rz_write_le64(ctx->digest, res); + } + if (algobit & RZ_HASH_ADLER32) { + ut32 res = rz_hash_adler32(buf, len); + rz_write_le32(ctx->digest, res); + } + if (algobit & RZ_HASH_HAMDIST) { + *ctx->digest = rz_hash_hamdist(buf, len); + } + if (algobit & RZ_HASH_PCPRINT) { + *ctx->digest = rz_hash_pcprint(buf, len); + } + if (algobit & RZ_HASH_PARITY) { + *ctx->digest = rz_hash_parity(buf, len); + } + if (algobit & RZ_HASH_ENTROPY) { + rz_mem_memzero(ctx->digest, sizeof(ctx->entropy)); + ctx->entropy = rz_hash_entropy(buf, len); + } + if (algobit & RZ_HASH_XOR) { + *ctx->digest = rz_hash_xor(buf, len); + } + if (algobit & RZ_HASH_XORPAIR) { + ut16 res = rz_hash_xorpair(buf, len); + rz_write_le16(ctx->digest, res); + } + if (algobit & RZ_HASH_MOD255) { + *ctx->digest = rz_hash_mod255(buf, len); + } + if (algobit & RZ_HASH_LUHN) { + *ctx->digest = rz_hash_luhn(buf, len); + } + + if (algobit & RZ_HASH_CRC8_SMBUS) { + ut8 res = rz_hash_crc_preset(buf, len, CRC_PRESET_8_SMBUS); + rz_write_le8(ctx->digest, res); + } +#if RZ_HAVE_CRC8_EXTRA + HANDLE_CRC_PRESET(8, CRC8_CDMA2000); + HANDLE_CRC_PRESET(8, CRC8_CDMA2000); + HANDLE_CRC_PRESET(8, CRC8_DARC); + HANDLE_CRC_PRESET(8, CRC8_DVB_S2); + HANDLE_CRC_PRESET(8, CRC8_EBU); + HANDLE_CRC_PRESET(8, CRC8_ICODE); + HANDLE_CRC_PRESET(8, CRC8_ITU); + HANDLE_CRC_PRESET(8, CRC8_MAXIM); + HANDLE_CRC_PRESET(8, CRC8_ROHC); + HANDLE_CRC_PRESET(8, CRC8_WCDMA); +#endif /* #if RZ_HAVE_CRC8_EXTRA */ + +#if RZ_HAVE_CRC15_EXTRA + if (algobit & RZ_HASH_CRC15_CAN) { + ut16 res = rz_hash_crc_preset(buf, len, CRC_PRESET_15_CAN); + rz_write_be16(ctx->digest, res); + } +#endif /* #if RZ_HAVE_CRC15_EXTRA */ + + if (algobit & RZ_HASH_CRC16) { + ut16 res = rz_hash_crc_preset(buf, len, CRC_PRESET_16); + rz_write_be16(ctx->digest, res); + } + if (algobit & RZ_HASH_CRC16_HDLC) { + ut16 res = rz_hash_crc_preset(buf, len, CRC_PRESET_16_HDLC); + rz_write_be16(ctx->digest, res); + } + if (algobit & RZ_HASH_CRC16_USB) { + ut16 res = rz_hash_crc_preset(buf, len, CRC_PRESET_16_USB); + rz_write_be16(ctx->digest, res); + } + if (algobit & RZ_HASH_CRC16_CITT) { + ut16 res = rz_hash_crc_preset(buf, len, CRC_PRESET_16_CITT); + rz_write_be16(ctx->digest, res); + } +#if RZ_HAVE_CRC16_EXTRA + HANDLE_CRC_PRESET(16, CRC16_AUG_CCITT); + HANDLE_CRC_PRESET(16, CRC16_BUYPASS); + HANDLE_CRC_PRESET(16, CRC16_CDMA2000); + HANDLE_CRC_PRESET(16, CRC16_DDS110); + HANDLE_CRC_PRESET(16, CRC16_DECT_R); + HANDLE_CRC_PRESET(16, CRC16_DECT_X); + HANDLE_CRC_PRESET(16, CRC16_DNP); + HANDLE_CRC_PRESET(16, CRC16_EN13757); + HANDLE_CRC_PRESET(16, CRC16_GENIBUS); + HANDLE_CRC_PRESET(16, CRC16_MAXIM); + HANDLE_CRC_PRESET(16, CRC16_MCRF4XX); + HANDLE_CRC_PRESET(16, CRC16_RIELLO); + HANDLE_CRC_PRESET(16, CRC16_T10_DIF); + HANDLE_CRC_PRESET(16, CRC16_TELEDISK); + HANDLE_CRC_PRESET(16, CRC16_TMS37157); + HANDLE_CRC_PRESET(16, CRCA); + HANDLE_CRC_PRESET(16, CRC16_KERMIT); + HANDLE_CRC_PRESET(16, CRC16_MODBUS); + HANDLE_CRC_PRESET(16, CRC16_X25); + HANDLE_CRC_PRESET(16, CRC16_XMODEM); +#endif /* #if RZ_HAVE_CRC16_EXTRA */ + +#if RZ_HAVE_CRC24 + if (algobit & RZ_HASH_CRC24) { + ut32 res = rz_hash_crc_preset(buf, len, CRC_PRESET_24); + rz_write_be24(ctx->digest, res); + } +#endif /* #if RZ_HAVE_CRC24 */ + + if (algobit & RZ_HASH_CRC32) { + ut32 res = rz_hash_crc_preset(buf, len, CRC_PRESET_32); + rz_write_be32(ctx->digest, res); + } + if (algobit & RZ_HASH_CRC32C) { + ut32 res = rz_hash_crc_preset(buf, len, CRC_PRESET_32C); + rz_write_be32(ctx->digest, res); + } + if (algobit & RZ_HASH_CRC32_ECMA_267) { + ut32 res = rz_hash_crc_preset(buf, len, CRC_PRESET_32_ECMA_267); + rz_write_be32(ctx->digest, res); + } +#if RZ_HAVE_CRC32_EXTRA + HANDLE_CRC_PRESET(32, CRC32_BZIP2); + HANDLE_CRC_PRESET(32, CRC32D); + HANDLE_CRC_PRESET(32, CRC32_MPEG2); + HANDLE_CRC_PRESET(32, CRC32_POSIX); + HANDLE_CRC_PRESET(32, CRC32Q); + HANDLE_CRC_PRESET(32, CRC32_JAMCRC); + HANDLE_CRC_PRESET(32, CRC32_XFER); +#endif /* #if RZ_HAVE_CRC32_EXTRA */ + +#if RZ_HAVE_CRC64 + HANDLE_CRC_PRESET(64, CRC64); +#endif /* #if RZ_HAVE_CRC64 */ + +#if RZ_HAVE_CRC64_EXTRA + HANDLE_CRC_PRESET(64, CRC64_ECMA182); + HANDLE_CRC_PRESET(64, CRC64_WE); + HANDLE_CRC_PRESET(64, CRC64_XZ); + HANDLE_CRC_PRESET(64, CRC64_ISO); +#endif /* #if RZ_HAVE_CRC64_EXTRA */ +} + RZ_API void rz_hash_do_end(RzHash *ctx, ut64 flags) { if_has_flag(RZ_HASH_MD4) { rz_md4_fini(ctx->digest, &ctx->md4); } if_has_flag(RZ_HASH_MD5) { - rz_hash_do_md5(ctx, NULL, -2); + MD5_Final(ctx->digest, &ctx->md5); } if_has_flag(RZ_HASH_SHA1) { rz_sha1_fini(ctx->digest, &ctx->sha1); diff --git a/librz/include/rz_crypto.h b/librz/include/rz_crypto.h index 2d95b3e4b9..cccd979138 100644 --- a/librz/include/rz_crypto.h +++ b/librz/include/rz_crypto.h @@ -18,9 +18,10 @@ enum { RZ_CRYPTO_MODE_CFB, }; +/* Defines in which direction the set_key methods needs to run */ enum { - RZ_CRYPTO_DIR_CIPHER, - RZ_CRYPTO_DIR_DECIPHER, + RZ_CRYPTO_DIR_ENCRYPT = 0, + RZ_CRYPTO_DIR_DECRYPT, }; typedef struct rz_crypto_t { @@ -45,14 +46,13 @@ typedef struct rz_crypto_plugin_t { bool (*update)(RzCrypto *cry, const ut8 *buf, int len); bool (*final)(RzCrypto *cry, const ut8 *buf, int len); bool (*use)(const char *algo); - int (*fini)(RzCrypto *cry); + bool (*init)(RzCrypto *cry); + bool (*fini)(RzCrypto *cry); } RzCryptoPlugin; typedef ut64 RzCryptoSelector; #ifdef RZ_API -RZ_API RzCrypto *rz_crypto_init(RzCrypto *cry, int hard); -RZ_API RzCrypto *rz_crypto_as_new(RzCrypto *cry); RZ_API int rz_crypto_add(RzCrypto *cry, RzCryptoPlugin *h); RZ_API RzCrypto *rz_crypto_new(void); RZ_API RzCrypto *rz_crypto_free(RzCrypto *cry); @@ -62,7 +62,7 @@ RZ_API bool rz_crypto_set_iv(RzCrypto *cry, const ut8 *iv, int ivlen); RZ_API int rz_crypto_update(RzCrypto *cry, const ut8 *buf, int len); RZ_API int rz_crypto_final(RzCrypto *cry, const ut8 *buf, int len); RZ_API int rz_crypto_append(RzCrypto *cry, const ut8 *buf, int len); -RZ_API ut8 *rz_crypto_get_output(RzCrypto *cry, int *size); +RZ_API const ut8 *rz_crypto_get_output(RzCrypto *cry, int *size); RZ_API const char *rz_crypto_name(const RzCryptoSelector bit); RZ_API const char *rz_crypto_codec_name(const RzCryptoSelector bit); #endif diff --git a/librz/include/rz_hash.h b/librz/include/rz_hash.h index a638990867..e8ccacb264 100644 --- a/librz/include/rz_hash.h +++ b/librz/include/rz_hash.h @@ -197,9 +197,9 @@ struct rz_hash_t { }; typedef struct rz_hash_seed_t { - int prefix; + bool as_prefix; ut8 *buf; - int len; + size_t len; } RzHashSeed; #define RZ_HASH_SIZE_CRC8_SMBUS 1 @@ -537,6 +537,7 @@ RZ_API int rz_hash_pcprint(const ut8 *buffer, ut64 len); /* lifecycle */ RZ_API void rz_hash_do_begin(RzHash *ctx, ut64 flags); +RZ_API void rz_hash_do_update(RzHash *ctx, ut64 flags, const ut8 *data, ut64 len); RZ_API void rz_hash_do_end(RzHash *ctx, ut64 flags); RZ_API void rz_hash_do_spice(RzHash *ctx, ut64 algo, int loops, RzHashSeed *seed); #endif diff --git a/librz/main/rz-hash.c b/librz/main/rz-hash.c index 7e530023ad..7857786b8d 100644 --- a/librz/main/rz-hash.c +++ b/librz/main/rz-hash.c @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2009-2020 pancake +// SPDX-FileCopyrightText: 2021 deroad // SPDX-License-Identifier: LGPL-3.0-only #include @@ -10,754 +10,1111 @@ #include #include -static ut64 from = 0LL; -static ut64 to = 0LL; -static bool incremental = true; -static int iterations = 0; -static int quiet = 0; -static RzHashSeed s = { - 0 -}, - *_s = NULL; +#define RZ_CRYPTO_NBITS (sizeof(RzCryptoSelector) * 8) -static void compare_hashes(const RzHash *ctx, const ut8 *compare, int length, int *ret) { - if (compare) { - // algobit has only 1 bit set - if (!memcmp(ctx->digest, compare, length)) { - printf("rz-hash: Computed hash matches the expected one.\n"); - } else { - eprintf("rz-hash: Computed hash doesn't match the expected one.\n"); - *ret = 1; - } - } -} +typedef enum { + RZ_HASH_MODE_STANDARD = 0, + RZ_HASH_MODE_JSON, + RZ_HASH_MODE_RANDOMART, + RZ_HASH_MODE_QUIET, + RZ_HASH_MODE_VERY_QUIET, +} RzHashMode; -static void do_hash_seed(const char *seed) { - const char *sptr = seed; - if (!seed) { - _s = NULL; +typedef enum { + RZ_HASH_OP_UNKNOWN = 0, + RZ_HASH_OP_ERROR, + RZ_HASH_OP_HELP, + RZ_HASH_OP_USAGE, + RZ_HASH_OP_VERSION, + RZ_HASH_OP_LIST_ALGO, + RZ_HASH_OP_HASH, + RZ_HASH_OP_DECRYPT, + RZ_HASH_OP_ENCRYPT, +} RzHashOp; + +typedef struct { + ut64 from; + ut64 to; +} RzHashOffset; + +typedef struct rz_hash_context { + bool little_endian; + bool show_blocks; + bool use_stdin; + char *algorithm; + char *compare; + char *iv; + char *input; + const char **files; + ut32 nfiles; + RzHashSeed seed; + RzHashMode mode; + RzHashOffset offset; + RzHashOp operation; + ut64 iterate; + ut64 block_size; + /* Output here */ + PJ *pj; + bool newline; +} RzHashContext; + +typedef bool (*RzHashRun)(RzHashContext *ctx, RzIO *io, const char *filename); + +static void rz_hash_show_help(bool usage_only) { + printf("Usage: rz-hash [-vhBkjLq] [-b S] [-a A] [-c H] [-E A] [-D A] [-s S] [-x S] [-f O] [-t O] [files|-] ...\n"); + if (usage_only) { return; } - _s = &s; - if (!strcmp(seed, "-")) { - s.buf = (ut8 *)rz_stdin_slurp(&s.len); - return; - } - if (seed[0] == '@') { - size_t len; - s.buf = (ut8 *)rz_file_slurp(seed + 1, &len); - s.len = (size_t)len; - return; - } - s.buf = (ut8 *)malloc(strlen(seed) + 128); - if (!s.buf) { - _s = NULL; - return; - } - if (*seed == '^') { - s.prefix = 1; - sptr++; - } else { - s.prefix = 0; - } - if (!strncmp(sptr, "s:", 2)) { - strcpy((char *)s.buf, sptr + 2); - s.len = strlen(sptr + 2); - } else { - s.len = rz_hex_str2bin(sptr, s.buf); - if (s.len < 1) { - strcpy((char *)s.buf, sptr); - s.len = strlen(sptr); - eprintf("Warning: This is not an hexpair, assuming a string, prefix it with 's:' to skip this message."); - } - } -} - -static void do_hash_hexprint(const ut8 *c, int len, int ule, PJ *pj, int rad) { - int i; - char *buf = malloc(len * 2 + 1); - if (!buf) { - return; - } - if (ule) { - for (i = 0; i < len; i++) { - snprintf(buf + i * 2, (len - i) * 2 + 1, "%02x", c[len - i - 1]); - } - } else { - for (i = 0; i < len; i++) { - snprintf(buf + i * 2, (len - i) * 2 + 1, "%02x", c[i]); - } - } - if (rad == 'j') { - pj_ks(pj, "hash", buf); - } else { - printf("%s%s", buf, rad == 'n' ? "" : "\n"); - } - free(buf); -} - -static void do_hash_print(RzHash *ctx, ut64 hash, int dlen, PJ *pj, int rad, int ule) { - char *o; - const ut8 *c = ctx->digest; - const char *hname = rz_hash_name(hash); - switch (rad) { - case 0: - if (!quiet) { - printf("0x%08" PFMT64x "-0x%08" PFMT64x " %s: ", - from, to > 0 ? to - 1 : 0, hname); - } - if (dlen == RZ_HASH_SIZE_ENTROPY) { - printf("%.8f\n", ctx->entropy); - } else { - do_hash_hexprint(c, dlen, ule, pj, rad); - } - break; - case 'n': - do_hash_hexprint(c, dlen, ule, pj, rad); - break; - case 'j': - pj_o(pj); - pj_ks(pj, "name", hname); - do_hash_hexprint(c, dlen, ule, pj, rad); - pj_end(pj); - break; - default: - o = rz_print_randomart(c, dlen, from); - printf("%s\n%s\n", hname, o); - free(o); - break; - } -} - -static int do_hash_internal(RzHash *ctx, ut64 hash, const ut8 *buf, int len, PJ *pj, int rad, int print, int le) { - if (len < 0) { - return 0; - } - int dlen = rz_hash_calculate(ctx, hash, buf, len); - if (!print) { - return 1; - } - if (iterations > 0) { - rz_hash_do_spice(ctx, hash, iterations, _s); - } - do_hash_print(ctx, hash, dlen, pj, rad, le); - return 1; -} - -static int do_hash(const char *file, const char *algo, RzIO *io, int bsize, int rad, int ule, const ut8 *compare) { - ut64 j, fsize, algobit = rz_hash_name_to_bits(algo); - RzHash *ctx; - ut8 *buf; - int ret = 0; - ut64 i; - if (algobit == RZ_HASH_NONE) { - eprintf("rz-hash: Invalid hashing algorithm specified\n"); - return 1; - } - fsize = rz_io_desc_size(io->desc); - if (fsize < 1) { - eprintf("rz-hash: Invalid file size\n"); - return 1; - } - if (bsize < 0) { - bsize = fsize / -bsize; - } - if (bsize == 0 || bsize > fsize) { - bsize = fsize; - } - if (to == 0LL) { - to = fsize; - } - if (from > to) { - eprintf("rz-hash: Invalid -f -t range\n"); - return 1; - } - if (fsize == -1LL) { - eprintf("rz-hash: Unknown file size\n"); - return 1; - } - buf = calloc(1, bsize + 1); - if (!buf) { - return 1; - } - - PJ *pj = NULL; - if (rad == 'j') { - pj = pj_new(); - if (!pj) { - free(buf); - return 1; - } - pj_a(pj); - } - ctx = rz_hash_new(true, algobit); - - if (incremental) { - for (i = 1; i < RZ_HASH_ALL; i <<= 1) { - if (algobit & i) { - ut64 hashbit = i & algobit; - int dlen = rz_hash_size(hashbit); - rz_hash_do_begin(ctx, i); - if (s.buf && s.prefix) { - do_hash_internal(ctx, hashbit, s.buf, s.len, pj, rad, 0, ule); - } - for (j = from; j < to; j += bsize) { - int len = ((j + bsize) > to) ? (to - j) : bsize; - rz_io_pread_at(io, j, buf, len); - do_hash_internal(ctx, hashbit, buf, len, pj, rad, 0, ule); - } - if (s.buf && !s.prefix) { - do_hash_internal(ctx, hashbit, s.buf, s.len, pj, rad, 0, ule); - } - rz_hash_do_end(ctx, i); - if (iterations > 0) { - rz_hash_do_spice(ctx, i, iterations, _s); - } - if (!*rz_hash_name(i)) { - continue; - } - if (!quiet && rad != 'j') { - printf("%s: ", file); - } - do_hash_print(ctx, i, dlen, pj, quiet ? 'n' : rad, ule); - if (quiet == 1) { - printf(" %s\n", file); - } else { - if (quiet && !rad) { - printf("\n"); - } - } - } - } - if (_s) { - free(_s->buf); - } - } else { - /* iterate over all algorithm bits */ - if (s.buf) { - eprintf("Warning: Seed ignored on per-block hashing.\n"); - } - for (i = 1; i < RZ_HASH_ALL; i <<= 1) { - ut64 f, t, ofrom, oto; - if (algobit & i) { - ut64 hashbit = i & algobit; - ofrom = from; - oto = to; - f = from; - t = to; - for (j = f; j < t; j += bsize) { - int nsize = (j + bsize < fsize) ? bsize : (fsize - j); - rz_io_pread_at(io, j, buf, bsize); - from = j; - to = j + bsize; - if (to > fsize) { - to = fsize; - } - do_hash_internal(ctx, hashbit, buf, nsize, pj, rad, 1, ule); - } - do_hash_internal(ctx, hashbit, NULL, 0, pj, rad, 1, ule); - from = ofrom; - to = oto; - } - } - } - if (rad == 'j') { - pj_end(pj); - printf("%s\n", pj_string(pj)); - pj_free(pj); - } - - compare_hashes(ctx, compare, rz_hash_size(algobit), &ret); - rz_hash_free(ctx); - free(buf); - return ret; -} - -static int do_help(int line) { - printf("Usage: rz-hash [-BhjkLqrv] [-b S] [-a A] [-c H] [-E A] [-s S] [-f O] [-t O] [file] ...\n"); - if (line) { - return 0; - } printf( - " -a algo comma separated list of algorithms (default is 'sha256')\n" - " -b bsize specify the size of the block (instead of full file)\n" - " -B show per-block hash\n" - " -c hash compare with this hash\n" - " -e swap endian (use little endian)\n" - " -E algo encrypt. Use -S to set key and -I to set IV\n" - " -D algo decrypt. Use -S to set key and -I to set IV\n" - " -f from start hashing at given address\n" - " -i num repeat hash N iterations\n" - " -I iv use give initialization vector (IV) (hexa or s:string)\n" - " -j output in json\n" - " -S seed use given seed (hexa or s:string) use ^ to prefix (key for -E)\n" - " (- will slurp the key from stdin, the @ prefix points to a file\n" - " -k show hash using the openssh's randomkey algorithm\n" - " -q run in quiet mode (-qq to show only the hash)\n" - " -L list all available algorithms (see -a)\n" - " -r output rizin commands\n" - " -s string hash this string instead of files\n" - " -t to stop hashing at given address\n" - " -x hexstr hash this hexpair string instead of files\n" - " -v show version information\n"); - return 0; + " -v Shows version\n" + " -h Shows this help page\n" + " - Input read from stdin instead from a file\n" + " -a algo Hash algorithm to use and you can specify multiple ones by\n" + " appending a comma (example: sha1,md4,md5,sha256)\n" + " -B Outputs the calculated value for each block\n" + " -b size Sets the block size\n" + " -c value Compare calculated value with a given one (hexadecimal)\n" + " -e endian Sets the endianness (default: 'big' accepted: 'big' or 'little')\n" + " -D algo Decrypt the given input; use -S to set key and -I to set IV (if needed)\n" + " -E algo Encrypt the given input; use -S to set key and -I to set IV (if needed)\n" + " -f from Starts the calculation at given offset\n" + " -t to Stops the calculation at given offset\n" + " -I iv Sets the initialization vector (IV)\n" + " -i times Repeat the calculation N times\n" + " -j Outputs the result as a JSON structure\n" + " -k Outputs the calculated value using openssh's randomkey algorithm\n" + " -L List all algorithms\n" + " -q Sets quiet mode (use -qq to get only the calculated value)\n" + " -S seed/key Sets the seed for -a and the key for -E/-D, use '^' to append it before\n" + " the input, use '@' prefix to load it from a file and '-' from read it\n" + " from stdin (you can combine them)\n" + " -s string Input read from a zero-terminated string instead from a file\n" + " -x hex Input read from a hexadecimal value instead from a file\n" + "\n" + " All the inputs (besides -s/-x/-c) can be hexadecimal or strings\n" + " if 's:' prefix is specified\n"); } -static void algolist(void) { - ut64 bits; - ut64 i; - for (i = 0; i < RZ_HASH_NBITS; i++) { - bits = 1ULL << i; - const char *name = rz_hash_name(bits); - if (name && *name) { - printf("h %s\n", name); +static void rz_hash_show_algorithms() { + const char *name; + for (ut64 i = 0; i < RZ_HASH_NBITS; i++) { + name = rz_hash_name(1ull << i); + if (RZ_STR_ISEMPTY(name)) { + continue; } + printf("h %s\n", name); } - // TODO: do not hardcode - printf("e base64\n"); - printf("e base91\n"); - printf("e punycode\n"); - for (i = 0;; i++) { - bits = ((ut64)1) << i; - const char *name = rz_crypto_name(bits); - if (!name || !*name) { - break; + + for (ut64 i = 0; i < RZ_CRYPTO_NBITS; i++) { + name = rz_crypto_codec_name(1ul << i); + if (RZ_STR_ISEMPTY(name)) { + continue; + } + printf("e %s\n", name); + } + + for (ut64 i = 0; i < RZ_CRYPTO_NBITS; i++) { + name = rz_crypto_name(1ul << i); + if (RZ_STR_ISEMPTY(name)) { + continue; } printf("c %s\n", name); } } -#define setHashString(x, y) \ - { \ - if (hashstr) { \ - eprintf("Hashstring already defined\n"); \ - return 1; \ +#define rz_hash_error(x, o, f, ...) \ + (x)->operation = o; \ + RZ_LOG_ERROR("rz-hash: error, " f, ##__VA_ARGS__); \ + return; + +#define rz_hash_set_val(x, k, d, v) \ + do { \ + if ((k) != (d)) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "invalid combination of arguments for '-%c' (expected " #d " but found something else)\n", c); \ } \ - hashstr_hex = y; \ - hashstr = (char *)x; \ + (k) = (v); \ + } while (0) + +#define rz_hash_ctx_set_val(x, k, d, v) \ + do { \ + if ((x)->k != (d)) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "invalid combination of arguments for '-%c' (expected " #d " but found something else)\n", c); \ + } \ + (x)->k = (v); \ + } while (0) + +#define rz_hash_ctx_set_bool(x, k, i, t, f) \ + do { \ + if (i && !strcmp(i, t)) { \ + (x)->k = true; \ + } else if (i && !strcmp(i, f)) { \ + (x)->k = false; \ + } else { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "expected '%s' or '%s' but got '%s'\n", t, f, i); \ + } \ + } while (0) + +#define rz_hash_ctx_set_quiet(x) \ + do { \ + if ((x)->mode == RZ_HASH_MODE_STANDARD) { \ + (x)->mode = RZ_HASH_MODE_QUIET; \ + } else if ((x)->mode == RZ_HASH_MODE_QUIET) { \ + (x)->mode = RZ_HASH_MODE_VERY_QUIET; \ + } else if ((x)->mode == RZ_HASH_MODE_JSON) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "can't be quiet when json mode is selected\n"); \ + } else if ((x)->mode == RZ_HASH_MODE_RANDOMART) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "can't be quiet when openssh mode is selected\n"); \ + } \ + } while (0) + +#define rz_hash_ctx_set_signed(x, k, i) \ + do { \ + (x)->k = strtoll((i), NULL, 0); \ + if ((x)->k < 1) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "argument must be > 0\n"); \ + } \ + } while (0) + +#define rz_hash_ctx_set_unsigned(x, k, i) \ + do { \ + (x)->k = strtoull((i), NULL, 0); \ + if ((x)->k < 1) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "argument must be > 0\n"); \ + } \ + } while (0) + +#define rz_hash_ctx_set_input(x, k, s, h) \ + do { \ + if ((x)->k) { \ + rz_hash_error(x, RZ_HASH_OP_UNKNOWN, "invalid combination of arguments for '-%c'\n", c); \ + } else if (h || strlen(s) < 1) { \ + (x)->k = strdup(s); \ + } else { \ + (x)->k = rz_str_newf("s:%s", s); \ + } \ + } while (0) + +#define rz_hash_ctx_set_mode(x, m) rz_hash_ctx_set_val(x, mode, RZ_HASH_MODE_STANDARD, m) +#define rz_hash_ctx_set_op(x, o) rz_hash_ctx_set_val(x, operation, RZ_HASH_OP_UNKNOWN, o) +#define rz_hash_ctx_set_str(x, k, s) rz_hash_ctx_set_val(x, k, NULL, strdup(s)) + +static bool rz_hash_parse_string(const char *option, const char *string, ut8 **buffer, size_t *bufsize) { + char *sstdin = NULL; + int stringlen = 0; + if (!strcmp(string, "-")) { + string = sstdin = rz_stdin_slurp(&stringlen); + } else { + stringlen = strlen(string); + } + if (stringlen < 1 || !string) { + RZ_LOG_ERROR("rz-hash: error, option %s is empty.\n", option); + free(sstdin); + return false; } -static bool is_power_of_two(const ut64 x) { - return x && !(x & (x - 1)); + ut8 *b = (ut8 *)malloc(stringlen + 1); + if (!b) { + RZ_LOG_ERROR("rz-hash: error, failed to allocate string in memory.\n"); + free(sstdin); + return false; + } + + memcpy(b, string, stringlen); + b[stringlen] = 0; + stringlen = rz_str_unescape((char *)b); + + *buffer = b; + *bufsize = stringlen; + free(sstdin); + + return true; } -// direction: 0 => encrypt, 1 => decrypt -static int encrypt_or_decrypt(const char *algo, int direction, const char *hashstr, int hashstr_len, const ut8 *iv, int ivlen, int mode) { - bool no_key_mode = !strcmp("base64", algo) || !strcmp("base91", algo) || !strcmp("punycode", algo); // TODO: generalise this for all non key encoding/decoding. - if (no_key_mode || s.len > 0) { - RzCrypto *cry = rz_crypto_new(); - if (rz_crypto_use(cry, algo)) { - if (rz_crypto_set_key(cry, s.buf, s.len, 0, direction)) { - const char *buf = hashstr; - int buflen = hashstr_len; - - if (iv && !rz_crypto_set_iv(cry, iv, ivlen)) { - eprintf("Invalid IV.\n"); - return 0; - } - - rz_crypto_update(cry, (const ut8 *)buf, buflen); - rz_crypto_final(cry, NULL, 0); - - int result_size = 0; - ut8 *result = rz_crypto_get_output(cry, &result_size); - if (result) { - if (write(1, result, result_size) != result_size) { - eprintf("Warning: cannot write result\n"); - } - free(result); - } - } else { - eprintf("Invalid key\n"); - } - return 0; - } else { - eprintf("Unknown %s algorithm '%s'\n", ((!direction) ? "encryption" : "decryption"), algo); - } - rz_crypto_free(cry); +static bool rz_hash_parse_hexadecimal(const char *option, const char *hexadecimal, ut8 **buffer, size_t *bufsize) { + char *sstdin = NULL; + int hexlen = 0; + if (!strcmp(hexadecimal, "-")) { + hexadecimal = sstdin = rz_stdin_slurp(&hexlen); } else { - eprintf("%s key not defined. Use -S [key]\n", ((!direction) ? "Encryption" : "Decryption")); + hexlen = strlen(hexadecimal); } - return 1; + + if (hexlen < 1 || !hexadecimal) { + RZ_LOG_ERROR("rz-hash: error, option %s is empty.\n", option); + return false; + } else if (hexlen & 1) { + RZ_LOG_ERROR("rz-hash: error, option %s is not a valid hexadecimal (len is not pair: %d).\n", option, hexlen); + return false; + } + *buffer = NULL; + st64 binlen = hexlen >> 1; + ut8 *b = (ut8 *)malloc(binlen); + if (b) { + *bufsize = rz_hex_str2bin(hexadecimal, b); + if (*bufsize < 1) { + RZ_LOG_ERROR("rz-hash: error, option %s is not a valid hexadecimal.\n", option); + free(b); + free(sstdin); + return false; + } + *buffer = b; + } + + free(sstdin); + return true; } -static int encrypt_or_decrypt_file(const char *algo, int direction, const char *filename, const ut8 *iv, int ivlen, int mode) { - bool no_key_mode = !strcmp("base64", algo) || !strcmp("base91", algo) || !strcmp("punycode", algo); // TODO: generalise this for all non key encoding/decoding. - if (no_key_mode || s.len > 0) { - RzCrypto *cry = rz_crypto_new(); - if (rz_crypto_use(cry, algo)) { - if (rz_crypto_set_key(cry, s.buf, s.len, 0, direction)) { - size_t file_size; - ut8 *buf; - if (strcmp(filename, "-") == 0) { - int sz; - buf = (ut8 *)rz_stdin_slurp(&sz); - file_size = (size_t)sz; - } else { - buf = (ut8 *)rz_file_slurp(filename, &file_size); - } - if (!buf) { - eprintf("rz-hash: Cannot open '%s'\n", filename); - return -1; - } +static void rz_hash_parse_cmdline(int argc, const char **argv, RzHashContext *ctx) { + const char *seed = NULL; - if (iv && !rz_crypto_set_iv(cry, iv, ivlen)) { - eprintf("Invalid IV.\n"); - free(buf); - return 0; - } + memset((void *)ctx, 0, sizeof(RzHashContext)); - rz_crypto_update(cry, buf, file_size); - rz_crypto_final(cry, NULL, 0); - - int result_size = 0; - ut8 *result = rz_crypto_get_output(cry, &result_size); - if (result) { - rz_xwrite(1, result, result_size); - free(result); - } - free(buf); - } else { - eprintf("Invalid key\n"); - } - return 0; - } else { - eprintf("Unknown %s algorithm '%s'\n", ((!direction) ? "encryption" : "decryption"), algo); + RzGetopt opt; + int c; + rz_getopt_init(&opt, argc, argv, "jD:e:vE:a:i:I:S:s:x:b:nBhf:t:kLqc:"); + while ((c = rz_getopt_next(&opt)) != -1) { + switch (c) { + case 'q': rz_hash_ctx_set_quiet(ctx); break; + case 'i': rz_hash_ctx_set_signed(ctx, iterate, opt.arg); break; + case 'j': rz_hash_ctx_set_mode(ctx, RZ_HASH_MODE_JSON); break; + case 'S': rz_hash_set_val(ctx, seed, NULL, opt.arg); break; + case 'I': rz_hash_ctx_set_str(ctx, iv, opt.arg); break; + case 'D': + rz_hash_ctx_set_str(ctx, algorithm, opt.arg); + rz_hash_ctx_set_op(ctx, RZ_HASH_OP_DECRYPT); + break; + case 'E': + rz_hash_ctx_set_str(ctx, algorithm, opt.arg); + rz_hash_ctx_set_op(ctx, RZ_HASH_OP_ENCRYPT); + break; + case 'L': rz_hash_ctx_set_op(ctx, RZ_HASH_OP_LIST_ALGO); break; + case 'e': rz_hash_ctx_set_bool(ctx, little_endian, opt.arg, "little", "big"); break; + case 'k': rz_hash_ctx_set_mode(ctx, RZ_HASH_MODE_RANDOMART); break; + case 'a': + rz_hash_ctx_set_str(ctx, algorithm, opt.arg); + rz_hash_ctx_set_op(ctx, RZ_HASH_OP_HASH); + break; + case 'B': ctx->show_blocks = true; break; + case 'b': rz_hash_ctx_set_unsigned(ctx, block_size, opt.arg); break; + case 'f': rz_hash_ctx_set_unsigned(ctx, offset.from, opt.arg); break; + case 't': rz_hash_ctx_set_unsigned(ctx, offset.to, opt.arg); break; + case 'v': ctx->operation = RZ_HASH_OP_VERSION; break; + case 'h': ctx->operation = RZ_HASH_OP_HELP; break; + case 's': rz_hash_ctx_set_input(ctx, input, opt.arg, false); break; + case 'x': rz_hash_ctx_set_input(ctx, input, opt.arg, true); break; + case 'c': rz_hash_ctx_set_str(ctx, compare, opt.arg); break; + default: + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "unknown flag '%c'\n", c); } - rz_crypto_free(cry); - } else { - eprintf("%s key not defined. Use -S [key]\n", ((!direction) ? "Encryption" : "Decryption")); } - return 1; + + if (ctx->operation == RZ_HASH_OP_HELP || + ctx->operation == RZ_HASH_OP_VERSION || + ctx->operation == RZ_HASH_OP_LIST_ALGO) { + return; + } + + if (opt.ind >= argc && !ctx->input) { + ctx->operation = RZ_HASH_OP_USAGE; + return; + } + + if (!ctx->input && !strcmp(argv[argc - 1], "-")) { + ctx->use_stdin = true; + } else { + ctx->files = RZ_NEWS(const char *, argc - opt.ind); + if (!ctx->files) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "failed to allocate file array memory.\n"); + } + ctx->nfiles = 0; + for (int i = opt.ind; i < argc; ++i) { + if (IS_NULLSTR(argv[i])) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "cannot open a file without a name.\n"); + } + if (rz_file_is_directory(argv[i])) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "cannot open directories (%s).\n", argv[i]); + } + ctx->files[ctx->nfiles++] = argv[i]; + } + } + + if (ctx->nfiles < 1 && !ctx->use_stdin && !ctx->input) { + ctx->operation = RZ_HASH_OP_USAGE; + return; + } + + if (ctx->operation == RZ_HASH_OP_ENCRYPT || ctx->operation == RZ_HASH_OP_DECRYPT) { + if (!seed && strncmp("base", ctx->algorithm, 4) && strcmp("punycode", ctx->algorithm)) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -S is required for algorithm '%s'.\n", ctx->algorithm); + } + if (ctx->compare) { + ssize_t len = strlen(ctx->compare); + if (!strncmp(ctx->algorithm, "base", 4)) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -c is incompatible with -E or -D with algorithm base64 or base91.\n"); + } else if (strchr(ctx->algorithm, ',')) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -c incompatible with multiple algorithms.\n"); + } else if (len < 1 || c & 1) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -c value length is not multiple of 2 (expected hexadecimal value).\n"); + } + } + if (ctx->show_blocks) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -B is incompatible with -E/-D.\n"); + } + if (ctx->mode == RZ_HASH_MODE_RANDOMART) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -k is incompatible with -E/-D.\n"); + } + } else if (ctx->operation == RZ_HASH_OP_HASH) { + if (ctx->iv) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -I is incompatible with -a; use -S to define a seed.\n"); + } + if (ctx->show_blocks && ctx->compare) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -B is incompatible with -c.\n"); + } + if (ctx->mode == RZ_HASH_MODE_RANDOMART && ctx->compare) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -c is incompatible with -k.\n"); + } + if (ctx->mode == RZ_HASH_MODE_RANDOMART && strchr(ctx->algorithm, ',')) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -a with multiple algorithms is incompatible with -k.\n"); + } + } + + if (ctx->offset.from && ctx->offset.to && ctx->offset.from >= ctx->offset.to) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -f value (%" PFMT64u ") is greater or equal to -t value (%" PFMT64u ").\n", ctx->offset.from, ctx->offset.to); + } + if (ctx->block_size && ctx->offset.from && ctx->offset.to && (ctx->offset.to - ctx->offset.from) % ctx->block_size) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "range between %" PFMT64u " and %" PFMT64u " is not a multiple of %" PFMT64u ".\n", ctx->offset.from, ctx->offset.to, ctx->block_size); + } + + if (seed) { + if (seed[0] == '^') { + seed++; + ctx->seed.as_prefix = true; + } + ssize_t seedlen = strlen(seed); + if (seedlen < 1) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "option -S is empty.\n"); + } + if (!strcmp(seed, "-")) { + int stdinlen = 0; + ctx->seed.buf = (ut8 *)rz_stdin_slurp(&stdinlen); + ctx->seed.len = stdinlen; + } else if (seed[0] == '@') { + ctx->seed.buf = (ut8 *)rz_file_slurp(seed + 1, &ctx->seed.len); + } else if (!strncmp(seed, "s:", 2)) { + if (!rz_hash_parse_string("-S", seed + 2, &ctx->seed.buf, &ctx->seed.len)) { + ctx->operation = RZ_HASH_OP_ERROR; + return; + } + } else { + if (!rz_hash_parse_hexadecimal("-S", seed, &ctx->seed.buf, &ctx->seed.len)) { + ctx->operation = RZ_HASH_OP_ERROR; + return; + } + } + if (!ctx->seed.buf) { + rz_hash_error(ctx, RZ_HASH_OP_ERROR, "failed to allocate seed memory.\n"); + } + } + + if (!ctx->block_size) { + ctx->block_size = 0x1000; + } +} + +static void rz_hash_context_fini(RzHashContext *ctx) { + free(ctx->algorithm); + free(ctx->compare); + free(ctx->iv); + free(ctx->input); + free(ctx->files); + free(ctx->seed.buf); + pj_free(ctx->pj); +} + +static RzIODesc *rz_hash_context_create_desc_io_stdin(RzIO *io) { + RzIODesc *desc = NULL; + int size; + char *uri = NULL; + ut8 *buffer = NULL; + + buffer = (ut8 *)rz_stdin_slurp(&size); + if (size < 1 || !buffer) { + goto rz_hash_context_create_desc_io_stdin_end; + } + + uri = rz_str_newf("malloc://%d", size); + if (!uri) { + rz_warn_if_reached(); + goto rz_hash_context_create_desc_io_stdin_end; + } + + desc = rz_io_open_nomap(io, uri, RZ_PERM_R, 0); + if (!desc) { + RZ_LOG_ERROR("rz-hash: error, cannot open malloc://%d\n", size); + goto rz_hash_context_create_desc_io_stdin_end; + } + + if (rz_io_pwrite_at(io, 0, buffer, size) != size) { + RZ_LOG_ERROR("rz-hash: error, cannot write into malloc://%d buffer\n", size); + rz_io_desc_close(desc); + desc = NULL; + goto rz_hash_context_create_desc_io_stdin_end; + } + +rz_hash_context_create_desc_io_stdin_end: + free(buffer); + free(uri); + return desc; +} + +static RzIODesc *rz_hash_context_create_desc_io_string(RzIO *io, const char *input) { + RzIODesc *desc = NULL; + char *uri = NULL; + ut8 *buffer = NULL; + size_t size; + + bool is_string = !strncmp(input, "s:", 2); + + if (is_string) { + if (!rz_hash_parse_string("-s", input + 2, &buffer, &size)) { + goto rz_hash_context_create_desc_io_string_end; + } + } else { + if (!rz_hash_parse_hexadecimal("-x", input, &buffer, &size)) { + goto rz_hash_context_create_desc_io_string_end; + } + } + if (!buffer || (!is_string && size < 1)) { + rz_warn_if_reached(); + goto rz_hash_context_create_desc_io_string_end; + } else if (is_string && size < 1) { + goto rz_hash_context_create_desc_io_string_end; + } + + uri = rz_str_newf("malloc://%lu", size); + if (!uri) { + rz_warn_if_reached(); + goto rz_hash_context_create_desc_io_string_end; + } + + desc = rz_io_open_nomap(io, uri, RZ_PERM_R, 0); + if (!desc) { + RZ_LOG_ERROR("rz-hash: error, cannot open malloc://%lu\n", size); + goto rz_hash_context_create_desc_io_string_end; + } + + if (rz_io_pwrite_at(io, 0, buffer, size) != size) { + RZ_LOG_ERROR("rz-hash: error, cannot write into malloc://%lu buffer\n", size); + rz_io_desc_close(desc); + desc = NULL; + goto rz_hash_context_create_desc_io_string_end; + } + +rz_hash_context_create_desc_io_string_end: + free(buffer); + free(uri); + return desc; +} + +static bool rz_hash_context_run(RzHashContext *ctx, RzHashRun run) { + bool result = false; + RzIODesc *desc = NULL; + + RzIO *io = rz_io_new(); + if (!io) { + rz_warn_if_reached(); + return false; + } + + if (ctx->mode == RZ_HASH_MODE_JSON) { + ctx->pj = pj_new(); + if (!ctx->pj) { + RZ_LOG_ERROR("rz-hash: error, failed to allocate JSON memory.\n"); + goto rz_hash_context_run_end; + } + pj_o(ctx->pj); + } + if (ctx->use_stdin) { + desc = rz_hash_context_create_desc_io_stdin(io); + if (!desc) { + RZ_LOG_ERROR("rz-hash: error, cannot read stdin\n"); + goto rz_hash_context_run_end; + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_ka(ctx->pj, "stdin"); + } + if (!run(ctx, io, "stdin")) { + goto rz_hash_context_run_end; + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + } + } else if (ctx->input) { + if (strlen(ctx->input) > 0) { + desc = rz_hash_context_create_desc_io_string(io, ctx->input); + if (!desc) { + RZ_LOG_ERROR("rz-hash: error, cannot read string\n"); + goto rz_hash_context_run_end; + } + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_ka(ctx->pj, !strncmp(ctx->input, "s:", 2) ? "string" : "hexadecimal"); + } + if (!run(ctx, io, !strncmp(ctx->input, "s:", 2) ? "string" : "hexadecimal")) { + goto rz_hash_context_run_end; + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + } + } else { + for (ut32 i = 0; i < ctx->nfiles; ++i) { + desc = rz_io_open_nomap(io, ctx->files[i], RZ_PERM_R, 0); + if (!desc) { + RZ_LOG_ERROR("rz-hash: error, cannot open file '%s'\n", ctx->files[i]); + goto rz_hash_context_run_end; + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_ka(ctx->pj, ctx->files[i]); + } + if (!run(ctx, io, ctx->files[i])) { + goto rz_hash_context_run_end; + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + } + rz_io_desc_close(desc); + desc = NULL; + } + } + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + printf("%s\n", pj_string(ctx->pj)); + } + result = true; + +rz_hash_context_run_end: + rz_io_desc_close(desc); + rz_io_free(io); + return result; +} + +static void rz_hash_print_crypto(RzHashContext *ctx, const char *hname, const ut8 *buffer, int len, ut64 from, ut64 to) { + char *value = ctx->operation == RZ_HASH_OP_ENCRYPT ? malloc(len * 2 + 1) : malloc(len + 1); + if (!value) { + RZ_LOG_ERROR("rz-hash: error, cannot allocate value memory\n"); + return; + } + + if (ctx->operation == RZ_HASH_OP_ENCRYPT) { + for (int i = 0, bsize; i < len; i++) { + bsize = (len - i) * 2 + 1; + snprintf(value + (i * 2), bsize, "%02x", buffer[i]); + } + } else { + memcpy(value, buffer, len); + value[len] = 0; + } + + switch (ctx->mode) { + case RZ_HASH_MODE_JSON: + pj_kn(ctx->pj, "from", from); + pj_kn(ctx->pj, "to", to); + pj_ks(ctx->pj, "name", hname); + pj_ks(ctx->pj, "value", value); + break; + case RZ_HASH_MODE_RANDOMART: + case RZ_HASH_MODE_STANDARD: + printf("0x%08" PFMT64x "-0x%08" PFMT64x " %s: ", from, to, hname); + fflush(stdout); + if (write(1, buffer, len) != len) { + RZ_LOG_ERROR("rz-hash: error, cannot write on stdout\n"); + } + printf("\n"); + break; + case RZ_HASH_MODE_QUIET: + printf("%s: ", hname); + fflush(stdout); + if (write(1, buffer, len) != len) { + RZ_LOG_ERROR("rz-hash: error, cannot write on stdout\n"); + } + printf("\n"); + break; + case RZ_HASH_MODE_VERY_QUIET: + if (write(1, buffer, len) != len) { + RZ_LOG_ERROR("rz-hash: error, cannot write on stdout\n"); + } + break; + } + free(value); +} + +static void rz_hash_print_digest(RzHashContext *ctx, RzHash *hctx, const char *hname, const ut8 *buffer, int len, ut64 from, ut64 to, const char *filename) { + bool is_entropy = !strcmp(hname, "entropy"); + char *rndart = NULL; + char *value = !is_entropy ? malloc(len * 2 + 1) : rz_str_newf("%.8f", hctx->entropy); + if (!value) { + return; + } + if (!is_entropy) { + if (ctx->little_endian) { + for (int i = 0, bsize; i < len; i++) { + bsize = (len - i) * 2 + 1; + snprintf(value + (i * 2), bsize, "%02x", buffer[len - i - 1]); + } + } else { + for (int i = 0, bsize; i < len; i++) { + bsize = (len - i) * 2 + 1; + snprintf(value + (i * 2), bsize, "%02x", buffer[i]); + } + } + } + + bool has_seed = !ctx->iv && ctx->seed.len > 0; + + switch (ctx->mode) { + case RZ_HASH_MODE_JSON: + if (has_seed) { + pj_kb(ctx->pj, "seed", true); + } + pj_kn(ctx->pj, "from", from); + pj_kn(ctx->pj, "to", to); + pj_ks(ctx->pj, "name", hname); + if (is_entropy) { + pj_kd(ctx->pj, "entropy", hctx->entropy); + } else { + pj_ks(ctx->pj, "hash", value); + } + break; + case RZ_HASH_MODE_STANDARD: + printf("%s: 0x%08" PFMT64x "-0x%08" PFMT64x " %s: %s%s\n", filename, from, to, hname, value, has_seed ? " with seed" : ""); + break; + case RZ_HASH_MODE_RANDOMART: + rndart = rz_print_randomart(buffer, len, from); + printf("%s\n%s\n", hname, rndart); + break; + case RZ_HASH_MODE_QUIET: + printf("%s: %s: %s\n", filename, hname, value); + break; + case RZ_HASH_MODE_VERY_QUIET: + printf("%s", value); + break; + } + free(value); + free(rndart); +} + +static void rz_hash_context_compare_hashes(RzHashContext *ctx, size_t filesize, bool result, const char *hname, const char *filename) { + ut64 to = ctx->offset.to ? ctx->offset.to : filesize; + switch (ctx->mode) { + case RZ_HASH_MODE_JSON: + pj_kb(ctx->pj, "seed", ctx->seed.len > 0); + pj_kb(ctx->pj, "compare", result); + pj_kn(ctx->pj, "from", ctx->offset.from); + pj_kn(ctx->pj, "to", to); + pj_ks(ctx->pj, "name", hname); + break; + case RZ_HASH_MODE_RANDOMART: + case RZ_HASH_MODE_STANDARD: + printf("%s: 0x%08" PFMT64x "-0x%08" PFMT64x " %s: computed hash %s the expected one\n", filename, ctx->offset.from, to, hname, result ? "matches" : "doesn't match"); + break; + case RZ_HASH_MODE_QUIET: + printf("%s: %s: computed hash %s the expected one\n", filename, hname, result ? "matches" : "doesn't match"); + break; + case RZ_HASH_MODE_VERY_QUIET: + printf("%s", result ? "true" : "false"); + break; + } +} + +static bool calculate_hash(RzHashContext *ctx, RzIO *io, const char *filename) { + bool result = false; + const char *hname = NULL; + RzHash *hctx = NULL; + ut64 algorithms, filesize; + ut8 digest[128] = { 0 }; + ut64 bsize = 0; + ut8 *block = NULL; + ut8 *cmphash = NULL; + + algorithms = rz_hash_name_to_bits(ctx->algorithm); + if (algorithms < 1) { + RZ_LOG_ERROR("rz-hash: error, invalid hash algorithm\n"); + goto calculate_hash_end; + } + + filesize = rz_io_desc_size(io->desc); + + hctx = rz_hash_new(true, algorithms); + if (!hctx) { + RZ_LOG_ERROR("rz-hash: error, cannot allocate hash context memory\n"); + goto calculate_hash_end; + } + + if (ctx->offset.to > filesize) { + RZ_LOG_ERROR("rz-hash: error, -t value is greater than file size\n"); + goto calculate_hash_end; + } + + if (ctx->offset.from > filesize) { + RZ_LOG_ERROR("rz-hash: error, -f value is greater than file size\n"); + goto calculate_hash_end; + } + + bsize = ctx->block_size; + block = malloc(bsize); + if (!block) { + RZ_LOG_ERROR("rz-hash: error, cannot allocate block memory\n"); + goto calculate_hash_end; + } + + if (ctx->compare) { + ut64 to = ctx->offset.to ? ctx->offset.to : filesize; + size_t cmphashlen = 0; + bool result = false; + + if (!rz_hash_parse_hexadecimal("-c", ctx->compare, &cmphash, &cmphashlen)) { + //RZ_LOG_ERROR("rz-hash: error, cannot allocate block memory\n"); + goto calculate_hash_end; + } + + for (ut64 i = 1; i < RZ_HASH_ALL; i <<= 1) { + if (!(algorithms & i)) { + continue; + } + hname = rz_hash_name(i); + if (IS_NULLSTR(hname)) { + // not all bits are used. + continue; + } + int hashlen = rz_hash_size(i); + if (hashlen != cmphashlen) { + result = false; + } else { + rz_hash_do_begin(hctx, i); + if (ctx->seed.as_prefix && ctx->seed.buf) { + rz_hash_do_update(hctx, i, ctx->seed.buf, ctx->seed.len); + } + + for (ut64 j = ctx->offset.from; j < to; j += bsize) { + int read = rz_io_pread_at(io, j, block, to - j > bsize ? bsize : (to - j)); + rz_hash_do_update(hctx, i, block, read); + } + + if (!ctx->seed.as_prefix && ctx->seed.buf) { + rz_hash_do_update(hctx, i, ctx->seed.buf, ctx->seed.len); + } + + rz_hash_do_end(hctx, i); + memcpy(digest, hctx->digest, hashlen); + + for (ut64 k = 0; k < ctx->iterate; ++k) { + rz_hash_calculate(hctx, i, digest, hashlen); + memcpy(digest, hctx->digest, hashlen); + } + + result = !memcmp(cmphash, digest, hashlen); + } + + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_o(ctx->pj); + } else if (ctx->mode == RZ_HASH_MODE_VERY_QUIET && ctx->newline) { + printf("\n"); + fflush(stdout); + } + rz_hash_context_compare_hashes(ctx, filesize, result, hname, filename); + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + } + ctx->newline = true; + } + } else if (ctx->show_blocks) { + ut64 to = ctx->offset.to ? ctx->offset.to : filesize; + for (ut64 i = 1; i < RZ_HASH_ALL; i <<= 1) { + if (!(algorithms & i)) { + continue; + } + + int hashlen = rz_hash_size(i); + hname = rz_hash_name(i); + for (ut64 j = ctx->offset.from; j < to; j += bsize) { + int read = rz_io_pread_at(io, j, block, to - j > bsize ? bsize : (to - j)); + + rz_hash_calculate(hctx, i, block, read); + memcpy(digest, hctx->digest, hashlen); + + for (ut64 k = 0; k < ctx->iterate; ++k) { + rz_hash_calculate(hctx, i, digest, hashlen); + memcpy(digest, hctx->digest, hashlen); + } + + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_o(ctx->pj); + } else if (ctx->mode == RZ_HASH_MODE_VERY_QUIET && ctx->newline) { + printf("\n"); + fflush(stdout); + } + rz_hash_print_digest(ctx, hctx, hname, digest, hashlen, j, j + bsize, filename); + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + } + ctx->newline = true; + } + } + } else { + ut64 to = ctx->offset.to ? ctx->offset.to : filesize; + for (ut64 i = 1; i < RZ_HASH_ALL; i <<= 1) { + if (!(algorithms & i)) { + continue; + } + + hname = rz_hash_name(i); + int hashlen = rz_hash_size(i); + + rz_hash_do_begin(hctx, i); + if (ctx->seed.as_prefix && ctx->seed.buf) { + rz_hash_do_update(hctx, i, ctx->seed.buf, ctx->seed.len); + } + + for (ut64 j = ctx->offset.from; j < to; j += bsize) { + int read = rz_io_pread_at(io, j, block, to - j > bsize ? bsize : (to - j)); + rz_hash_do_update(hctx, i, block, read); + } + + if (!ctx->seed.as_prefix && ctx->seed.buf) { + rz_hash_do_update(hctx, i, ctx->seed.buf, ctx->seed.len); + } + + rz_hash_do_end(hctx, i); + memcpy(digest, hctx->digest, hashlen); + + for (ut64 k = 0; k < ctx->iterate; ++k) { + rz_hash_calculate(hctx, i, digest, hashlen); + memcpy(digest, hctx->digest, hashlen); + } + + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_o(ctx->pj); + } else if (ctx->mode == RZ_HASH_MODE_VERY_QUIET && ctx->newline) { + printf("\n"); + fflush(stdout); + } + rz_hash_print_digest(ctx, hctx, hname, digest, hashlen, ctx->offset.from, to, filename); + if (ctx->mode == RZ_HASH_MODE_JSON) { + pj_end(ctx->pj); + } + ctx->newline = true; + } + } + result = true; + +calculate_hash_end: + free(block); + free(cmphash); + rz_hash_free(hctx); + return result; +} + +static bool calculate_decrypt(RzHashContext *ctx, RzIO *io, const char *filename) { + RzCrypto *cry = NULL; + bool result = false; + ut8 *iv = NULL; + size_t ivlen = 0; + ut64 filesize = 0; + ut64 bsize = 0; + ut8 *block = NULL; + + if (ctx->iv) { + if (!strncmp(ctx->iv, "s:", 2)) { + if (!rz_hash_parse_string("-I", ctx->iv + 2, &iv, &ivlen)) { + goto calculate_decrypt_end; + } + } else { + if (!rz_hash_parse_hexadecimal("-I", ctx->iv, &iv, &ivlen)) { + goto calculate_decrypt_end; + } + } + } + + cry = rz_crypto_new(); + if (!cry) { + RZ_LOG_ERROR("rz-hash: error, failed to allocate memory\n"); + goto calculate_decrypt_end; + } + + if (!rz_crypto_use(cry, ctx->algorithm)) { + RZ_LOG_ERROR("rz-hash: error, unknown encryption algorithm '%s'\n", ctx->algorithm); + goto calculate_decrypt_end; + } + + if (!rz_crypto_set_key(cry, ctx->seed.buf, ctx->seed.len, 0, RZ_CRYPTO_DIR_DECRYPT)) { + RZ_LOG_ERROR("rz-hash: error, invalid key\n"); + goto calculate_decrypt_end; + } + + if (iv && !rz_crypto_set_iv(cry, iv, ivlen)) { + RZ_LOG_ERROR("rz-hash: error, invalid IV.\n"); + goto calculate_decrypt_end; + } + + filesize = rz_io_desc_size(io->desc); + if (filesize < 1) { + RZ_LOG_ERROR("rz-hash: error, file size is less than 1\n"); + goto calculate_decrypt_end; + } + + bsize = ctx->block_size; + block = malloc(bsize); + if (!block) { + RZ_LOG_ERROR("rz-hash: error, cannot allocate block memory\n"); + goto calculate_decrypt_end; + } + + ut64 to = ctx->offset.to ? ctx->offset.to : filesize; + for (ut64 j = ctx->offset.from; j < to; j += bsize) { + int read = rz_io_pread_at(io, j, block, to - j > bsize ? bsize : (to - j)); + rz_crypto_update(cry, block, read); + } + + rz_crypto_final(cry, NULL, 0); + + int plaintext_size = 0; + const ut8 *plaintext = rz_crypto_get_output(cry, &plaintext_size); + + rz_hash_print_crypto(ctx, ctx->algorithm, plaintext, plaintext_size, ctx->offset.from, to); + result = true; + +calculate_decrypt_end: + free(block); + free(iv); + rz_crypto_free(cry); + return result; +} + +static bool calculate_encrypt(RzHashContext *ctx, RzIO *io, const char *filename) { + RzCrypto *cry = NULL; + bool result = false; + ut8 *iv = NULL; + size_t ivlen = 0; + ut64 filesize = 0; + ut64 bsize = 0; + ut8 *block = NULL; + + bool requires_key = !strncmp("base", ctx->algorithm, 4) || !strcmp("punycode", ctx->algorithm); + if (!requires_key && ctx->seed.len < 1) { + RZ_LOG_ERROR("rz-hash: error, cannot encrypt without a key\n"); + goto calculate_encrypt_end; + } + + if (ctx->iv) { + if (!strncmp(ctx->iv, "s:", 2)) { + if (!rz_hash_parse_string("-I", ctx->iv + 2, &iv, &ivlen)) { + goto calculate_encrypt_end; + } + } else { + if (!rz_hash_parse_hexadecimal("-I", ctx->iv, &iv, &ivlen)) { + goto calculate_encrypt_end; + } + } + } + + cry = rz_crypto_new(); + if (!cry) { + RZ_LOG_ERROR("rz-hash: error, failed to allocate memory\n"); + goto calculate_encrypt_end; + } + + if (!rz_crypto_use(cry, ctx->algorithm)) { + RZ_LOG_ERROR("rz-hash: error, unknown encryption algorithm '%s'\n", ctx->algorithm); + goto calculate_encrypt_end; + } + + if (!rz_crypto_set_key(cry, ctx->seed.buf, ctx->seed.len, 0, RZ_CRYPTO_DIR_ENCRYPT)) { + RZ_LOG_ERROR("rz-hash: error, invalid key\n"); + goto calculate_encrypt_end; + } + + if (iv && !rz_crypto_set_iv(cry, iv, ivlen)) { + RZ_LOG_ERROR("rz-hash: error, invalid IV.\n"); + goto calculate_encrypt_end; + } + + filesize = rz_io_desc_size(io->desc); + if (filesize < 1) { + RZ_LOG_ERROR("rz-hash: error, file size is less than 1\n"); + goto calculate_encrypt_end; + } + + bsize = ctx->block_size; + block = malloc(bsize); + if (!block) { + RZ_LOG_ERROR("rz-hash: error, cannot allocate block memory\n"); + goto calculate_encrypt_end; + } + + ut64 to = ctx->offset.to ? ctx->offset.to : filesize; + for (ut64 j = ctx->offset.from; j < to; j += bsize) { + int read = rz_io_pread_at(io, j, block, to - j > bsize ? bsize : (to - j)); + rz_crypto_update(cry, block, read); + } + + rz_crypto_final(cry, NULL, 0); + + int ciphertext_size = 0; + const ut8 *ciphertext = rz_crypto_get_output(cry, &ciphertext_size); + + rz_hash_print_crypto(ctx, ctx->algorithm, ciphertext, ciphertext_size, ctx->offset.from, to); + result = true; + +calculate_encrypt_end: + free(block); + free(iv); + rz_crypto_free(cry); + return result; } RZ_API int rz_main_rz_hash(int argc, const char **argv) { - ut64 i; - int ret, c, rad = 0, bsize = 0, numblocks = 0, ule = 0; - const char *file = NULL; - const char *algo = "sha256"; /* default hashing algorithm */ - const char *seed = NULL; - const char *decrypt = NULL; - const char *encrypt = NULL; - char *hashstr = NULL; - ut8 *iv = NULL; - int ivlen = -1; - const char *ivseed = NULL; - const char *compareStr = NULL; - const char *ptype = NULL; - ut8 *compareBin = NULL; - int hashstr_len = -1; - int hashstr_hex = 0; - size_t bytes_read = 0; // bytes read from stdin - ut64 algobit; - RzHash *ctx; - RzIO *io; + int result = 1; + RzHashContext ctx; - RzGetopt opt; - rz_getopt_init(&opt, argc, argv, "p:jD:veE:a:i:I:S:s:x:b:nBhf:t:kLqc:"); - while ((c = rz_getopt_next(&opt)) != -1) { - switch (c) { - case 'q': quiet++; break; - case 'i': - iterations = atoi(opt.arg); - if (iterations < 0) { - eprintf("error: -i argument must be positive\n"); - return 1; - } - break; - case 'j': rad = 'j'; break; - case 'S': seed = opt.arg; break; - case 'I': ivseed = opt.arg; break; - case 'n': numblocks = 1; break; - case 'D': decrypt = opt.arg; break; - case 'E': encrypt = opt.arg; break; - case 'L': algolist(); return 0; - case 'e': ule = 1; break; - case 'k': rad = 2; break; - case 'p': ptype = opt.arg; break; - case 'a': algo = opt.arg; break; - case 'B': incremental = false; break; - case 'b': bsize = (int)rz_num_math(NULL, opt.arg); break; - case 'f': from = rz_num_math(NULL, opt.arg); break; - case 't': to = 1 + rz_num_math(NULL, opt.arg); break; - case 'v': return rz_main_version_print("rz-hash"); - case 'h': return do_help(0); - case 's': setHashString(opt.arg, 0); break; - case 'x': setHashString(opt.arg, 1); break; - case 'c': compareStr = opt.arg; break; - default: return do_help(0); + rz_hash_parse_cmdline(argc, argv, &ctx); + + switch (ctx.operation) { + case RZ_HASH_OP_LIST_ALGO: + rz_hash_show_algorithms(); + break; + case RZ_HASH_OP_HASH: + if (!rz_hash_context_run(&ctx, calculate_hash)) { + goto rz_main_rz_hash_end; } - } - if (encrypt && decrypt) { - eprintf("rz-hash: Option -E and -D are incompatible with each other.\n"); - return 1; - } - if (compareStr) { - int compareBin_len; - if (bsize && !incremental) { - eprintf("rz-hash: Option -c incompatible with -b and -B options.\n"); - return 1; + break; + case RZ_HASH_OP_DECRYPT: + if (!rz_hash_context_run(&ctx, calculate_decrypt)) { + goto rz_main_rz_hash_end; } - bool flag = false; - if (encrypt) { - flag = !strcmp(encrypt, "base64") || !strcmp(encrypt, "base91"); - } else if (decrypt) { - flag = !strcmp(decrypt, "base64") || !strcmp(decrypt, "base91"); + break; + case RZ_HASH_OP_ENCRYPT: + if (!rz_hash_context_run(&ctx, calculate_encrypt)) { + goto rz_main_rz_hash_end; } - if (flag) { - eprintf("rz-hash: Option -c incompatible with -E base64, -E base91, -D base64 or -D base91 options.\n"); - return 1; - } - algobit = rz_hash_name_to_bits(algo); - // if algobit represents a single algorithm then it's a power of 2 - if (!is_power_of_two(algobit)) { - eprintf("rz-hash: Option -c incompatible with multiple algorithms in -a.\n"); - return 1; - } - compareBin = malloc((strlen(compareStr) + 1) * 2); - if (!compareBin) { - return 1; - } - compareBin_len = rz_hex_str2bin(compareStr, compareBin); - if (compareBin_len < 1) { - eprintf("rz-hash: Invalid -c hex hash\n"); - free(compareBin); - return 1; - } else if (compareBin_len != rz_hash_size(algobit)) { - eprintf( - "rz-hash: Given -c hash has %d byte(s) but the selected algorithm returns %d byte(s).\n", - compareBin_len, - rz_hash_size(algobit)); - free(compareBin); - return 1; - } - } - if ((st64)from >= 0 && (st64)to < 0) { - to = 0; // end of file - } - if (from || to) { - if (to && from >= to) { - eprintf("Invalid -f or -t offsets\n"); - return 1; - } - } - if (ptype) { - // TODO: support p=%s (horizontal bars) - // TODO: list supported statistical metrics - // TODO: support -f and -t - for (i = opt.ind; i < argc; i++) { - printf("%s:\n", argv[i]); - rz_sys_cmdf("rizin -qfnc \"p==%s 100\" \"%s\"", ptype, argv[i]); - } - return 0; - } - // convert iv to hex or string. - if (ivseed) { - iv = (ut8 *)malloc(strlen(ivseed) + 128); - if (!strncmp(ivseed, "s:", 2)) { - strcpy((char *)iv, ivseed + 2); - ivlen = strlen(ivseed + 2); - } else { - ivlen = rz_hex_str2bin(ivseed, iv); - if (ivlen < 1) { - strcpy((char *)iv, ivseed); - ivlen = strlen(ivseed); - } - } - } - do_hash_seed(seed); - if (hashstr) { -#define INSIZE 32768 - ret = 0; - if (!strcmp(hashstr, "-")) { - hashstr = malloc(INSIZE); - if (!hashstr) { - free(iv); - return 1; - } - bytes_read = fread((void *)hashstr, 1, INSIZE - 1, stdin); - if (bytes_read < 1) { - bytes_read = 0; - } - hashstr[bytes_read] = '\0'; - hashstr_len = bytes_read; - } - if (hashstr_hex) { - ut8 *out = malloc((strlen(hashstr) + 1) * 2); - hashstr_len = rz_hex_str2bin(hashstr, out); - if (hashstr_len < 1) { - eprintf("Invalid hex string\n"); - free(out); - free(iv); - return 1; - } - hashstr = (char *)out; - /* out memleaks here, hashstr can't be freed */ - } else { - if (!bytes_read) { - hashstr_len = strlen(hashstr); - } - } - if (from) { - if (from >= hashstr_len) { - eprintf("Invalid -f.\n"); - free(iv); - return 1; - } - } - if (to) { - if (to > hashstr_len) { - eprintf("Invalid -t.\n"); - return 1; - } - } else { - to = hashstr_len; - } - hashstr = hashstr + from; - hashstr_len = to - from; - hashstr[hashstr_len] = '\0'; - if (!bytes_read && !hashstr_hex) { - hashstr_len = rz_str_unescape(hashstr); - } - if (encrypt) { - return encrypt_or_decrypt(encrypt, 0, hashstr, hashstr_len, iv, ivlen, 0); - } else if (decrypt) { - return encrypt_or_decrypt(decrypt, 1, hashstr, hashstr_len, iv, ivlen, 0); - } else { - char *str = (char *)hashstr; - int strsz = hashstr_len; - if (_s) { - // alloc/concat/resize - str = malloc(strsz + s.len); - if (s.prefix) { - memcpy(str, s.buf, s.len); - memcpy(str + s.len, hashstr, hashstr_len); - } else { - memcpy(str, hashstr, hashstr_len); - memcpy(str + strsz, s.buf, s.len); - } - strsz += s.len; - str[strsz] = 0; - } - algobit = rz_hash_name_to_bits(algo); - if (algobit == 0) { - eprintf("Invalid algorithm. See -E, -D maybe?\n"); - if (str != hashstr) { - free(str); - } - free(iv); - return 1; - } - PJ *pj = NULL; - if (rad == 'j') { - pj = pj_new(); - if (!pj) { - if (str != hashstr) { - free(str); - } - free(iv); - return 1; - } - pj_a(pj); - } - for (i = 1; i < RZ_HASH_ALL; i <<= 1) { - if (algobit & i) { - ut64 hashbit = i & algobit; - ctx = rz_hash_new(true, hashbit); - from = 0; - to = strsz; - do_hash_internal(ctx, hashbit, (const ut8 *)str, strsz, pj, rad, 1, ule); - compare_hashes(ctx, compareBin, rz_hash_size(algobit), &ret); - rz_hash_free(ctx); - } - } - if (rad == 'j') { - pj_end(pj); - printf("%s\n", pj_string(pj)); - pj_free(pj); - } - if (_s) { - if (str != hashstr) { - free(str); - } - free(s.buf); - } - return ret; - } - } - if (opt.ind >= argc) { - free(iv); - return do_help(1); - } - if (numblocks) { - bsize = -bsize; - } else if (bsize < 0) { - eprintf("rz-hash: Invalid block size\n"); - free(iv); - return 1; + break; + case RZ_HASH_OP_VERSION: + rz_main_version_print("rz-hash"); + break; + case RZ_HASH_OP_USAGE: + rz_hash_show_help(true); + goto rz_main_rz_hash_end; + case RZ_HASH_OP_ERROR: + goto rz_main_rz_hash_end; + case RZ_HASH_OP_HELP: + result = 0; + default: + rz_hash_show_help(false); + goto rz_main_rz_hash_end; } - io = rz_io_new(); - for (ret = 0, i = opt.ind; i < argc; i++) { - file = argv[i]; + result = 0; - if (file && !*file) { - eprintf("Cannot open empty path\n"); - return 1; - } - - if (encrypt) { // for encrytion when files are provided - int rt = encrypt_or_decrypt_file(encrypt, 0, argv[i], iv, ivlen, 0); - if (rt == -1) { - continue; - } else { - return rt; - } - } else if (decrypt) { - int rt = encrypt_or_decrypt_file(decrypt, 1, argv[i], iv, ivlen, 0); - if (rt == -1) { - continue; - } else { - return rt; - } - } else { - RzIODesc *desc = NULL; - if (!strcmp(argv[i], "-")) { - int sz = 0; - ut8 *buf = (ut8 *)rz_stdin_slurp(&sz); - char *uri = rz_str_newf("malloc://%d", sz); - if (sz > 0) { - desc = rz_io_open_nomap(io, uri, RZ_PERM_R, 0); - if (!desc) { - eprintf("rz-hash: Cannot open malloc://1024\n"); - free(iv); - return 1; - } - rz_io_pwrite_at(io, 0, buf, sz); - } - free(uri); - free(buf); - } else { - if (rz_file_is_directory(argv[i])) { - eprintf("rz-hash: Cannot hash directories\n"); - free(iv); - return 1; - } - desc = rz_io_open_nomap(io, argv[i], RZ_PERM_R, 0); - if (!desc) { - eprintf("rz-hash: Cannot open '%s'\n", argv[i]); - free(iv); - return 1; - } - } - ret |= do_hash(argv[i], algo, io, bsize, rad, ule, compareBin); - to = 0; - rz_io_desc_close(desc); - } - } - free(hashstr); - rz_io_free(io); - free(iv); - - return ret; +rz_main_rz_hash_end: + rz_hash_context_fini(&ctx); + return result; } diff --git a/librz/util/punycode.c b/librz/util/punycode.c index d32a71c0c5..c7471096b5 100644 --- a/librz/util/punycode.c +++ b/librz/util/punycode.c @@ -65,37 +65,34 @@ ut8 *utf32toutf8(ut32 *input) { return result; } -ut32 *utf8toutf32(const ut8 *input) { +ut32 *utf8toutf32(const ut8 *input, int len) { if (!input) { eprintf("ERROR input is null\n"); return NULL; } - int i = 0; - int j = 0; int val = 0; - int len = strlen((const char *)input); - ut32 *result = calloc(strlen((const char *)input) + 1, 4); + ut32 *result = calloc(len + 1, 4); if (!result) { eprintf("ERROR: out of memory\n"); return NULL; } - while (i < len) { + for (int i = 0, j = 0; i < len; j++) { if (input[i] >> 7 == 0) { val = input[i]; i += 1; - } else if (input[i] >> 5 == 0x6) { + } else if (input[i] >> 5 == 0x6 && (len - i) > 1) { val = (((input[i] & 0x1f) << 6) & 0xfc0) | (input[i + 1] & 0x3f); i += 2; - } else if (input[i] >> 4 == 0xe) { + } else if (input[i] >> 4 == 0xe && (len - i) > 2) { val = (((input[i] & 0xf) << 12) & 0xf000) | (((input[i + 1] & 0x3f) << 6) & 0xffc0) | (input[i + 2] & 0x3f); i += 3; - } else if (input[i] >> 3 == 0x1e) { + } else if (input[i] >> 3 == 0x1e && (len - i) > 3) { val = (((input[i] & 0xf) << 18) & 0x1c0000) | (((input[i + 1] & 0x3f) << 12) & 0x1ff000) | (((input[i + 2] & 0x3f) << 6) & 0x1fffc0) | @@ -107,7 +104,6 @@ ut32 *utf8toutf32(const ut8 *input) { return NULL; } result[j] = val; - j++; } return result; @@ -192,7 +188,7 @@ RZ_API char *rz_punycode_encode(const ut8 *src, int srclen, int *dstlen) { return NULL; } - actualsrc = utf8toutf32(src); + actualsrc = utf8toutf32(src, srclen); if (!actualsrc) { return NULL; } diff --git a/shlr/winkd/iob_net.c b/shlr/winkd/iob_net.c index 83123accee..909a3ff837 100644 --- a/shlr/winkd/iob_net.c +++ b/shlr/winkd/iob_net.c @@ -193,13 +193,12 @@ static bool _encrypt(iobnet_t *obj, ut8 *buf, int size, int type) { } // Overwrite the buffer with encrypted data int sz; - ut8 *encbuf = rz_crypto_get_output(cry, &sz); + const ut8 *encbuf = rz_crypto_get_output(cry, &sz); if (!encbuf) { goto end; } memcpy(buf, encbuf, size - KDNET_HMAC_SIZE); - free(encbuf); ret = true; end: rz_crypto_free(cry); @@ -301,14 +300,13 @@ static bool _decrypt(iobnet_t *obj, ut8 *buf, int size, int type) { } // Overwrite it with decrypted data int sz; - ut8 *decbuf = rz_crypto_get_output(cry, &sz); + const ut8 *decbuf = rz_crypto_get_output(cry, &sz); if (!decbuf) { goto end; } memcpy(buf, decbuf, size - KDNET_HMAC_SIZE); ret = true; - free(decbuf); end: rz_crypto_free(cry); return ret; diff --git a/test/db/cmd/cmd_ph b/test/db/cmd/cmd_ph index 7b7a952be8..1b59dc71f8 100644 --- a/test/db/cmd/cmd_ph +++ b/test/db/cmd/cmd_ph @@ -3,16 +3,16 @@ FILE=bins/elf/analysis/x86-helloworld-gcc CMDS=<Io2Tv!^aB RUN -NAME=rz-hash -D base91 +NAME=rz-hash -qqD base91 FILE== -CMDS=!rz-hash -E base91 -s "hello world" | rz-hash -D base91 -s - +CMDS=!rz-hash -qqE base91 -s "hello world" | rz-hash -qqD base91 -s - EXPECT=hello world RUN -NAME=rz-hash -E rc2 +NAME=rz-hash -qqE rc2 FILE== -CMDS=!rz-hash -E rc2 -S key -s "helloworld123456" | rz-ax -S +CMDS=!rz-hash -qqE rc2 -S s:key -s "helloworld123456" | rz-ax -S EXPECT=<