8

次の呼び出しについて考えてみますRSA_generate_key()

RSA * rsa = RSA_generate_key(8192, RSA_F4, NULL, NULL);

8,192ビットのRSAキーの生成には、長い時間がかかる場合があります(数秒から数分まで)。上記のコード行を含むアプリケーションが、キーの生成をキャンセルするボタンをユーザーに提供するとします。

キーが生成される前に、計算を中止して関数を返すにはどうすればよいですか?の3番目の引数は、進行状況を表示するために使用されるコールバック関数であることを覚えていRSA_generate_key()ます。コールバックが「操作を中止して戻る」という意味の値を返す方法はありますか?

別のスレッドで関数を実行してからスレッドを終了することはできません。

4

6 に答える 6

7

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;
}

テストプログラムはPOSIXgettimeofdayを想定していますが、システムが提供する別の高解像度クロックに簡単に変換できます。テスト手順は次のとおりです。

両方のコードをファイルに追加し、でコンパイルし-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
于 2013-04-04T21:59:58.383 に答える
2

進行状況コールバックを使用して関数をキャンセルすることはできません。これは、純粋に進行状況をユーザーに表示するためのものです。(詳細はこちら

RSA_generate_key()バックグラウンドで実行されるように呼び出すスレッドを生成します。ユーザーがキャンセルボタンを押したら、スレッドを強制終了します。

于 2013-03-03T06:39:03.350 に答える
2

問題は、コールバックは通常、情報を送信する機能を提供せず、情報受信するだけであるということだと思います。他のポスターのいくつかが言及しているように、実際のキー生成ルーチンのソースコードを変更し、独自のバージョンをコンパイルすることを検討するかもしれません。この場合、参照によってある種の値を呼び出し元のルーチンに戻し、それを外部に設定して、失敗条件をトリガーすることができます。

RSA_generate_key実際には非推奨であり、現在は単なるラッパーになっていRSA_generate_key_exます。

ファイルのバージョン1.19.4.2によるとrsa_gen.c、にいない限りFIPS_mode、キーは静的メソッドによって生成されますrsa_builtin_keygen。では、に入るとFIPS_mode何でも生成されます。rsa->meth->rsa_keygenRSA_generate_key

とは言うものの、コールバック(パラメーター)が他のメソッドに渡される場所はたくさんありますcb。おそらく、それらのメソッドがそれを呼び出してステータスを更新できるようにするためです。

トリックはBN_GENCB、ある種の「キャンセル」フラグを含むように更新するか、メソッド内でコールバックが実際に呼び出される方法を変更して、コールバックメソッドが起動したときにフラグを設定できるようにすることです。関数は、生成サブルーチンから抜け出すことによって尊重します。

それをどのように進めるかは、まだ理解して解決する必要があるものですが、うまくいけば、これはあなたに少しのスタートを与えるでしょう。

于 2013-04-04T19:34:57.750 に答える
1

私はそのような状況に直面したことはなく、以前は何もしませんでしたが。OpenSSLのソースコードを変更できる場合は、次のことを試すことができます。

変数Vが2つの関数間で共有されているとしましょう。したがって、これはファイル内のグローバル変数または静的変数であり、RSA_generate_keyによって使用されており、別の関数RSA_set_Vと言います。

RSA_generate_keyは変数のみを読み取ります。RSA_set_Vは変数を設定します。

RSA_generate_keyでは、時間のかかるループで、この変数をチェックする追加の条件が使用される場合があります。このループを終了するか、Vの特定の値で関数を終了する場合があります。

  while (V!=CERTAIN_VALUE && Rest_of_Condition) {
      //Loop body.
  }

ここで、RSA_set_Vで、VをCERTAIN_VALUEに設定します。ユーザーが[停止]をクリックしたら、RSA_set_Vを呼び出します。RSA_generate_keyを停止する必要があります。

ただし、問題はほとんどありません。RSA_generate_keyの速度が低下する可能性があります。

于 2013-03-30T03:53:30.433 に答える
0

ソースコードによると、opensslのコードを変更しないと、RSA_generate_keyメソッドを中断して返すことはできません。

私はこれを行うために2つの方法を考えました:

  1. メソッドをバックグラウンドスレッドで実行し、ユーザーがキャンセルボタンを押したときに、メソッドを実行してバックグラウンドで終了させます。その後、スレッドを終了させます。結果を無視します。ユーザーが別の世代を要求した場合は、新しいスレッドを開始します。

  2. もう1つは、サブプロセスを開始してキーを生成することです。RSA構造には、多くのBIGNUMメンバーが含まれています。これは、一部のint / ulongの構造でもあり、サブプロセスでキーが生成された後、これらの関連メンバーを親プロセスにコピーして戻します。ユーザーがキャンセルボタンを押した場合、サブプロセスを強制終了しても安全です。しかし、これらのint/longをコピーするだけでセナリオに十分かどうかはわかりません。

于 2013-04-02T15:09:32.770 に答える
0

スレッドを終了したくない場合は、代わりに新しいプロセスをフォークして、ユーザーが中止した場合にそれを終了できますか?

于 2013-04-04T18:24:20.810 に答える