Dada una clave privada: 3cd0560f5b27591916c643a0b7aa69d03839380a738d2e912990dcc573715d2c
y un hash tx: 456f9e1b6184d770f1a240da9a3c4458e55b6b4ba2244dd21404db30b3131b94
me gustaría firmar, usando SSL y PHP. Al convertir la clave privada a un formato pem (para que SSL pueda usarla), genero la siguiente cadena base64: PNBWD1snWRkWxkOgt6pp0Dg5OApzjS6RKZDcxXNxXSw=
. Entonces, un formato pem válido debería ser:
-----BEGIN EC PRIVATE KEY----- PNBWD1snWRkWxkOgt6pp0Dg5OApzjS6RKZDcxXNxXSw= -----END EC PRIVATE KEY-----
Sin embargo, no parece estar funcionando. Estoy usando la siguiente función: openssl_sign($hash, $signature, $private_key, OPENSSL_ALGO_SHA256)
.
Pero cuando genero una clave privada aleatoria usando SSL, por ejemplo: -----BEGIN EC PRIVATE KEY----- MHcCAQEEINhhp8dYz31X+KWq3u/gutJthvW2puUbB9AOIul/v2SOoAoGCCqGSM49 AwEHoUQDQgAE0jE7TIszCklw//SGyYW0+z38PUxwfkip9WS4UUn68f7D78D6ZQ/O dlPisC1fQZrUrFrik/wq7E4Xwrqs3n3b5w== -----END EC PRIVATE KEY-----
La función funciona. ¿Qué tiene de malo el formato pem que estoy generando usando una clave privada existente?
cuando verifico tu clave privada creada por ti mismo, aparece este error:
error: 0D07207B: rutinas de codificación asn1: ASN1_get_object: encabezado demasiado largo
No pude ver cómo creaste tu clave privada, pero el camino a seguir es a través de la estructura ASN.1, y luego base64. Al usar OpenSSL para firmar, también debe asegurarse de que está firmando datos hexadecimales y no cadenas (esto se explica en la respuesta del enlace que proporcioné en mi comentario).
La estructura ASN1 para una clave privada se ve así:
# ASN.1 STRUCTURE FOR PRIVATE KEY:
# 30 <-- declares the start of an ASN.1 sequence
# 74 <-- length of following sequence
# 02 <-- declares the start of an integer
# 01 <-- length of integer in bytes (1 byte)
# 01 <-- value of integer (1)
# 04 <-- declares the start of an "octet string"
# 20 <-- length of string to follow (32 bytes)
# 3cd0560f5b27591916c643 ... a738d2e912990dcc573715d2c
# \--------------------------------------------------/
# this is the private key
# a0 <-- declares the start of context-specific tag 0
# 07 <-- length of context-specific tag
# 06 <-- declares the start of an object ID
# 05 <-- length of object ID to follow
# 2b 81 04 00 0a <-- the object ID of the curve secp256k1
# a1 <-- declares the start of context-specific tag 1
# 44 <-- declares the length of context-sepcifc tag (68 bytes)
# 03 <-- declares the start of a bit string
# 42 <-- length of bit string to follow (66 bytes)
# 00 <-- ??
# 04 f1 44 f0 dc 00 80 af d2 b7 3f 13 37 6c ... 05 49 cd 83 f4 58 56 1e
# \-------------------------------------------------------------------/
# this is the public key
Usando su clave privada, derivé el pukey y obtuve este formato pem:
### use pre defined ASN.1 strings to concatenate PEM privkey
a pre_string : 30740201010420
the privkey : 3cd0560f5b27591916c643a0b7aa69d03839380a738d2e912990dcc573715d2c
a mid_string : a00706052b8104000aa144034200
the pubkey : 04BF350D2821375158A608B51E3E898E507FE47F2D2E8C774DE4A9A7EDECF74ED
A24243CB992C5673A07FA5B3A66CD8E3ACEF2809D0E380A0C7929DAB1E5D5438B
### base64 privkey file and put some nice surroundings
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK
oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6
WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw==
-----END EC PRIVATE KEY-----
usando asn1parse, el resultado se ve así:
openssl asn1parse -in privkey.pem
0:d=0 hl=2 l= 116 cons: SEQUENCE
2:d=1 hl=2 l= 1 prim: INTEGER :01
5:d=1 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:3CD0560F5B27591916C643A0B7AA69D03839380A738D2E912990DCC573715D2C
39:d=1 hl=2 l= 7 cons: cont [ 0 ]
41:d=2 hl=2 l= 5 prim: OBJECT :secp256k1
48:d=1 hl=2 l= 68 cons: cont [ 1 ]
50:d=2 hl=2 l= 66 prim: BIT STRING
juntando todo:
#!/bin/sh
###############################################
# convert from chars to hex
printf $( echo 456f9e1b6184d770f1a240da9a3c4458e55b6b4ba2244dd21404db30b3131b94 | sed 's/[[:xdigit:]]\{2\}/\\x&/g' ) > tmp_utx.hex
echo "The private key in HEX format: "
echo 3cd0560f5b27591916c643a0b7aa69d03839380a738d2e912990dcc573715d2c
# The private key in PEM format:
echo "-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIDzQVg9bJ1kZFsZDoLeqadA4OTgKc40ukSmQ3MVzcV0soAcGBSuBBAAK
oUQDQgAEvzUNKCE3UVimCLUePomOUH/kfy0ujHdN5Kmn7ez3TtokJDy5ksVnOgf6
WzpmzY46zvKAnQ44Cgx5Kdqx5dVDiw==
-----END EC PRIVATE KEY-----" > privkey.pem
# the signing process
# prepare pubkey:
openssl ec -in privkey.pem -pubout -out pubkey.pem
# sign:
openssl dgst -sign privkey.pem -sha256 -hex tmp_utx.hex
openssl dgst -sign privkey.pem -sha256 tmp_utx.hex > tmp_sig.hex
# verify:
openssl dgst -verify pubkey.pem -sha256 -signature tmp_sig.hex tmp_utx.hex
echo " "
devoluciones:
Verificado OK
Para Javascript/Node, recomiendo esta biblioteca:
https://www.npmjs.com/package/key-codificador
https://github.com/blockstack/key-codificador-js/
Hace exactamente lo que necesitas.
pebwindkraft
usuario2298995