web-dev-qa-db-ja.com

ECキーペアのサイズが間違っています

OpenSSLを使用してECキーペアを生成しています。 OpenSSLで表示されるキーの長さが、プライベートキーとパブリックキーの両方で予想よりも1バイト長いことに気づきました。

00(秘密鍵の最初のバイト)はASN.1でエンコードされた整数であり、値が負でない値として解釈され、公開鍵の最初のバイトが04は非圧縮キー用です。

秘密鍵は33バイト(32バイトではない)であり、公開鍵は65バイト(64バイトではない)です。

秘密鍵:(256ビット)

priv:

  00:b5:15:94:05:96:a0:6b:03:4e:9d:49:01:ce:50:
  71:f7:6a:fe:28:24:2a:24:23:b2:0e:d6:a0:b5:6a:
  0f:65:d3

パブ:

  04:db:b4:97:f3:5d:17:45:e5:79:4f:db:c2:bd:ea:
  19:2c:fd:3a:dc:bc:19:49:91:e1:e1:59:9f:0c:7a:
  9e:e7:97:c1:ad:4c:a8:53:b6:b0:af:d8:7e:58:34:
  90:e1:d1:0b:85:9d:89:e1:4c:7c:b8:b6:2d:27:70:
  62:66:9e:b2:ac

ASN1 OID:prime256v1

NISTカーブ:P-256

秘密鍵と公開鍵の最初のバイトを削除するにはどうすればよいですか?または、プライベートのサイズを32バイトに、パブリックキーのサイズを64バイトに調整するにはどうすればよいですか。

先頭の00は数値の値を変更しますか?

OpenSSL 1.0.2kを使用しています2017年1月26日

3
Med

バイトを切り捨てる理由がわかりません。ですから、これがあなたの質問に対する良い答えであるかどうかはわかりませんが、とにかく行くでしょう。

RFCs /実験を読んで私が見つけたものは次のとおりです。

How can I adjust the size of the private to 32 Bytes and public key to 64 Bytes?

する必要はありません。彼らはすでにその形になっています。 opensslのプリントアウトから読み取るのは少し混乱します。

Does the leading 00 change the value of the number?

いずれにしても、それをunsigned intとして解析する場合、答えは「いいえ」です。 (そして、それを(誤って)署名されたintとして解析しようとした場合は「はい」。その場合、0x00プレフィックスを保持する必要があります。)

