Pergunta

I tried to use crypto:sign/4 to sign a message but failed. Could anyone show me how to sign a message using ECDSA in Erlang? Thanks. (I'm using Erlang version R16B01.)

The module code:

-module(message).

-compile(export_all).

go() ->
    {_PubKey, PriKey} = crypto:generate_key(ecdh, secp256k1),
    SigBin = sign_message(PriKey, "Hello"),
    SigBin.

sign_message(PriKey, Msg) ->
    Algorithm = ecdsa,
    DigestType = sha256,
    MsgBin = list_to_binary(Msg),
    SigBin = crypto:sign(Algorithm, DigestType, MsgBin, PriKey),
    SigBin.

But it failed on a test run:

1> message:go().
** exception error: no function clause matching crypto:sign(ecdsa,sha256,
                                                        {digest,

        <<24,95,141,179,34,113,254,37,245,97,166,252,147,
        139,46,38,67,6,236,48,78,218,81,128,...>>},
        <<189,38,200,204,95,248,54,69,42,65,216,165,242,228,100,
        54,158,5,61,174,58,198,191,161,9,...>>) (crypto.erl, line 462)

Thanks to Paul, this error can be fixed by making the following change.

change:

SigBin = crypto:sign(Algorithm, DigestType, MsgBin, PriKey),

to:

SigBin = crypto:sign(Algorithm, DigestType, MsgBin, [PriKey, secp256k1]),
Foi útil?

Solução

The crypto:sign/4 and crypto:generate_key/2 functions are quite confusing for ECDSA as ECDSA requires domain parameters, unlike the other two supported algorithms.

The error message simply tells you that the parameters you are passing do not match any clause of the crypto:sign/4 function. You are probably passing an argument of the wrong type.

You can look at the source code of the called function to find out why no clause match your parameters. This is typically what you would do for your own functions. Yet here, crypto:sign/4 is a system function which is properly documented.

The documentation reads as follows:

sign(Algorithm, DigestType, Msg, Key) -> binary()

Types:

Algorithm = rsa | dss | ecdsa

Msg = binary() | {digest,binary()}

The msg is either the binary "cleartext" data to be signed or it is the hashed value of "cleartext" i.e. the digest (plaintext).

DigestType = digest_type()

Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()]

Your first three arguments are obviously ok. The issue is with the key. Indeed, your code goes like this:

{_PubKey, PriKey} = crypto:generate_key(ecdh, secp256k1)

Looking at the documentation of crypto:generate_key/2, you'll find out that in the case of ECDH, PrivKey is of type ecdh_private() and not [ecdh_private(),ecdh_params()] as crypto:sign/4 expects.

A fix would be to pass [PrivKey, secp256k1] to your sign_message function, as the sign function requires the identification of the curve domain parameters through the sign key parameter.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top