从here我知道BN_CTX是一个保存BIGNUM临时变量的结构。那些BIGNUM变量何时进入BN_CTX的BN_POOL?如果我有一个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);
答案 0 :(得分:17)
我在这里回答我自己的问题。我想它总是在SO中发生。
OpenSSL中的BIGNUM是一个复杂的结构,它拥有一个任意大的数字,因此重复创建和释放BIGNUM实例将导致相当大的开销。创建BIGNUM上下文或BN_CTX并用于节省此开销。
<强>结构强>
BN_CTX结构包含两个结构:BN_POOL
和BN_STACK
。 BN_POOL
使用链表保留一组临时bignums,而BN_STACK
管理堆栈帧。
创建
使用BN_CTX
创建ctx
实例BN_CTX_new()
。函数必须先调用BN_CTX_start()
才能获得新的堆栈帧。通过调用BN_CTX_get(ctx)
,OpenSSL会在BN_POOL
ctx
中查找未使用的bignum。如果没有任何可用的临时值,OpenSSL将创建一个并链接到链表。必须在将ctx
作为参数传递给其他函数之前完成此操作。
当然,有一种机制可以阻止用户创建过多的临时bignums。您可以在BN_POOL
内创建的预定义数量的bignums为16.一旦超出限制,OpenSSL库中的随机位置就会发生可能的分段错误。
退出
使用BIGNUM实例完成函数后,它从ctx
获得并准备退出,调用BN_CTX_end()
以释放临时bignums,这意味着这些bignums变为“未使用”并且可以被请求到下一个BN_CTX_get()
。
最后,可能在多次BN_CTX_start()
和BN_CTX_end()
后,BN_CTX_end()
被调用以释放BN_STACK
结构,并清除BN_POOL
中的免费bignums。< / p>
示例代码
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()
时,会创建临时bignum并将其存储在BN_POOL
中并返回。后续BN_CTX_get()
中的bar()
不会创建新的bignum,而是返回它首先创建的那个。 BN_CTX_free()
foo()
中的BN_CTX
最终会清除这个临时的bignum。
<强>结论强>
当关注性能时,使用BN_CTX
通过将BIGNUM创建的开销传递给
请注意bn = BN_new();
if (bn)
BN_free(bn);
中存储的bignum数量有限制。如果性能不是问题,那么使用
{{1}}
很好。