Using digital signatures for data integrity checking in Linux

February 27, 2019

Kirill Brazhnikov-February 27, 2019


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:

  1. MD5 source binary file generation;

  2. The creation of two keys: private and public (certificate).

  3. 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 that signs ELF binary files. (Note: source without line numbers is included at the end of this article.)

001   #!/bin/bash
003   KEY_DIR="$HOME/.ssh"
004   PRIVATE_KEY="$KEY_DIR/priv.key"
005   CERTIFICATE="$KEY_DIR/pub.crt"
006   SUBJECT="/C=RU/ST=Nizhni Novgorod/L=Nizhniy Novgorod/O=Auriga/OU=DEV/"
008   if [ "$#" = "0" ]; then
009       echo "Usage:   ... "
010       exit 1;
011   fi
013   if [ ! -d "$KEY_DIR" ]; then
014       # Control will enter here if $DIRECTORY does not exist.
015       mkdir "$KEY_DIR"
016   fi
018   # Create private key and certificate
019   openssl req -nodes -x509 -sha256 -newkey rsa:4096 -keyout "$PRIVATE_KEY" -out "$CERTIFICATE" -days 365 -subj "$SUBJECT"
021   for ELF_BIN in $@; do
022       ELF_BASE_NAME="${ELF_BIN##*/}"
023       #       ELF_BIN_OLD="$ELF_BIN.old"
025       ELF_BIN_MD5="$ELF_BASE_NAME.md5"
027       if [ ! -f "$ELF_BIN" ] || [ "x$ELF_BIN" = "x" ];then
028           echo "Error: no such file $ELF_BIN"
029       exit 1
030       fi
032       # Remove .sig section
033       objcopy --remove-section=.sig "$ELF_BIN"
035       # Add 512-byte section filled with zeros
036       rm -f dummy.txt
037       touch dummy.txt
038       truncate --size=512 dummy.txt
039       objcopy --add-section .sig=dummy.txt --set-section-flags .sig=noload,readonly "$ELF_BIN"
041       # Create MD5 hash
042       md5sum "$ELF_BIN" | awk '{ print $1 }' > "$KEY_DIR/$ELF_BIN_MD5"
044       # Encrypt MD5 hash using private key
045       openssl dgst -sha256 -sign "$PRIVATE_KEY" -out "$KEY_DIR/$ELF_BIN_SIGNATURE" "$KEY_DIR/$ELF_BIN_MD5"
047       # Validate encrypted MD5 hash using certificate
048       openssl dgst -sha256 -verify <(openssl x509 -in "$CERTIFICATE" -pubkey -noout) -signature "$KEY_DIR/$ELF_BIN_SIGNATURE" "$KEY_DIR/$ELF_BIN_MD5"
050       # Add encrypted MD5 hash into ELF binary into .sig section
051       echo "Add .sig section"
052       objcopy --update-section .sig="$KEY_DIR/$ELF_BIN_SIGNATURE" --set-section-flags .sig=noload,readonly "$ELF_BIN" "$ELF_BIN"
054       # Print .sig section
055       echo "Check .sig section"
056       objdump -sj .sig "$ELF_BIN"
057   done
059   rm -f dummy.txt
061   ls -ls ~/.ssh

Figure 1. The process of signing ELF binary. (Source: Auriga)

Let us explore the details of what this script does.

Line 19:

openssl req -nodes -x509 -sha256 -newkey rsa:4096 -keyout "$PRIVATE_KEY" -out "$CERTIFICATE" -days 365 -subj "$SUBJECT"

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/, 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 ( 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.

Line 21:

for ELF_BIN in $@; do

Start of loop for all binary files added to the script.

Line 33:

objcopy --remove-section=.sig "$ELF_BIN"

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.

Lines 36+:

rm -f dummy.txt
touch dummy.txt
truncate --size=512 dummy.txt
objcopy --add-section .sig=dummy.txt --set-section-flags .sig=noload,readonly "$ELF_BIN

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.

Line 42:

md5sum "$ELF_BIN" | awk '{ print $1 }' > "$KEY_DIR/$ELF_BIN_MD5"

Calculate MD5 of the binary file (with .sig section) and write the result to a text file, binary_name.md5.

Line 45:

openssl dgst -sha256 -sign "$PRIVATE_KEY" -out "$KEY_DIR/$ELF_BIN_SIGNATURE" "$KEY_DIR/$ELF_BIN_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.

Line 48:

openssl dgst -sha256 -verify <(openssl x509 -in "$CERTIFICATE" -pubkey -noout) -signature "$KEY_DIR/$ELF_BIN_SIGNATURE" "$KEY_DIR/$ELF_BIN_MD5"

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

Line 52:

objcopy --update-section .sig="$KEY_DIR/$ELF_BIN_SIGNATURE" --set-section-flags .sig=noload,readonly "$ELF_BIN" "$ELF_BIN"

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.

Continue reading on page two >>

< Previous
Page 1 of 2
Next >

Loading comments...