openSSL:使用压缩的CurvePoint R而不是r

时间:2017-11-06 14:03:56

标签: c openssl ecdsa

我想验证一些包含不是ASN.1 DER编码的ECDSA签名的数据包。

我正在尝试使用openSSL(版本1.1.0)执行任务,因为它似乎带来了所有必需的功能。

目前我无法从数据包导入签名。 签名如下所示:

signature shown in Wireshark

(最后4个字节不应标记为签名的一部分)

TShark展示了相关的部分:

    "gn.sh.sig": {
      "gn.st.pka": "0",
      "gn.st.eccpointtype": "3",
      "gn.st.opaque": "1f:f8:ad:a7:fd:99:b2:a8:a2:69:d4:d6:67:e5:ee:5b:3f:8b:e8:7f:49:fc:b4:79:95:98:15:0d:cb:bd:06:3c",
      "gn.st.opaque": "61:a4:6a:c9:a7:dd:bd:0d:9c:0a:0e:73:db:52:06:bb:79:53:99:51:16:45:45:81:4e:df:94:5c:58:59:40:14"
    }

编码符合ETSI TS 103 097 v1.2.1

第一个条目opaqueECC Point type形成一个名为R的EccPoint,而第二个字段opaque名为s

我的第一步是在openSSL中创建签名并将数据导入其中。

我的代码(删除错误处理以减小大小)如下所示:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/bn.h>

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

void verify_signature(void)
{
  int res;

  // Which value is correct for r-part?
  static const char sig_r_hex[] = "1ff8ada7fd99b2a8a269d4d667e5ee5b3f8be87f49fcb4799598150dcbbd063c";
  static const char sig_s_hex[] = "61a46ac9a7ddbd0d9c0a0e73db5206bb79539951164545814edf945c58594014";

  BN_CTX *bn_ctx = BN_CTX_new();
  BN_CTX_start(bn_ctx);

  // Create signature and import from packet.
  BIGNUM *bn_r = BN_CTX_get(bn_ctx);
  BIGNUM *bn_s = BN_CTX_get(bn_ctx);

  res = BN_hex2bn(&bn_r, sig_r_hex);
  res = BN_hex2bn(&bn_s, sig_s_hex);

  ECDSA_SIG *signature = ECDSA_SIG_new();
  res = ECDSA_SIG_set0(signature, bn_r, bn_s);
  printf("ECDSA_SIG_set0(): %d\n", res);

  // ...
  // Create hash of message and verify signature with public key
  //...
}

int main(int arc, char *argv[])
{ 
  ERR_load_crypto_strings();
  OpenSSL_add_all_algorithms();
  OPENSSL_config(NULL);

  verify_signature();

  EVP_cleanup();
  CRYPTO_cleanup_all_ex_data();
  ERR_free_strings();
  return 0;
}

我目前缺少的是如何正确处理值R。 压缩CurvePoint的哪些部分应该用作r来初始化签名? 我是否需要解压缩y部分? 我是否必须为压缩的y值添加一些指示?

欢迎任何提示。

编辑:

根据我在IEEE1609.2和SEC-1中的内容,可以添加其他信息,以便更快地从R计算r。这可能是点R本身。 如r = xR mod n,应该可以从EccPoint计算r

openSSL是否支持此机制以加快验证速度,或者我是否真的必须删除额外信息(并了解如何执行此操作)才能将r提供给openSSL?

1 个答案:

答案 0 :(得分:0)

4.2.5 - 4.2.8在http://www.etsi.org/deliver/etsi_ts/103000_103099/103097/01.02.01_60/ts_103097v010201p.pdf中,给出以下结构(其中extern表示数据中没有字面表示'):

enum {
     x_coordinate_only(0),
     compressed_lsb_y_0(2),
     compressed_lsb_y_1(3),
     uncompressed(4),
     (2^8-1)
} EccPointType;

struct {
 extern PublicKeyAlgorithm algorithm;
 extern uint8 field_size;
 EccPointType type;
 opaque x[field_size];
 select(type) {
     case x_coordinate_only:
     case compressed_lsb_y_0:
     case compressed_lsb_y_1:
         ;
     case uncompressed:
         opaque y[field_size];
     unknown:
         opaque data<var>;
     }
} EccPoint;

struct {  
    extern PublicKeyAlgorithm algorithm;  
    extern uint8 field_size;  
    EccPoint R;  
    opaque s[field_size]; 
} EcdsaSignature;

struct {
    PublicKeyAlgorithm algorithm;
    select(algorithm) {
        case ecdsa_nistp256_with_sha256:
            EcdsaSignature ecdsa_signature;
        unknown:
            opaque signature<var>;
    }
} Signature;

你知道它是P-256的ECDSA,使用SHA256,而且我们有一个“压缩的y-1”点。让我们首先使用我们所知道的解析这些结构的所有“选择”部分,并消除所有“外部”字段:

struct {
    PublicKeyAlgorithm algorithm; // 1 byte = 0x00 ("ecdsa, P-256, sha256")
    {                             //EcdsaSignature ecdsa_signature
        {                         //EccPoint R
            EccPointType type;        //1 byte = 0x03 ("compressed lsb y-1")
            opaque x[field_size];     //these are the first 32 opaque bytes
            ;                         // select(type) resolves to nothing.
        }  
        opaque s[field_size];     //these are the second 32 opaque bytes
    }
} Signature;

好。那更简单。现在我们知道所有字节是什么。那么关于“压缩点”的所有这些业务是什么?从本质上讲,点压缩实际上是最大限度地减少必须通过网络发送的数据量。事实证明,给定NIST曲线上某点的X坐标,您可以求解Y坐标,但有2个可能的答案。 Certicom的一些聪明的人注意到,与给定X坐标一起使用的两个可能的Y坐标总是在它们的最低有效位中有所不同 - 因此当他们必须发送所有X时,他们只能发送LSb Y(即,足够的信息,以便您知道Y的两个解决方案中的哪一个是正确的)。因此,“压缩lsb y-1”的EccPointType告诉您,对于X坐标,正确的Y坐标是LSb中具有1的坐标。

关于此的最佳消息是您不必关心。 ECDSA仅使用R的X坐标,它位于第一个标记为“x”的不透明斑点中。

所以这是一个冗长的解释,说“你不需要做任何事情。你已经拥有正确的r(= X坐标R)和s来喂养进入OpenSSL的ECDSA_do_verify。