I have generated a private key using OpenSSL:
ARWIN-TIO:/tmp$ openssl ecparam -name prime256v1 -genkey -noout -out key.pem
ARWIN-TIO:/tmp$ cat key.pem
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIINcLTcsL/VhTBEsp1gRgHtO9lLzypm7oYjwViz3bWZCoAoGCCqGSM49
AwEHoUQDQgAE8kuZsfDhQdkkYjVRla3ShxAlsbLwOt8jUsKyebB7GGWxnBiDqRoB
bSxkkd+APIM/4+lYwIDAx5+EmIIuUIRdcA==
-----END EC PRIVATE KEY-----
And I'm struggling to use it in Erlang's Crypto module:
ARWIN-TIO:/tmp$ erl
Erlang/OTP 21 [erts-10.3.5.6] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Eshell V10.3.5.6 (abort with ^G)
1> Message = <<"Hello">>.
<<"Hello">>
2> PrivateKey = base64:decode("MHcCAQEEIINcLTcsL/VhTBEsp1gRgHtO9lLzypm7oYjwViz3bWZCoAoGCCqGSM49AwEHoUQDQgAE8kuZsfDhQdkkYjVRla3ShxAlsbLwOt8jUsKyebB7GGWxnBiDqRoBbSxkkd+APIM/4+lYwIDAx5+EmIIuUIRdcA==").
<<48,119,2,1,1,4,32,131,92,45,55,44,47,245,97,76,17,44,
167,88,17,128,123,78,246,82,243,202,153,...>>
3> Signature = crypto:sign(ecdsa, sha256, Message, [PrivateKey, prime256v1]).
** exception error: badkey
in function crypto:sign/5
called as crypto:sign(ecdsa,sha256,<<"Hello">>,
[<<48,119,2,1,1,4,32,131,92,45,55,44,47,245,97,76,17,44,
167,88,17,128,123,78,...>>,
prime256v1],
[])
When I generate the keys using Erlang's Crypto module, it works:
ARWIN-TIO:/tmp$ erl
Erlang/OTP 21 [erts-10.3.5.6] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Eshell V10.3.5.6 (abort with ^G)
1> Message = <<"Hello">>.
<<"Hello">>
2> {PublicKey, PrivateKey} = crypto:generate_key(ecdh, crypto:ec_curve(prime256v1)).
{<<4,149,38,43,104,132,214,232,147,174,88,185,96,250,185,
181,170,8,231,61,255,134,143,255,4,136,249,9,...>>,
<<130,195,50,229,108,51,72,27,219,145,250,244,116,3,52,
234,13,60,148,175,112,192,140,110,232,46,116,...>>}
3> Signature = crypto:sign(ecdsa, sha256, Message, [PrivateKey, prime256v1]).
<<48,70,2,33,0,252,243,117,254,110,176,232,185,121,156,93,
105,74,115,115,247,83,82,17,32,167,254,223,74,...>>
I noticed that the Erlang private keys are way shorter than the OpenSSL one:
4> base64:encode(PrivateKey).
<<"gsMy5WwzSBvbkfr0dAM06g08lK9wwIxu6C50rwKaBvw=">>
Which is way shorter than the one generated with "openssl ecparam -name prime256v1 -genkey -noout -out key.pem"
Why are the OpenSSL keys different/not working with Erlang's Crypto module? How can I make them compatible?
Thanks.
What you are looking at is a X9.62 encoded private key that got PEM encoded in addition. You've removed the PEM header lines and base 64 decoded, so now you just have the X9.62 encoded private key left.
As you seem to be using OpenSSL, first decode the base64 so you can do:
openssl asn1parse -inform DER -in private_prime256v1.bin
Which will give you:
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 [HEX DUMP]:
835C2D372C2FF5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
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
You haven't clearly shown the full extend of the public / private keys, but it looks like they are just the "flat" representations of the secret S and, for the public key, the uncompressed point W.
So that would be the OCTET STRING in the parsed private key (the final BIT STRING contains the optional public key, the uncompressed point W):
835C2D372C2FF5614C112CA75811807B4EF652F3CA99BBA188F0562CF76D6642
So this explains the why. I don't exactly know how to parse structures like this, but you may not have to. It seems like Erlang already has a function that does this for you called public_key:pem_decode
which should just take the entire openssl
generated key. According to the documentation it should also parse private keys.
As I'm not a Erlang programmer I cannot test this easily, so please let me know.