3

OpenSSL を使用して C++ でECDSA公開鍵をインポートしようとしていますが (署名を検証するため)、 d2i_ECPKParametersは NULL を返します。

Web Cryptograph API で生成されたキー。spki形式でエクスポートされた公開鍵(キーをエクスポートするときの ASN.1 構造、および spki の DER エンコーディングについて W3 TR doc が説明しています)。

私は OpenSSL を初めて使用します。何が間違っていましたか?

輸入:

bool ecdsa_verify(
    const std::array<uint8_t, 20>& hash,
    const std::experimental::basic_string_view<uint8_t>& signature,
    const std::experimental::basic_string_view<uint8_t>& public_key) {
  EC_GROUP* ec_group = nullptr;

  const unsigned char* public_key_data = public_key.data();
  ec_group = d2i_ECPKParameters(nullptr, &public_key_data, public_key.length());
  if (ec_group == nullptr) {
    return false; // RETURN POINT
  }

  EC_KEY* ec_key = EC_KEY_new();
  if (ec_key == nullptr) {
    EC_GROUP_free(ec_group);
    return false;
  }

  if (!EC_KEY_set_group(ec_key, ec_group)) {
    EC_GROUP_free(ec_group);
    EC_KEY_free(ec_key);
    return false;
  }

  bool is_signature_valid =
      ECDSA_verify(0, hash.data(), hash.size(), signature.data(),
                   signature.length(), ec_key);

  EC_GROUP_free(ec_group);
  EC_KEY_free(ec_key);

  return is_signature_valid;
}

更新: 他のインポートを試してください (ただし、まだ機能しません):

  const unsigned char* public_key_data = public_key.data();

  EC_KEY* ec_key =
      o2i_ECPublicKey(nullptr, &public_key_data, public_key.length());
  if (ec_key == nullptr) {
    return false; // RETURN POINT
  }

  bool is_signature_valid =
      ECDSA_verify(0, hash.data(), hash.size(), signature.data(),
                   signature.length(), ec_key);

  EC_KEY_free(ec_key);

書き出す:

function ecdsa_export_pub_key(key) {
  return window.crypto.subtle.exportKey(
    "spki",
    key);
}

更新 2:

(JS でエクスポートされたキーから) PEM キーを生成しましたが、基本的には PEM キーを使用しません。JavaScript で公開鍵をエクスポートした後、ArrayBuffer から新しい Uint8Array を作成し、それを WebSocket (バイナリ フレーム) 経由でサーバーに送信し、解析を試みます。受信した uint8_t 配列は常に 158 バイト長です。私は P-521 -- secp521r1 を使用しています。

pkcs8でエクスポートされた秘密鍵!

-----BEGIN PRIVATE KEY-----
 MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIApK1m/qpIAZ1iENht
 XJxng4bdur6YV2SpMs+uFtSiJ/n96HbjVkqSENavv7vblIow+i5QUhaOkqSNWi0B
 7x695C6hgYkDgYYABAATsbs5B+ebSwoIXD6RD2NYONzSWOtt0SigPM27pdYEWpld
 /6j6S34gvRHQwDSMzs6//1zVE20Mn+izNM0KPWhRewD6SotR8/2QGWB5uo8GiXx1
 RLyBp+TOurQLEsYwiWSLkUIUMvPH/6WCxSNO4FzBf617PRqs7Zv3Vo98d9JH/3mI
 TA==
 -----END PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
 MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAE7G7OQfnm0sKCFw+kQ9jWDjc0ljr
 bdEooDzNu6XWBFqZXf+o+kt+IL0R0MA0jM7Ov/9c1RNtDJ/oszTNCj1oUXsA+kqL
 UfP9kBlgebqPBol8dUS8gafkzrq0CxLGMIlki5FCFDLzx/+lgsUjTuBcwX+tez0a
 rO2b91aPfHfSR/95iEw=
 -----END PUBLIC KEY-----

詳細:

