Openssl Public Key

Being able to verify that a piece of data originates from a trusted source (authenticity) and that it has not been altered in transit (integrity) is a common requirement in many use cases. It is needed for instance when distributing software packages and installers and when delivering firmware to an embedded device. Digital signatures allow the recipient to verify both authenticity and integrity of the received document. This blog post describes how to use digital signatures with OpenSSL in practice. First part describes what is a digital signature and then the second part shows how to use OpenSSL sign and verify functions to work with signatures.

The first key posted is a public key in X.509/SPKI format (PEM encoded), which contains the actual key in uncompressed format 0x04 + +. The key derived from this using the OpenSSL statement is also a public key in X.509/SPKI format, but contains the actual key in compressed format 0x02 + or 0x03 + for even or odd y, respectively. This module allows one to (re)generate OpenSSL public keys from their private keys. It uses the pyOpenSSL python library to interact with openssl. Keys are generated in PEM format. This module works only if the version of PyOpenSSL is recent enough ( 16.0.0).

What is a digital signature?

To understand what makes a digital signature, the two requirements, integrity and authenticity, should be first examined separately. Common method to verify integrity is to use a hash function. A hash function takes an arbitrary length data and produce a fixed sized digest for it. For instance, SHA256 hash function always produces 256-bit output. Hash functions are also designed so that even a minute change in the input produces very different digest output. Also, it is very hard to find two inputs that produce the same digest (collision resistance).

To verify integrity in practice using a hash function, the sender first calculates the digest for the message or document. The digest is then sent alongside the message to the recipient. When the message is received, the recipient calculates the digest from the received data and verifies that it matches with the one calculated by the sender. If the digests differ, the data has changed in transit. It is quite common to find hash values for download files on websites (e.g. Linux distributions or software installers) which allow the user to verify the file before installing. For instance, SHA256 hashes for recent Ubuntu images are shown below:

However, if the digest is sent with the data, it is possible that a malicious actor intercepts the message and modifies it (man-in-the middle). Since calculating the digest does not require any secret, it is possible to alter the data and update the digest before sending it to the recipient. Anyone who has the data is able to calculate a valid hash for it which means that a hash function alone cannot be used to verify the authenticity of the data.

To authenticate the source of the data, a secret that is only known by the sender needs to be used. Often this secret information is a private key. When a hash function and asymmetric cryptography (public-private key) are combined, digital signatures can be created.

Simply put, a digital signature is a hash value (digest) from the original data that is encrypted using a private key. To verify a signature, the recipient first decrypts the signature using a public key that matches with the senders private key. This produces a digest. Then the recipient calculates a digest from the received data and verifies that it matches with the one in the signature. If the digest match, the signature is valid.

Any change in the data will invalidate the signature. Also, it is computationally infeasible to produce a valid signature for the modified data without knowing the private key when sufficiently large key size and proper hash functions are used. Therefore, when the signature is valid, the recipient can be sure that the message originated from a trusted source and it is unchanged.

It is important to note that digital signature does not encrypt the original data. It just provides a scheme to verify it. Another important thing to note is that encryption alone does not provide authentication. Encryption hides the plain data, but it may still be possible to change the encrypted message to control the output that is produced when the recipient decrypts it.

Openssl public key fingerprint

Implementation

To work with digital signatures, private and public key are needed. 4096-bit RSA key can be generated with OpenSSL using the following commands.

The private key is in key.pem file and public key in key.pub file. The sender uses the private key to digitally sign documents, and the public key is distributed to recipients.

Sign and verify from command line

To sign a data file (data.zip in the example), OpenSSL digest (dgst) command is used. More information about the command can be found from its man page.

The -sign argument tells OpeSSL to sign the calculated digest using the provided private key. The hash function is selected with -sha256 argument. Other hash functions can be used in its place (e.g. sha1 or sha512). The output is written to data.zip.sign file in binary format.

The digital signature can also be verified using the same openssl dgst command. Obviously this step is performed on the receivers end.

The -verify argument tells OpenSSL to verify signature using the provided public key. The signature file is provided using -signature argument.

When the signature is valid, OpenSSL prints “Verified OK”.

It is also possible to calculate the digest and signature separately. This can be useful if the signature is calculated on a different machine where the data file is generated (e.g. to manage private keys securely). This way the whole data file does not need to be moved to the signing machine.

Openssl Show Public Key

The pkeyutl command does not know which hashing algorithm was used because it only gets the generated digest as input. Therefore -pkeyopt argument is used to tell which algorithm was used, so it can be properly marked in the signature for verify operation. Otherwise the arguments should be fairly self-explanatory. More information from the man page.

Verify with C

If the OpenSSL command line utilities are not available for instance in an embedded environment, the signature can also be verified quite easily using C and libssl library. First, the OpenSSL headers should be installed:

The following listing shows an implementation for a command line application that takes data file, signature file and public key as arguments, and verifies the signature. Note that all error handling has been omitted (e.g. files not available) to simplify the example.

The application needs to be linked with crypto library which provides the necessary interfaces.

The application first calculates SHA256 digest from the data file. Then, both the signature and public key are read from files. Finally RSA_verify function is used to decrypt the signature and compare it with the SHA256 digest calculated earlier.

Openssl Public Key

Conclusions

Openssl Extract Public Key

Digital signatures provide a strong cryptographic scheme to validate integrity and authenticity of data and are therefore useful in various use cases. OpenSSL provides easy command line utilities to both sign and verify documents. Additionally the libcrypto can be used to perform these operations from a C application. Special care should be taken when handling the private keys especially in a production environment because the whole scheme relies on the senders private key being kept secret.