[〜#〜] tldr [〜#〜]:先行する0x00は、opensslが出力のみに追加するSIGN BYTEです。証明書自体にはエンコードされません。そして、私はあなたがpubkeyの先頭バイト( x02、0x03または0x04 のいずれか)をカットできると思います。

先頭にnullバイトがあるサンプルキー

これが私が生成したランダムキーの例です:

$ cat leading-nullbyte.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIN/37NFyCvL7brp4zljP83sNj1PvtFsp8dMR86EDwLZUoAoGCCqGSM49
AwEHoUQDQgAEK0acP7Ml6fgKy35YE7JGVP7AmNy7oJ6gl4QIqiwiSExbr4iDPfxT
81550HxXoiQiBJXBJxhgXYpIcJVmFGk20w==
-----END EC PRIVATE KEY-----

ecプリントアウトleading-nullbyte.pem

この鍵は、秘密鍵の接頭部「00:」で示されています。

少なくともopenssl prettyプリンタを使用している場合...

$ openssl ec -noout -text -in leading-nullbyte.pem
read EC key
Private-Key: (256 bit)
priv:
    00:df:f7:ec:d1:72:0a:f2:fb:6e:ba:78:ce:58:cf:
    f3:7b:0d:8f:53:ef:b4:5b:29:f1:d3:11:f3:a1:03:
    c0:b6:54
pub:
    04:2b:46:9c:3f:b3:25:e9:f8:0a:cb:7e:58:13:b2:
    46:54:fe:c0:98:dc:bb:a0:9e:a0:97:84:08:aa:2c:
    22:48:4c:5b:af:88:83:3d:fc:53:f3:5e:79:d0:7c:
    57:a2:24:22:04:95:c1:27:18:60:5d:8a:48:70:95:
    66:14:69:36:d3
ASN1 OID: prime256v1
NIST CURVE: P-256

asn1parse Leading-nullbyte.pem

...ただし、実際にASN1エンコーディングの内部を見る場合、00:プレフィックスはありません。すぐにdf:で始まります。また、長さは32(l= 32)として指定されます。 33ではない。

    5:d=1  hl=2 l=  32 prim:  OCTET STRING
      0000 - df f7 ec d1 72 0a f2 fb-6e ba 78 ce 58 cf f3 7b   ....r...n.x.X..{

コンテキスト内の行は次のとおりです。

$ openssl asn1parse -i -dump -in leading-nullbyte.pem
    0:d=0  hl=2 l= 119 cons: SEQUENCE
    2:d=1  hl=2 l=   1 prim:  INTEGER           :01
    5:d=1  hl=2 l=  32 prim:  OCTET STRING
      0000 - df f7 ec d1 72 0a f2 fb-6e ba 78 ce 58 cf f3 7b   ....r...n.x.X..{
      0010 - 0d 8f 53 ef b4 5b 29 f1-d3 11 f3 a1 03 c0 b6 54   ..S..[)........T
   39:d=1  hl=2 l=  10 cons:  cont [ 0 ]
   41:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   51:d=1  hl=2 l=  68 cons:  cont [ 1 ]
   53:d=2  hl=2 l=  66 prim:   BIT STRING
      0000 - 00 04 2b 46 9c 3f b3 25-e9 f8 0a cb 7e 58 13 b2   ..+F.?.%....~X..
      0010 - 46 54 fe c0 98 dc bb a0-9e a0 97 84 08 aa 2c 22   FT............,"
      0020 - 48 4c 5b af 88 83 3d fc-53 f3 5e 79 d0 7c 57 a2   HL[...=.S.^y.|W.
      0030 - 24 22 04 95 c1 27 18 60-5d 8a 48 70 95 66 14 69   $"...'.`].Hp.f.i
      0040 - 36 d3                                             6.

したがって、先頭の0x00は実際には証明書ファイルにエンコードされていません。それに関してopensslのソースコードを調べたことはありませんが、これを印刷出力のバグと呼んでいます。

RFC5915 (私はそう思う)によれば、ECキーはUNSIGNED整数です。

先頭のnullバイトなしのサンプルキー

これが私が生成した別のランダムキーです。 openssl ec prettyプリンターを使用する場合、0x00プレフィックスはありません。

そのため、これは、0x00プレフィックスが必ずしも各ECプライベートキーに存在するとは限らないことを示しています。

$ cat no-leading-nullbyte.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIAGcFoPfqfFZ5TDv71ZBBCctapiVKwZikE8HfKf61V1DoAoGCCqGSM49
AwEHoUQDQgAENPjKv9vobJnz1FSlSu5cNPyPwCvcsMmIr5HH92C+mZdVtanHwlTm
29IwOE5lSE8KMywIJs8pLCvX79kJhZ/upg==
-----END EC PRIVATE KEY-----

ecプリントアウトno-leading-nullbyte.pem

$ openssl ec -noout -text -in no-leading-nullbyte.pem
read EC key
Private-Key: (256 bit)
priv:
    01:9c:16:83:df:a9:f1:59:e5:30:ef:ef:56:41:04:
    27:2d:6a:98:95:2b:06:62:90:4f:07:7c:a7:fa:d5:
    5d:43
pub:
    04:34:f8:ca:bf:db:e8:6c:99:f3:d4:54:a5:4a:ee:
    5c:34:fc:8f:c0:2b:dc:b0:c9:88:af:91:c7:f7:60:
    be:99:97:55:b5:a9:c7:c2:54:e6:db:d2:30:38:4e:
    65:48:4f:0a:33:2c:08:26:cf:29:2c:2b:d7:ef:d9:
    09:85:9f:ee:a6
ASN1 OID: prime256v1
NIST CURVE: P-256

asn1parse no-leading-nullbyte.pem

ここでも長さは32として与えられます:

    5:d=1  hl=2 l=  32 prim:  OCTET STRING
      0000 - 01 9c 16 83 df a9 f1 59-e5 30 ef ef 56 41 04 27   .......Y.0..VA.'

完全な解析:

$ openssl asn1parse -i -dump -in no-leading-nullbyte.pem
    0:d=0  hl=2 l= 119 cons: SEQUENCE
    2:d=1  hl=2 l=   1 prim:  INTEGER           :01
    5:d=1  hl=2 l=  32 prim:  OCTET STRING
      0000 - 01 9c 16 83 df a9 f1 59-e5 30 ef ef 56 41 04 27   .......Y.0..VA.'
      0010 - 2d 6a 98 95 2b 06 62 90-4f 07 7c a7 fa d5 5d 43   -j..+.b.O.|...]C
   39:d=1  hl=2 l=  10 cons:  cont [ 0 ]
   41:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   51:d=1  hl=2 l=  68 cons:  cont [ 1 ]
   53:d=2  hl=2 l=  66 prim:   BIT STRING
      0000 - 00 04 34 f8 ca bf db e8-6c 99 f3 d4 54 a5 4a ee   ..4.....l...T.J.
      0010 - 5c 34 fc 8f c0 2b dc b0-c9 88 af 91 c7 f7 60 be   \4...+........`.
      0020 - 99 97 55 b5 a9 c7 c2 54-e6 db d2 30 38 4e 65 48   ..U....T...08NeH
      0030 - 4f 0a 33 2c 08 26 cf 29-2c 2b d7 ef d9 09 85 9f   O.3,.&.),+......
      0040 - ee a6                                             ..

Extra:0x00が符号バイトであることをどうやって知るのですか?

...実験により:

私はそのように千のキーを生成しました:

$ for i in $(seq -w 1000); do echo $i; openssl ecparam -name prime256v1 -genkey -noout > key.$i.pem; done

そして私はソートして最初のバイトでそれらを数えました:

$ for i in $(seq -w 1000); do openssl ec -noout -text -in key.$i.pem 2>/dev/null | grep '^priv:' -A1 | tail -1; done | sed 's/ *//' | sed 's/\(..\).*/\1/' | sort | uniq -c

    496 00
      3 01
      3 02
      4 03
      5 04
      4 05
      5 06
      3 07
      1 08
      3 09
      1 0a
      3 0b
      2 0c
      2 0d
      3 0e
      4 0f
      4 11
      6 12
      1 14
      7 15
      3 16
      7 17
      4 18
      1 19
      6 1a
      3 1b
      3 1c
      3 1d
     11 1e
      3 1f
      6 20
      4 21
      2 22
      3 23
      8 24
      3 25
      2 26
      7 27
      3 28
      7 29
      4 2a
      4 2b
      9 2c
      2 2d
      5 2e
      2 2f
      5 30
      7 31
      6 32
      3 33
      6 34
      8 35
      5 36
      2 37
      2 38
      5 39
      2 3a
      1 3b
      4 3c
      3 3d
      2 3e
      2 3f
      2 40
      3 41
      5 42
      5 43
      3 44
      4 45
      5 46
      4 47
      5 48
      5 49
      5 4a
      5 4b
      8 4c
      6 4d
      3 4e
      5 4f
      4 50
      2 51
      4 52
      2 53
      2 54
      3 55
      7 56
      2 57
      5 58
      3 59
      3 5a
      5 5b
      2 5d
      1 5e
      9 5f
      3 60
      3 61
      3 62
      6 63
      3 64
      1 65
      7 66
      4 67
      3 68
      4 69
      4 6a
      3 6b
      6 6c
      4 6d
      3 6e
      3 6f
      7 70
      4 71
      2 72
      5 73
      2 74
      1 75
      5 76
      3 77
     10 78
      2 79
      7 7a
      5 7b
      6 7c
      6 7d
      5 7e
      5 7f

最上位バイトは0x7fです。そして、それが最上位ビットとして0が残っている最後のバイトです。 (ここではそれらの1000をすべて掲載しませんが、最初のバイトが0x00で、次に2番目のバイトが0x80であるすべての特権キーです。(0x0000で始まる特権キーはありませんでした。)すべての特権キーには0x00がありませんでした。最初のバイトには2番目のバイト<= 0x7fがあったため。)

4
StackzOfZtuff