Using OpenSSL to Sign Data (Simple Guide)
OpenSSL, a tool which accompanies us all the time but often being ignored by everyone. OpenSSL is currently the most powerful tool in the cryptographic industry.
With that said, OpenSSL itself is not easy to use and rather complicated and confusing.
This guide focus on signing & encrypting data in a simple way, utilizing a pair of Elliptic Curve keys.
My OpenSSL version:
OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
Getting Started
Generate keys
First we need to choose the algorithm. Unlike RSA
, which only differs in key size, ECC
has a lot of curves, like NIST curve, Brainpool curve.
Yeah I know, Curve 25519 folks. Unfortunately Curve 25519 is not a standard curve and therefore not supported by
ecparam
in OpenSSL. Alternatively you can useopenssl genpkey -algorithm ed25519/x25519
to generate Curve 25519 keys, but due to the specialty of Curve 25519, it CANNOT be used for encryption, only signing. Also, you are ought to generate X.509 certificates in order to sign stuff, which is beyond what we are going to talk about.
Run openssl ecparam -list_curves
to see all the curves available.
$ openssl ecparam -list_curves 1 ↵
secp112r1 : SECG/WTLS curve over a 112 bit prime field
secp112r2 : SECG curve over a 112 bit prime field
secp128r1 : SECG curve over a 128 bit prime field
secp128r2 : SECG curve over a 128 bit prime field
secp160k1 : SECG curve over a 160 bit prime field
secp160r1 : SECG curve over a 160 bit prime field
secp160r2 : SECG/WTLS curve over a 160 bit prime field
secp192k1 : SECG curve over a 192 bit prime field
secp224k1 : SECG curve over a 224 bit prime field
secp224r1 : NIST/SECG curve over a 224 bit prime field
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field
prime192v2: X9.62 curve over a 192 bit prime field
prime192v3: X9.62 curve over a 192 bit prime field
prime239v1: X9.62 curve over a 239 bit prime field
prime239v2: X9.62 curve over a 239 bit prime field
prime239v3: X9.62 curve over a 239 bit prime field
prime256v1: X9.62/SECG curve over a 256 bit prime field
sect113r1 : SECG curve over a 113 bit binary field
sect113r2 : SECG curve over a 113 bit binary field
sect131r1 : SECG/WTLS curve over a 131 bit binary field
sect131r2 : SECG curve over a 131 bit binary field
sect163k1 : NIST/SECG/WTLS curve over a 163 bit binary field
sect163r1 : SECG curve over a 163 bit binary field
sect163r2 : NIST/SECG curve over a 163 bit binary field
sect193r1 : SECG curve over a 193 bit binary field
sect193r2 : SECG curve over a 193 bit binary field
sect233k1 : NIST/SECG/WTLS curve over a 233 bit binary field
sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field
sect239k1 : SECG curve over a 239 bit binary field
sect283k1 : NIST/SECG curve over a 283 bit binary field
sect283r1 : NIST/SECG curve over a 283 bit binary field
sect409k1 : NIST/SECG curve over a 409 bit binary field
sect409r1 : NIST/SECG curve over a 409 bit binary field
sect571k1 : NIST/SECG curve over a 571 bit binary field
sect571r1 : NIST/SECG curve over a 571 bit binary field
c2pnb163v1: X9.62 curve over a 163 bit binary field
c2pnb163v2: X9.62 curve over a 163 bit binary field
c2pnb163v3: X9.62 curve over a 163 bit binary field
c2pnb176v1: X9.62 curve over a 176 bit binary field
c2tnb191v1: X9.62 curve over a 191 bit binary field
c2tnb191v2: X9.62 curve over a 191 bit binary field
c2tnb191v3: X9.62 curve over a 191 bit binary field
c2pnb208w1: X9.62 curve over a 208 bit binary field
c2tnb239v1: X9.62 curve over a 239 bit binary field
c2tnb239v2: X9.62 curve over a 239 bit binary field
c2tnb239v3: X9.62 curve over a 239 bit binary field
c2pnb272w1: X9.62 curve over a 272 bit binary field
c2pnb304w1: X9.62 curve over a 304 bit binary field
c2tnb359v1: X9.62 curve over a 359 bit binary field
c2pnb368w1: X9.62 curve over a 368 bit binary field
c2tnb431r1: X9.62 curve over a 431 bit binary field
wap-wsg-idm-ecid-wtls1: WTLS curve over a 113 bit binary field
wap-wsg-idm-ecid-wtls3: NIST/SECG/WTLS curve over a 163 bit binary field
wap-wsg-idm-ecid-wtls4: SECG curve over a 113 bit binary field
wap-wsg-idm-ecid-wtls5: X9.62 curve over a 163 bit binary field
wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field
wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field
wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field
wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field
wap-wsg-idm-ecid-wtls10: NIST/SECG/WTLS curve over a 233 bit binary field
wap-wsg-idm-ecid-wtls11: NIST/SECG/WTLS curve over a 233 bit binary field
wap-wsg-idm-ecid-wtls12: WTLS curve over a 224 bit prime field
Oakley-EC2N-3:
IPSec/IKE/Oakley curve #3 over a 155 bit binary field.
Not suitable for ECDSA.
Questionable extension field!
Oakley-EC2N-4:
IPSec/IKE/Oakley curve #4 over a 185 bit binary field.
Not suitable for ECDSA.
Questionable extension field!
brainpoolP160r1: RFC 5639 curve over a 160 bit prime field
brainpoolP160t1: RFC 5639 curve over a 160 bit prime field
brainpoolP192r1: RFC 5639 curve over a 192 bit prime field
brainpoolP192t1: RFC 5639 curve over a 192 bit prime field
brainpoolP224r1: RFC 5639 curve over a 224 bit prime field
brainpoolP224t1: RFC 5639 curve over a 224 bit prime field
brainpoolP256r1: RFC 5639 curve over a 256 bit prime field
brainpoolP256t1: RFC 5639 curve over a 256 bit prime field
brainpoolP320r1: RFC 5639 curve over a 320 bit prime field
brainpoolP320t1: RFC 5639 curve over a 320 bit prime field
brainpoolP384r1: RFC 5639 curve over a 384 bit prime field
brainpoolP384t1: RFC 5639 curve over a 384 bit prime field
brainpoolP512r1: RFC 5639 curve over a 512 bit prime field
brainpoolP512t1: RFC 5639 curve over a 512 bit prime field
SM2 : SM2 curve over a 256 bit prime field
Basically all the curves above are available to use, specifically begun with prime, secp, brainpool
SM2
is the algorithm developed by the Chinese government and, currently, little information about it is available online. Unless you work for the CHinese government or you are dealing with entites that related to banking or incorporating in China, you are generally not suggested to use SM2 curves.
We will be using SECP curves today.
To generate your keys,
openssl ecparam -name secp384r1 -genkey -noout -out private.pem
So here’s the thing, ecparam
by default only generates the parameters
that are needed to generate the respective curve, which is useful if you need to generate a lot of curves. Obviously this is not the case here, so we give it -genkey
to ask it to generate the key, and we specify -noout
to ask OpenSSL to not output the parameters. The -name
is not the name of your private key, but the name of the curve that you are using, here we are going to use 384-bit SECP curve.
Encrypting your key
The key we have just generated is UNENCRYPTED, which is not safe. I suggest everyone to encrypt their key(s).
openssl ec -in private.pem -aes-256-cbc -out private_enc.pem
Put in your passphrase and you are good to go.
To obtain your public key,
openssl ec -in private.pem -pubout -out public.pem
Signing
Now we can sign some data.
To generate some random number,
dd if=/dev/random of=data bs=1k count=1
--- OR ---
echo $RANDOM | tee data
And to sign it,
openssl dgst -sha384 -sign private.pem data > data.sig
To verify it,
openssl dgst -sha384 -verify public.pem -signature data.sig data
If everything is OK, you will see
$ openssl dgst -sha384 -verify public.pem -signature data.sig data
Verified OK
Alternatively, you can use -sha256
or -sha512
.
Encrypting
Due to the specialty of ECC, you CANNOT encrypt big data blocks directly. Instead, you should generate a long and complex symmetric key and encrypt your big data blocks using that key. After that, you encrypt the key.
We first need to generate the symmetric key, but we don’t need it to be ASCII-armored. A binary should be ok.
openssl rand -out symmetric_key.bin 256
The 256
stands for the bit length. Longer is usually better but your encryption speed will be significantly slower.
After that, we can symmetrically encrypt the data.
openssl enc -aes-256-cbc -pbkdf2 -in data -out data_enc.bin -pass file:./symmetric_key.bin
Okay, let’s deal with the key.
Still, due to the specialty of ECC, we cannot encrypt the data directly. Instead, we need to utilize something called ECDH to derive a shared key from our primary key, which is symmetric. Then we encrypt data using that key.
# Derive a shared key from our primary key.
openssl pkeyutl -derive -inkey private.pem -peerkey public.pem -out shared_key.bin
# Convert the shared key into an AES key.
openssl dgst -sha256 -binary shared_key.bin > derived_key.bin
# Encrypt the key that was used to encrypt files using the derived key.
openssl enc -aes-256-cbc -pbkdf2 -in symmetric_key.bin -out encrypted_symmetric_key.bin -pass file:./derived_key.bin
Similarly, we can decrypt the data in the following steps.
# Derive a shared key from our primary key.
openssl pkeyutl -derive -inkey private.pem -peerkey public.pem -out shared_key.bin
# Convert the shared key into an AES key.
openssl dgst -sha256 -binary shared_key.bin > derived_key.bin
# Decrypt the key that was used to decrypt files using the derived key.
openssl enc -d -aes-256-cbc -pbkdf2 -in encrypted_symmetric_key.bin -out decrypted_symmetric_key.bin -pass file:./derived_key.bin
# Decrypt the data
openssl enc -d -aes-256-cbc -pbkdf2 -in data_enc.bin -out data_decrypted -pass file:./decrypted_symmetric_key.bin
Your decrypted file should appear in data_decrypted
Outro
This is just a simple guide to signing, encrypting, and decrypting using OpenSSL, with ECC keys. ECC itself is very different, so it’s not as easy as RSA, but I’m sure that you have understood the basic operations by viewing this article.