С RSA_generate_key
обеспечивает обратный вызов прогресса, вы можете отключить функцию longjmp
. С небольшим количеством дополнительного кода вы можете создать обертку для RSA_generate_key
, которая принимает общую тестовую функцию, которая может использоваться для проверки тайм-аута или флага, установленного системой окон.
#include <openssl/rsa.h>
#include <stdbool.h>
#include <setjmp.h>
struct trampoline_ctx {
bool (*testfn)(void *);
void *testfn_arg;
jmp_buf env;
};
static void trampoline(int ignore1, int ignore2, void *arg)
{
struct trampoline_ctx *ctx = arg;
if (!ctx->testfn(ctx->testfn_arg))
longjmp(ctx->env, 1);
}
// like RSA_generate_key, but accepts a test function. If testfn returns
// false, key generation is terminated and NULL is returned.
RSA *
my_generate_key(int num, unsigned long e,
bool (*testfn)(void *), void *testfn_arg)
{
struct trampoline_ctx ctx;
ctx.testfn = testfn;
ctx.testfn_arg = testfn_arg;
if (setjmp(ctx.env))
return NULL;
return RSA_generate_key(num, e, trampoline, &ctx);
}
Этот подход является удивительно портативным, поскольку longjmp
уполномочена как C89 и C99. Недостаток заключается в том, что он может утечка ресурсов, если функция, которую вы не используете, динамически распределяет. Однако на практике утечка может быть достаточно маленькой, чтобы быть незамеченной, если она выполняется нечасто или только по явному запросу пользователя. Чтобы быть уверенным, что это так, запустите код в узком цикле и понаблюдайте за потреблением ресурсов в процессе.
Вот тестовая программа для вышеупомянутой функции:
#include <stdio.h>
#include <sys/time.h>
double now()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + (double) tv.tv_usec/1e6;
}
struct tt_ctx {
double start;
double limit;
};
bool test_time_limit(void *arg)
{
struct tt_ctx *ctx = arg;
return now() - ctx->start <= ctx->limit;
}
int main(int argc, char **argv)
{
int limit = atoi(argv[1]);
struct tt_ctx ctx;
ctx.start = now();
ctx.limit = limit/1000.0;
RSA *key = my_generate_key(4096, 65537, test_time_limit, &ctx);
printf("%p\n", key);
return 0;
}
Тестовая программа предполагает POSIX gettimeofday
, но может быть тривиальным образом преобразованы в другой с высокой разрешающей способностью часов, как это предусмотрено в системе. Процедура испытания следующая:
Добавить оба фрагмента кода в файл и скомпилировать с помощью -lrsa
.В тестовой программе будет генерироваться 4096-битный RSA-ключ в течение времени, указанного в миллисекундах в командной строке. Во всех случаях он печатает полученный указатель RSA *
, чтобы указать, завершил ли запрос my_generate_key
или был прерван. Выход time
сопровождает исполнение в качестве проверки вменяемости, чтобы убедиться, что ограничение по времени соблюдается:
# try with a 10ms limit
$ time ./a.out 10
(nil) # too short
./a.out 10 0.02s user 0.00s system 85% cpu 0.023 total
# see if 100ms is enough time
$ time ./a.out 100
(nil) # still too short
./a.out 100 0.10s user 0.00s system 97% cpu 0.106 total
# try with 1 whole second:
$ time ./a.out 1000
0x2369010 # success!
./a.out 1000 0.64s user 0.00s system 99% cpu 0.649 total
Из всех ответов здесь это, наверное, самый умный. Поэтому я собираюсь присудить награду за ваш ответ. –
Блестящий ответ и прекрасно продуманный. :) –
Codelite всегда говорит: устарело ... – delive