Using RSA keys for signing in Erlang

8 Feb 2023 14:06 erlang cryptography

How do I sign (and verify) things in Erlang, using an RSA key?

We’ll start with a private key:

Size = 2048,  % in bits
Exp = 65537,  % standard RSA exponent
RSAPrivateKey = public_key:generate_key({rsa, Size, Exp}).

If you want to check this against openssl, write the key to a file; see this post.

Signing a message

Signature = public_key:sign(<<"Hello World">>, sha256, RSAPrivateKey).

You can also use crypto:sign/4, but you’ll need to decompose the RSAPrivateKey record first:

rr(public_key).   % if in the REPL, otherwise -include_lib("public_key/include/public_key.hrl").

#'RSAPrivateKey'{publicExponent = E, modulus = N, privateExponent = D} = RSAPrivateKey.
Signature = crypto:sign(rsa, sha256, <<"Hello World">>, [E, N, D]).

Or, using the longer key format (which is faster):

rr(public_key).   % if in the REPL, otherwise -include_lib("public_key/include/public_key.hrl").

#'RSAPrivateKey'{publicExponent = E, modulus = N, privateExponent = D, prime1 = P1, prime2 = P2, exponent1 = E1, exponent2 = E2, coefficient = C} = RSAPrivateKey.
Signature = crypto:sign(rsa, sha256, <<"Hello World">>, [E, N, D, P1, P2, E1, E2, C]).

All of the above should return the same value for Signature.

You can compare it with openssl, as follows:

echo -n 'Hello World' | openssl dgst -sha256 -sign my.key | base64

Verifying a message

To verify a message, you need only the public key:

#'RSAPrivateKey'{modulus = Modulus, publicExponent = PublicExponent} = RSAPrivateKey.
RSAPublicKey = #'RSAPublicKey'{modulus = Modulus, publicExponent = PublicExponent}.
true = public_key:verify(<<"Hello World">>, sha256, Signature, RSAPublicKey).

But it also works with the private key:

true = public_key:verify(<<"Hello World">>, sha256, Signature, RSAPrivateKey).

If you want to use crypto:verify/5, that looks like this:

true = crypto:verify(rsa, sha256, <<"Hello World">>, Signature, [E, N]).

You can compare it with openssl, but note that you’ll need the public key (my.pub) and the signature should be in a file (here, sig):

$ echo -n 'Hello World' | openssl dgst -sha256 -verify my.pub -signature sig
Verified OK

If it fails:

$ echo -n 'Hello World!' | openssl dgst -sha256 -verify my.pub -signature sig
Verification Failure