Tamaño incorrecto para el par de claves EC

3

Estoy usando OpenSSL para generar pares de claves EC. Observo que la longitud de las claves mostradas por OpenSSL es exactamente un byte más larga de lo esperado tanto para la clave privada como para la pública.

El 00 (primer byte de la clave privada) es un entero con codificación ASN.1, garantiza que el valor se interprete como no negativo y el primer byte de la clave pública 04 es para la clave sin comprimir.

La clave privada es de 33 bytes (no de 32 bytes), y la clave pública es de 65 bytes, (no de 64 bytes)

  

Clave privada: (256 bits)

     

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
     

pub:

  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
     

OID ASN1: prime256v1

     

NIST CURVE: P-256

¿Cómo puedo eliminar el primer byte para la clave privada y pública? o de lo contrario, ¿cómo puedo ajustar el tamaño de lo privado a 32 bytes y la clave pública a 64 bytes?

¿El 00 inicial cambia el valor del número?

Estoy usando OpenSSL 1.0.2k 26 de enero de 2017

    
pregunta Med 26.06.2017 - 16:17
fuente

1 respuesta

3

No estoy seguro de por qué quieres cortar bytes. Así que no estoy seguro de que esta sea una buena respuesta a su pregunta. De todos modos, vaya.

Esto es lo que descubrí al leer los RFC / experimentación.

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

No tienes que hacerlo. Ya están en esa forma. Es un poco confuso leerlo desde la impresión de openssl.

Does the leading 00 change the value of the number?

La respuesta es "No" si, de todos modos, ibas a analizarlo como int sin firmar. (Y "sí" si (por error) iba a analizarlo como un int firmado. En ese caso, debe mantener el prefijo 0x00).

TLDR : el 0x00 principal es un SIGN BYTE que openssl agrega solo para la impresión. NO está codificado en el propio certificado. Y supongo que puede cortar el byte principal (uno de 0x02, 0x03 o 0x04 ) de la tecla de menú porque solo almacena información sobre si se utiliza la codificación comprimida o no comprimida.

Clave de ejemplo con nullbyte inicial

Aquí hay un ejemplo de una clave aleatoria que generé:

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

impresión ec leading_nullbyte.pem

Esta clave se muestra con el prefijo "00:" para la clave privada.

Al menos al usar la impresora 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

... sin embargo, al mirar dentro de la codificación ASN1 no hay un prefijo 00: . Simplemente comienza con df: de inmediato. Y también: la longitud se da como 32 ( l= 32 ). No 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..{

Aquí están esas líneas en contexto:

$ 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.

Por lo tanto, el 0x00 inicial no está realmente codificado en el archivo de certificado. Aunque no he echado un vistazo al código fuente de openssl, me refiero a llamar a esto un error de impresión.

De acuerdo con RFC5915 (creo) una clave EC es un entero sin signo.

Clave de ejemplo SIN nullbyte inicial

Aquí hay otra clave aleatoria que generé. NO tiene el prefijo 0x00 cuando se usa la impresora openssl ec pretty.

Así que esto me dice que ese prefijo 0x00 no está necesariamente allí para cada clave privada de EC.

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

impresión 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

Aquí nuevamente la longitud se da como 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.'

análisis completo:

$ 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   ...+........'.
      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: ¿Cómo sé que el 0x00 es un byte de signo?

... por experimentación:

He generado mil claves así:

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

Y luego los ordené y los conté por el primer byte así:

$ 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/\(..\).*//' | 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

El byte más alto es 0x7f. Y ese es el byte final que todavía tiene un 0 como el bit más significativo. (No publicaré todos los miles de ellos aquí, pero todas las claves privadas que tenían 0x00 como su primer byte tenían su segundo byte > = 0x80. (No había ninguna clave privada que comenzara con 0x0000). Y todas las claves privadas NO tenían 0x00 como su primer byte luego tuvo su segundo byte < = 0x7f.)

    
respondido por el StackzOfZtuff 27.06.2017 - 22:58
fuente

Lea otras preguntas en las etiquetas