Using digital signatures for data integrity checking in Linux
One of the most important questions in today’s world is the question of confidence in received data. For example, user А sends data D to user B via email. How can user B be sure that the received data is the same data that was sent by user A? One possible way of resolving this issue is using a digital signature (DS). The following requirements apply to a DS:
The signature content should depend on the signed message;
The sender’s unique information should be used in a signature;
It should be easy to create a signature;
It should be impossible to falsify a signature computationally;
A signature should be small.
This article considers a DS implementation example for binary file integrity checking in Linux (64-bit ELF). We will use a direct DS when only a sender and a recipient are communicating (without a third party/an arbitrator). We will need a private encryption key and a public key (certificate) for this. The sender creates both keys. User A signs an executable file and passes the certificate to user B with the help of safe delivery means. After this, user A sends a signed file to user B. User B runs the received file; if the binary file is corrupted, user B will receive a message that DS verification has failed. To implement this solution, we will need a program for signing binary files and a code that verifies DSs.
DS implementation example
DS implementation includes the following steps:
MD5 source binary file generation;
The creation of two keys: private and public (certificate).
Binary file signing (ELF):
1 MD5 of the binary file is encrypted with the help of the private key;
3.2 The encrypted MD5 is written to a new .sig section of the binary file;
3.3 The certificate is saved to the ~/.ssh folder.
All this can be implemented with the help of the Linux utilities openssl, objcopy, and md5sum. Below you can find an example of a script sign_elf.sh that signs ELF binary files. (Note: source without line numbers is included at the end of this article.)
Figure 1. The process of signing ELF binary. (Source: Auriga)
Let us explore the details of what this script does.
req — certificate creation request
-nodes — create a private plaintext key
-x509 — output — self-signed certificate
-sha256 — encryption algorithm
-newkey rsa:4096 — create a new certificate and RSA private key, number of bits — 4096
-keyout $PRIVATE_KEY — the path to the file where the private key is written to
-out $CERTIFICATE — the path to the file where the certificate is written to-days 365 — number of days for certificate acknowledgement
-subj $SUBJECT — new certificate subject (should have the format of /type0=value0/type1=value1/type2=…). In our case, this is /C=RU/ST=Nizhni Novgorod/L=Nizhniy Novgorod/O=Auriga/OU=DEV/CN=www.auriga.com, where
С — country
ST — state, region, province
L — location
O — organization
OU — organizational department/unit
CN — basic title/container name
The subject is described in detail in RFC-5280 (https://tools.ietf.org/html/rfc5280). After this command is run, a private key will be generated, ~/.ssh/priv.key and certificate ~/.ssh/pub.crt. The private key will be used to encrypt the data, and the certificate will be used for data decryption. Using one private key, it is possible to generate a number of unique certificates for decrypting data that was encrypted with this private key.
Start of loop for all binary files added to the sign_elf.sh script.
Remove the .sig section from our binary file. This needs to be conducted if the file was already signed with our script and we want to re-sign it.
Create a 512-byte text file and add it to our binary file not loaded on the runtime .sig section only for reading, which contains data from the dummy.txt file.
Calculate MD5 of the binary file (with .sig section) and write the result to a text file, binary_name.md5.
This command encrypts the file with MD5 created by line 42 with a private key. Arguments:
dgst — this option indicates that we want to encrypt (sign) data;
-sha256 — encryption algorithm;
-sign $PRIVATE_KEY — encrypt the file with the help of private key $PRIVATE_KEY;
-out $KEY_DIR/$ELF_BIN_SIGNATURE — encrypted data is saved to file $KEY_DIR/$ELF_BIN_SIGNATURE;
$KEY_DIR/$ELF_BIN_MD5 — text file containing data to be encrypted.
Signed file verification. It can be understood by reference to this line that for DS verification we need encrypted data, a certificate that will help us perform verification and data verification. That is, if
x — encrypted data,
y — certificate,
z — verification data,
f(x,y) = z
Remove the old .sig section and add a new one to file $ELF_BIN (binary_name). As data for the new .sig section, data from the signed file $KEY_DIR/$ELF_BIN_SIGNATURE (~/.ssh/binary_name.sha256) is used.