Использование OpenSSL BN_CTX
Отсюда я понимаю, что BN_CTX - это структура, которая содержит временные переменные BIGNUM. Когда эти переменные BIGNUM войдут в BN_POOL BN_CTX? Если у меня есть bignum_ctx BN_CTX *ctx;
(либо объявлен в верхней части моей функции, либо передан в качестве аргумента), когда я должен сделать
ctx = BN_CTX_new();
/* Do something */
BN_CTX_free(ctx);
и когда я должен сделать следующее вместо этого?
BN_CTX_start(ctx);
/* Do something */
BN_CTX_end(ctx);
И если у меня есть Bignum BIGNUM *bn;
при каких обстоятельствах я должен использовать
BN_CTX_start(ctx);
bn = BN_CTX_get(ctx);
BN_CTX_end(ctx);
а не просто новый и бесплатный экземпляр?
bn = BN_new();
if (bn)
BN_free(bn);
1 ответ
Здесь я отвечаю на свой вопрос. Я думаю, что это происходит все время в SO.
BIGNUM в OpenSSL - это сложная структура, которая содержит произвольно большое число, и, следовательно, многократное создание и освобождение экземпляров BIGNUM приведет к значительным накладным расходам. Контекст BIGNUM, или BN_CTX, создается и используется для сохранения этих издержек.
Состав
Структура BN_CTX содержит две структуры: BN_POOL
а также BN_STACK
, BN_POOL
хранит связку временных бигнумов со связанным списком, а BN_STACK
управляет фреймом стека.
При создании
BN_CTX
пример ctx
создан с BN_CTX_new()
, Функция должна вызывать BN_CTX_start()
чтобы получить новый кадр стека первым. По телефону BN_CTX_get(ctx)
, OpenSSL ищет неиспользованный бигнум в BN_POOL
из ctx
, Если нет доступного временного значения, OpenSSL создаст его и создаст ссылку на связанный список. Это должно быть сделано до прохождения ctx
в качестве аргумента для других функций.
Конечно, есть механизм, предотвращающий создание пользователем слишком большого количества временных номеров. Заранее определенное количество бигнумов, которые вы можете создать в BN_POOL
равно 16. Как только предел превышен, вероятная ошибка сегментации произойдет в случайном месте в библиотеке OpenSSL.
На выходе
После выполнения функции с экземпляром BIGNUM, полученным из ctx
и готов выйти, BN_CTX_end()
вызывается для освобождения временных значений, означающих, что эти значения становятся "неиспользованными" и могут быть запрошены следующим BN_CTX_get()
,
Наконец, вероятно, после нескольких раз BN_CTX_start()
а также BN_CTX_end()
, BN_CTX_end()
призван к свободе BN_STACK
структура, и очистить свободные номера в BN_POOL
,
Пример кода
void foo(){
BN_CTX* ctx;
ctx = BN_CTX_new();
/* Using BIGNUM context in a series of BIGNUM operations */
bar(ctx);
bar(ctx);
bar(ctx);
/* Using BIGNUM context in a function called in loops */
while(/*condition*/){
bar(ctx);
}
BN_CTX_free(ctx);
}
А вот и функция bar( )
void bar(BN_CTX* ctx){
BIGNUM *bn;
BN_CTX_start(ctx);
bn = BN_CTX_get(ctx);
/* Do something with bn */
BN_CTX_end(ctx);
}
Функция foo()
создает новый контекст BIGNUM и передает его в качестве аргумента функции bar()
, По первому разу bar()
звонки BN_CTX_get()
временный бигнум создается и сохраняется в BN_POOL
и возвращается. BN_CTX_get()
в последующем bar()
не будет создавать новый bignum, но вместо этого возвращает тот, который был создан в первую очередь. Этот временный бигнум будет окончательно освобожден BN_CTX_free()
в foo()
,
Заключение
Когда производительность вызывает беспокойство, используйте BN_CTX
чтобы сэкономить на создании BIGNUM, передав его функциям, которые
- требовать, чтобы структуры BIGNUM содержали временные большие числа, и
- вызываются последовательно для выполнения определенных операций bignum, или
- неоднократно называются в циклах.
Имейте в виду, что существует ограничение на количество бигнумов, хранящихся в BN_CTX
, Если производительность не является проблемой, то с помощью
bn = BN_new();
if (bn)
BN_free(bn);
просто отлично.