5

我想在使用 EC 密钥对数据进行签名期间提供 OpenSSL 特定数据以用作随机种子。我这样做是为了将我的应用程序与另一个参考应用程序(封闭源代码)进行比较。该实用程序将带有私钥的文件、带有要签名的数据的文件和带有随机数据的文件作为参数。

我已经生成了 EC 密钥,并签署了数据,但由于我没有共同点,因此无法比较这两个应用程序。OpenSSL 生成用于对数据进行签名的随机数据(可能来自 /dev/random),因此每次运行都会给我一个不同的签名。

我已尝试RAND_clear()与 结合使用RAND_add(),但不断更改签名。要么我不理解整个 ECDSA 概念,要么我做错了什么。

我比较应用程序的第二个选项是导入公钥并验证参考程序生成的签名。这是更好的选择,但我无法导入给定的示例公钥(83 个字符的十六进制字符串)。EC_POINT_oct2point()一直给我空结果。

任何帮助/指针/参考将不胜感激。

char * key_as_binary_data;  //369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702
int data_size;  //Size of the key buffer
EC_POINT * ecpoint = NULL;
EC_GROUP * ecgroup = NULL;
EC_KEY * eckey = NULL;
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
int asn1_flag = OPENSSL_EC_NAMED_CURVE;

eckey = EC_KEY_new();
ecpoint = EC_POINT_new(ecgroup);
ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1"));
EC_GROUP_set_asn1_flag(ecgroup, asn1_flag);
EC_GROUP_set_point_conversion_form(ecgroup, form);
EC_KEY_set_group(eckey,ecgroup);
EC_KEY_generate_key(eckey);

//This gives me a null ecpoint
EC_POINT_oct2point(ecgroup,ecpoint,key_as_binary_data,data_size-1,ctx); 
EC_KEY_set_public_key(eckey,ecpoint);
4

5 回答 5

3

这就是您应该如何加载该公钥:

  EC_KEY    *key = NULL;
  EC_POINT *pub_key;
  const EC_GROUP *group;

  SSL_library_init();
  SSL_load_error_strings();

  key = EC_KEY_new_by_curve_name(NID_sect163k1);
  group = EC_KEY_get0_group(key);
  pub_key = EC_POINT_new(group);

  EC_POINT_hex2point(group,
    "369368AF243193D001E39CE76BB1D5DA08A9BC0A63307AB352338E5EA5C0E05A0C2531866F3E3C2702", pub_key, NULL);

  EC_KEY_set_public_key(key, pub_key);

  if (!EC_KEY_check_key(key)) {
    printf("EC_KEY_check_key failed:\n");
    printf("%s\n",ERR_error_string(ERR_get_error(),NULL));
  } else {
    printf("Public key verified OK\n");
  }

它似乎可以验证,所以它应该可以用于检查签名。

我认为您的错误可能只是将 NULL(在 ecgroup 中)传递给 EC_POINT_new()。

于 2009-07-23T15:20:24.743 回答
2

尽管您正在清除池并重置它,但您得到不同结果的原因是默认情况下 OpenSSL 的 RAND 实现会将 pid 散列到输出块中(正是为了确保即使使用相同种子的应用程序也不会得到相同的PRNG 输出,因为 99.9% 的时间发生的都是坏事)。

此外,即使不是这种情况,您的参考应用程序也不太可能使用 OpenSSL 用于将种子文件转换为一系列随机字节的相同 PRNG。(当然,除非您的参考应用程序实际上也使用 OpenSSL)。您要做的是首先弄清楚参考应用程序使用哪种 PRNG - 这可能是标准 PRNG 设计,如 X9.31 或 FIPS-186 中的那些,或者可能是完全自定义的。然后为 OpenSSL 重新实现该设计并通过RAND_set_rand_method.

至于验证:看起来您需要转置以下行:

   ecpoint = EC_POINT_new(ecgroup);
   ecgroup = EC_GROUP_new_by_curve_name(OBJ_sn2nid("sect163k1"));

否则 ecpoint 从一开始就设置为 NULL,这会导致EC_KEY_generate_key失败,因为组设置为 NULL。引用 openssl-0.9.8k 的 crypto/ec/ec_key.c :

if (!eckey || !eckey->group)
   {
   ECerr(EC_F_EC_KEY_GENERATE_KEY, ERR_R_PASSED_NULL_PARAMETER);
   return 0;
   }
于 2009-08-07T15:34:26.563 回答
2

您可以使用以下方法控制 OpenSSL 在签名过程中产生的随机数据:

ECDSA_SIG* ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey);

其中kinv是签名期间使用的随机数。

于 2015-10-13T06:20:24.707 回答
0

签名程序纯粹是为了让其他人确认您已签名,即。是您的私钥用于签署消息(或任何数据),而实际上没有您的私钥。

该算法在维基百科Elliptic_Curve_DSA上进行了概述, 阅读“签名生成算法”时,似乎随机数据用于帮助增强签名的强度,并使攻击更难找出私钥。

因此,您应该期望签名每次都不同,因为这不仅仅是一个散列。

请参阅“签名验证算法”部分以查看验证步骤是您希望用来确认您的 openssl 版本正在输出有效签名 wrt ECDSA 方法和封闭源程序的步骤。

于 2009-07-23T12:10:35.090 回答
0

我找不到 的文档RAND_clear,因此无法评论为什么它不会产生可重现的随机数。

但即使你做到了,你想要的也可能是不可能的。ECDSA 签名生成需要在特定范围内选择一个随机整数。该算法的两种不同实现可能对如何从它们的熵源生成这样的整数有完全不同的想法。AFAIK 将熵位转换为所需数字的方法不是 ECDSA 算法的一部分。

例如(当然是非常糟糕的例子),一种实现可能会这样做:

int random_number = rand() % n;

另一个可能会这样做:

int random_number = (rand() * n) / RAND_MAX;

所以即使你给他们相同的种子数据,你仍然可能从不同的实现中得到不同的签名。您所能做的就是验证您是否生成了有效的签名。

于 2009-07-23T13:17:56.390 回答