% openssl asn1parse -inform PEM -in pub.pem 
    0:d=0  hl=3 l= 155 cons: SEQUENCE          
    3:d=1  hl=2 l=  16 cons: SEQUENCE          
    5:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   14:d=2  hl=2 l=   5 prim: OBJECT            :secp521r1
   21:d=1  hl=3 l= 134 prim: BIT STRING        
% openssl asn1parse -inform PEM -in priv.pem
    0:d=0  hl=3 l= 238 cons: SEQUENCE          
    3:d=1  hl=2 l=   1 prim: INTEGER           :00
    6:d=1  hl=2 l=  16 cons: SEQUENCE          
    8:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   17:d=2  hl=2 l=   5 prim: OBJECT            :secp521r1
   24:d=1  hl=3 l= 214 prim: OCTET STRING      [HEX DUMP]:3081D3020101044200A4AD66FEAA48019D6210D86D5C9C678386DDBABE985764A932CFAE16D4A227F9FDE876E3564A9210D6AFBFBBDB948A30FA2E5052168E92A48D5A2D01EF1EBDE42EA1818903818600040013B1BB3907E79B4B0A085C3E910F635838DCD258EB6DD128A03CCDBBA5D6045A995DFFA8FA4B7E20BD11D0C0348CCECEBFFF5CD5136D0C9FE8B334CD0A3D68517B00FA4A8B51F3FD90196079BA8F06897C7544BC81A7E4CEBAB40B12C63089648B91421432F3C7FFA582C5234EE05CC17FAD7B3D1AACED9BF7568F7C77D247FF79884C

o2i_ECPublicKey 呼び出し時のエラー コード:

(同じデータで呼び出しますが、エラーは毎回異なります。とにかく繰り返されます。)

error:10067066:elliptic curve routines:ec_GFp_simple_oct2point:invalid
error:10098010:elliptic curve routines:o2i_ECPublicKey:EC lib
error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long
error:10067066:elliptic curve routines:ec_GFp_simple_oct2point:invalid
error:10098010:elliptic curve routines:o2i_ECPublicKey:EC lib

更新 3:

C++ から、受信したデータ (キー) をファイルに書き出しました。

% % openssl asn1parse -inform DER -in data.bin 
    0:d=0  hl=3 l= 155 cons: SEQUENCE          
    3:d=1  hl=2 l=  16 cons: SEQUENCE          
    5:d=2  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
   14:d=2  hl=2 l=   5 prim: OBJECT            :secp521r1
   21:d=1  hl=3 l= 134 prim: BIT STRING
% 
% hexdump data.bin                          
0000000 8130 309b 0610 2a07 4886 3dce 0102 0506
0000010 812b 0004 0323 8681 0400 1300 bbb1 0739
0000020 9be7 0a4b 5c08 913e 630f 3858 d2dc eb58
0000030 d16d a028 cd3c a5bb 04d6 995a ff5d faa8
0000040 7e4b bd20 d011 34c0 ce8c bfce 5cff 13d5
0000050 0c6d e89f 34b3 0acd 683d 7b51 fa00 8b4a
0000060 f351 90fd 6019 ba79 068f 7c89 4475 81bc
0000070 e4a7 bace 0bb4 c612 8930 8b64 4291 3214
0000080 c7f3 a5ff c582 4e23 5ce0 7fc1 7bad 1a3d
0000090 edac f79b 8f56 777c 47d2 79ff 4c88     
000009

16 進数でエンコードされたエクスポートされた SPKI (WebCrypto エクスポートの結果):

プライベート:

MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIApK1m/qpIAZ1iENhtXJxng4bdur6YV2SpMs+uFtSiJ/n96HbjVkqSENavv7vblIow+i5QUhaOkqSNWi0B7x695C6hgYkDgYYABAATsbs5B+ebSwoIXD6RD2NYONzSWOtt0SigPM27pdYEWpld/6j6S34gvRHQwDSMzs6//1zVE20Mn+izNM0KPWhRewD6SotR8/2QGWB5uo8GiXx1RLyBp+TOurQLEsYwiWSLkUIUMvPH/6WCxSNO4FzBf617PRqs7Zv3Vo98d9JH/3mITA==

