13

这里我了解到 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);
4

1 回答 1

24

在这里,我正在回答我自己的问题。我想它一直在 SO 中发生。

OpenSSL 中的 BIGNUM 是一个复杂的结构,包含一个任意大的数字,因此重复创建和释放 BIGNUM 实例将导致相当大的开销。创建并使用 BIGNUM 上下文或 BN_CTX 来节省此开销。

结构

BN_CTX 结构包含两个结构:BN_POOLBN_STACK。使用BN_POOL链表保留一捆临时 bignum,而BN_STACK管理堆栈帧。

创建时

使用 . 创建一个BN_CTX实例。函数必须首先调用以获取新的堆栈帧。通过调用,OpenSSL 在中查找未使用的 bignum 。如果没有任何可用的临时 bignum,OpenSSL 将创建一个并链接到链表。这必须在作为参数传递给其他函数之前完成。ctxBN_CTX_new()BN_CTX_start()BN_CTX_get(ctx)BN_POOLctxctx

当然,有一种机制可以防止用户创建过多的临时 bignums。您可以在 a 中创建的预定义 bignum 数量BN_POOL为 16。一旦超过限制,可能会在 OpenSSL 库中的随机位置发生分段错误。

退出时

ctx在函数处理完它从中获取并准备退出 的 BIGNUM 实例后,BN_CTX_end()将调用以释放临时 bignum,这意味着这些 bignum 变为“未使用”并且可以由 next 请求BN_CTX_get()

最后,大概在几次BN_CTX_start()and之后BN_CTX_end()BN_CTX_end()调用freeBN_STACK结构,并清除free bignums 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 上下文并将其作为参数传递给 function bar()。在第一次bar()调用时BN_CTX_get(),会创建一个临时的 bignum 并将其存储在BN_POOL并返回。BN_CTX_get()随后bar()将不会创建新的 bignum 而是返回它首先创建的那个。这个临时的 bignum 最终会被BN_CTX_free()in清除foo()

结论

当关注性能时,BN_CTX通过将 BIGNUM 创建传递给函数来节省开销

  1. 需要 BIGNUM 结构来保存临时大数字,并且
  2. 被顺序调用以执行某些 bignum 操作,或
  3. 在循环中被重复调用。

请注意,存储在BN_CTX. 如果性能不是问题,则使用

bn = BN_new();
if (bn)
    BN_free(bn);

很好。

于 2013-05-16T03:56:14.310 回答