公衆:

MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAE7G7OQfnm0sKCFw+kQ9jWDjc0ljrbdEooDzNu6XWBFqZXf+o+kt+IL0R0MA0jM7Ov/9c1RNtDJ/oszTNCj1oUXsA+kqLUfP9kBlgebqPBol8dUS8gafkzrq0CxLGMIlki5FCFDLzx/+lgsUjTuBcwX+tez0arO2b91aPfHfSR/95iEw=

更新 4:

秘密鍵の jwk 形式:

{
  "crv":"P-521",
  "d":"AKStZv6qSAGdYhDYbVycZ4OG3bq-mFdkqTLPrhbUoif5_eh241ZKkhDWr7-725SKMPouUFIWjpKkjVotAe8eveQu",
  "ext":true,
  "key_ops":["sign"],
  "kty":"EC",
  "x":"ABOxuzkH55tLCghcPpEPY1g43NJY623RKKA8zbul1gRamV3_qPpLfiC9EdDANIzOzr__XNUTbQyf6LM0zQo9aFF7",
  "y":"APpKi1Hz_ZAZYHm6jwaJfHVEvIGn5M66tAsSxjCJZIuRQhQy88f_pYLFI07gXMF_rXs9Gqztm_dWj3x30kf_eYhM"
}
4

2 に答える 2

3

... エクスポートされた公開鍵は spki 形式です ...

エンコードされたキーは、ASN.1 を使用して大まかに次のように構成されます。厳しい詳細については、RFC 5480 のセクション 2. サブジェクトの公開鍵情報フィールドRFC 3279 のセクション 2.3.5 ECDSA および ECDH キーを参照してください。

SEQUENCE {
   ALGORITHM ID
   KEY {
      NAMED_CURVE or DOMAIN_PARAMETERS
      PUBLIC_KEY or PRIVATE_KEY  
   }
}

外部シーケンスとアルゴリズム識別子のない鍵素材である「生の鍵」もあります。OpenSSL は、 man ページで「生の鍵」を従来の鍵と呼んでいます。


d2i_ECPKParameters は NULL を返します...

OK、ドメイン パラメータだけでなく、SPKI があります。ドメイン パラメーターは、曲線係数 ( aおよびb )、係数 ( p )、基点 ( G ) などであり、曲線を記述します。彼らは鍵を持っていません。

d2i_PublicKeyそのため、キーを に解析し、キーをEVP_KEYロードした後にドメイン パラメータをフェッチするようなものを使用する必要があります。


私が見た相互運用性の最大の問題は次のとおりです。

NAMED_CURVE or DOMAIN_PARAMETERS

名前付き曲線の場合は、secp256またはprime256v1のようなものになります。そのドメイン パラメータの場合、名前付き曲線は「巻き戻された」または「完全に展開された」ものであり、曲線係数 ( aおよびb )、係数 ( p )、基点 ( G ) などになります。まったく同じことですが、実際には多くの問題を引き起こします。

名前付き曲線とドメイン パラメーター間の相互運用は、OpenSSL に関する wiki ページを作成するほど多くの問題を引き起こします。カーブという名前。実際、ばかげているため、OpenSSL Web サーバーはそれ自体で適切に実行できません。

したがって、ここで言えることは、何を持っているかを認識し、ソフトウェアで名前付き曲線とドメイン パラメータがまったく同じであっても (プレゼンテーションの詳細を除いて) 等しいとは思わないことです。


いくつかのテスト キーを提供していただければ、詳細を提供できる可能性があります。私の推測では、PEM でエンコードされたキーがあるため、 PEM_read_PUBKEYなどの他の関数を使用する必要があります。しかし、それは推測にすぎません。

于 2015-11-12T03:53:36.190 に答える