wiki:linux/crypto

Version 2 (modified by Tim Harvey, 2 months ago) (diff)

fixed cryptodev building instructions

Linux Crypto API

The Crypto API, introduced in Linux 2.5.45, is a generic cryptography library API introduced in the kernel containing support for all popular block ciphers, hash functions, AEAD, HMAC, and compression algorithms. The kernel contains software implementations for major symmetric ciphers as well as allows plugging in implementations which take advantage of hardware components such as the IMX6 CAAM and OcteonTX ZIP/CPT hardware blocks that can accelerate encryption/compression.

The Linux Kernel Crypto API backend modules transparently accelerate kernelspace crypto users such as IPsec, 802.11, 802.15.4, Bluetooth, and and dm-crypt (search the kernel for 'crypto_alloc_' to find all users).

Software vs Hardware Crypto:

  • Software:
    • Example: OpenSSL SW engine
    • pros:
      • full control over the algorithm
      • no black box
    • cons
      • consumes CPU cycles
      • often slower than dedicated software
  • Hardware:
    • Example: IMX6 CAAM, Octeon-Tx CPT/ZIP
    • pros
      • minimal CPU cycles
      • generally faster than software counterpart
    • cons
      • limited subset of algorithms
      • black box

Note that often modern processors can outperform hardware crypto offload by using software crypto (at the expense of using up CPU cycles). In these cases or the case where the benefit of hardware crypto results in the same performance the difference is the off-loading to conserve CPU cycles. Perform benchmarks before choosing a solution that's right for you.

References:

Linux userspace crypto support

Accessing the Linux kernel Crypto API from userspace in order to take advantage of hardware crypto offload can be done in one of two ways:

  • AF_ALG: the in-tree/official solution (since OpenSSL 1.1.0) and supported in older OpenSSL via an out-of-tree plugin
  • Cryptodev: out-of-tree kernel module ported from BSD with better performance and natively supported in OpenSSL

You can use either of the above kernel API's directly or you can use a crypto library that may support them such as OpenSSL or GnuTLS.

AF_ALG

AF_ALG is a netlink-based interface that adds an AF_ALG address family introduced in 2.6.38.

Kernel configuration:

  • CONFIG_CRYPTO_USER_API
  • CONFIG_CRYPTO_USER_API_HASH
  • CONFIG_CRYPTO_USER_API_SKCIPHER
  • CONFIG_CRYPTO_USER_API_RNG
  • CONFIG_CYRPTO_USER_API_AEAD

Comparison to Cryptodev (+ indicates a pro, - indicates a con):

  • supports CIPHER, HASH
  • socket based interface
  • + in kernel since 2.6.38
  • + inherently asynchronous
  • - OpenSSL 1.1.0+ supports AF_ALG natively but prior versions require out-of-tree engine plugin to be built
  • - GnuTLS does not have support for AF_ALG
  • - not many examples
  • - higher latency compared to cryptodev

Example native code:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/if_alg.h>
#include <linux/socket.h>
#define SHA256_DIGEST_SZ 32

int main(void)
{
        struct sockaddr_alg sa = {
                .salg_family = AF_ALG,
                .salg_type = "hash",
                .salg_name = "sha256"
        };
        unsigned char digest[SHA256_DIGEST_SZ];
        char *input = "Hello World!";
        int i, sockfd, fd;
        sockfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        bind(sockfd, (struct sockaddr *)&sa, sizeof(sa));
        fd = accept(sockfd, NULL, 0);
        write(fd, input, strlen(input));
        read(fd, digest, SHA256_DIGEST_SZ);
        close(fd);
        close(sockfd);
        for (i = 0; i < SHA256_DIGEST_SZ; i++)
                printf("%02x", digest[i]);
        printf("\n");
        return 0;
}
  • use the splice() call to push data
  • page-align the buffers with payloads

Cryptodev

The Cryptodev-linux kernel module has to be compiled as it is not part of the kernel tree. It is API compatible with OpenBSD's Cryptographic Framework (OCF or /dev/crypto) and it is GPLv2 licensed which means one day it could be included directly in the linux kernel. It enables userspace application access to the Crytpo API backend modules already present in the kernel.

Comparison to AF_ALG (+ indicates pro, - indicates con):

  • Supports CIPHER, HASH, AEAD
  • users character device interface (/dev/crypto)
  • + compatible with OpenBSP /dev/crytpo (API compatible, not code compatible)
  • + OpenSSL has engine for cryptodev
  • + GnuTLS has support for cryptodev
  • + nice examples (in the examples directory of the linux kernel driver source)
  • + lower latency than AF_ALG
  • - out of tree kernel driver (for years now)
  • - Adds arbitrary IOCTLs
  • - Synchronous only

Even though cryptodev is out-of-tree its quite easy to compile it against your kernel:

  • In general:
    tar xvf crptodev-linux-*.tar.gz
    make
    insmod cryptodev.ko
    
  • Example cross compiling on host for Newport via Newport BSP:
    cd newport
    . ./setup-environment # activate cross-compile shell environment
    git clone https://github.com/cryptodev-linux/cryptodev-linux.git -b cryptodev-linux-1.10
    KERNEL_DIR=$PWD/linux make -C cryptodev-linux
    KERNEL_DIR=$PWD/linux DESTDIR=$PWD/linux/install INSTALL_MOD_PATH=$PWD/linux/install make -C cryptodev-linux install
    tar cvzf cryptodev-linux.tar.gz -C $PWD/linux/install lib/modules/4.20.7-00006-gaf078a3/extra/cryptodev.ko usr/local/include/crypto/cryptodev.h
    

For examples using the cryptodev API via /dev/crypto see the cryptodev-linux/examples:

References:

OpenSSL library

Instead of accessing crypto functions directly via CPU instructions or the kernel APIs, we opted to use the OpenSSL library to wrap that functionality for us. There are a few steps to enable OpenSSL for each kernel API.

https://image.slidesharecdn.com/slideshare-linuxcrypto-160411115704/95/slideshare-linux-crypto-4-638.jpg

To see what engine support exists in OpenSSL use the openssl engine command:

root@bionic-armhf:~/openssl-1.1.0g# openssl engine
(cryptodev) BSD cryptodev engine
(dynamic) Dynamic engine loading support
  • the above shows that dynamic engine loading is supported as well as the cryptodev engine

To evaluate performance vs CPU load tradeoff use the openssl speed command:

  • Example: GW6304 (IMX6Q@1.2GHz)
    root@bionic-armhf:~/openssl-1.1.0g# openssl speed -evp aes-128-cbc -elapsed
    You have chosen to measure elapsed time instead of user CPU time.
    Doing aes-128-cbc for 3s on 16 size blocks: 27715 aes-128-cbc's in 3.00s
    Doing aes-128-cbc for 3s on 64 size blocks: 27570 aes-128-cbc's in 3.00s
    Doing aes-128-cbc for 3s on 256 size blocks: 27010 aes-128-cbc's in 3.00s
    Doing aes-128-cbc for 3s on 1024 size blocks: 23792 aes-128-cbc's in 3.00s
    Doing aes-128-cbc for 3s on 8192 size blocks: 9095 aes-128-cbc's in 3.00s
    Doing aes-128-cbc for 3s on 16384 size blocks: 4963 aes-128-cbc's in 3.00s
    OpenSSL 1.1.0g  2 Nov 2017
    built on: reproducible build, date unspecified
    options:bn(64,32) rc4(char) des(long) aes(partial) blowfish(ptr) 
    compiler: gcc -DDSO_DLFCN -DHAVE_DLFCN_H -DNDEBUG -DOPENSSL_THREADS -DOPENSSL_NO_STATIC_ENGINE -DOPENSSL_PIC -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DPOLY1305_ASM -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS -DOPENSSLDIR="\"/usr/lib/ssl\"" -DENGINESDIR="\"/usr/lib/arm-linux-gnueabihf/engines-1.1\"" 
    The 'numbers' are in 1000s of bytes per second processed.
    type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes
    aes-128-cbc        147.81k      588.16k     2304.85k     8121.00k    24835.41k    27104.60k
    root@bionic-armhf:~/openssl-1.1.0g# openssl speed -evp aes-128-cbc -engine cryptodev
    engine "cryptodev" set.
    Doing aes-128-cbc for 3s on 16 size blocks: 27750 aes-128-cbc's in 0.19s
    Doing aes-128-cbc for 3s on 64 size blocks: 27562 aes-128-cbc's in 0.04s
    Doing aes-128-cbc for 3s on 256 size blocks: 26970 aes-128-cbc's in 0.06s
    Doing aes-128-cbc for 3s on 1024 size blocks: 23868 aes-128-cbc's in 0.08s
    Doing aes-128-cbc for 3s on 8192 size blocks: 9045 aes-128-cbc's in 0.01s
    Doing aes-128-cbc for 3s on 16384 size blocks: 4882 aes-128-cbc's in 0.05s
    OpenSSL 1.1.0g  2 Nov 2017
    built on: reproducible build, date unspecified
    options:bn(64,32) rc4(char) des(long) aes(partial) blowfish(ptr) 
    compiler: gcc -DDSO_DLFCN -DHAVE_DLFCN_H -DNDEBUG -DOPENSSL_THREADS -DOPENSSL_NO_STATIC_ENGINE -DOPENSSL_PIC -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DAES_ASM -DBSAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DPOLY1305_ASM -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS -DOPENSSLDIR="\"/usr/lib/ssl\"" -DENGINESDIR="\"/usr/lib/arm-linux-gnueabihf/engines-1.1\"" 
    The 'numbers' are in 1000s of bytes per second processed.
    type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes
    aes-128-cbc       2336.84k    44099.20k   115072.00k   305510.40k  7409664.00k  1599733.76k
    
  • Use -elapsed argument when evaluating software crypto to see how many operations within a wall time of 3s can be performed compared to how much CPU time and how many operations can be performed within a wall time of 3s when using a hardware crypto engine: The above test shows for 16 byte blocks of aes-128-cbs's you can get 27715 iterations within 3s with software crypto and 27750 iterations within the same 3s (wall-clock time) but only using 0.19s of CPU time (ever so slight of a performance boost but significantly less CPU use) which results in hardware crypto having a much higher bandwidth if you look at it in terms of what it can do in 3s of CPU time
  • Use -engine cryptodev to use the cryptodev engine (if available)
  • Use -engine af_alg to use the AF_ALG engine (if available)
  • Use -elapsed and no -engine param to use software crypto to show wall-clock time vs CPU time

OpenSSL with AF_ALG

OpenSSL added native AF_ALG support 1.1.0 (Aug 25 2016). If you are using a version prior to that you need to build a plugin for OpenSSL.

Note that a Linux v4.1 kernel or newer is required (AF_ALG was added in 2.6.38 but a newer feature of async support on a socket is needed which came with 'net: socket: add support for async operations' in v4.1).

Note that Ubuntu's OpenSSL does not enable AF_ALG support by default so you will still need to build/rebuild OpenSSL to enable it.

To build the out-of-tree OpenSSL af_alg plugin for OpenSSL versions prior to 1.1.0:

# install deps
apt install build-essential pkg-config libssl-dev
# build
git clone https://github.com/sarnold/af_alg.git
cd af_alg/
./autogen.sh
./configure
make
# install plugin to engines directory for currently installed libssl
DIR=$(dpkg -L libssl1.0.0 | grep engines$)
# openssl version -d # shows OPENSSLDIR
sudo cp libaf_alg.so $DIR
sudo chmod 644 $DIR/libaf_alg.so
openssl engine # show engines available
  • Note that this plugin is incompatible with OpenSSL 1.1.x and will fail to build for those versions due to API changes

Note that prior to OpenSSL 1.1.1 afalg is not enabled by default thus you need to rebuild it and add the 'enable-afalgeng' config option.

To ensure you are loading the kernel modules (af_alg, algif_hash, algif_skcipher):

  • load them on boot:
    # ensure these modules are loaded at bootup
    echo af_alg >> /etc/modules
    echo algif_hash >> /etc/modules
    echo algif_skcipher >> /etc/modules
    
  • load them for current boot:
    # load them now
    modprobe af_alg algif_hash algif_skcipher
    

OpenSSL performance can be tested with:

openssl engine # ensure af_alg is present
openssl speed -evp aes-128-cbc -engine af_alg -elapsed

OpenSSL with cryptodev

Because Cryptodev is not available by default on Linux distributions OpenSSL has to be compiled with additional flags to include support for them:

apt install build-essential pkg-config
wget https://www.openssl.org/source/openssl-1.1.1c.tar.gz
tar xvf openssl-*
cd openssl-*
./config -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS
make
make install
  • Additionally the sysroot should have the cryptodev header installed: /usr/include/crypto/cryptodev.h

Note that for Ubuntu / Debian Linux distros it is preferred to download source package, modify debian/rules and recompile the package:

apt install build-essential pkg-config ubuntu-dev-tools debhelper
apt-get build-dep openssl
apt-get source openssl
cd openssl-*/
sed -i -e "s/CONFARGS  =/CONFARGS = -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS/" debian/rules
dch -i "Enabled cryptodev support"
DEB_BUILD_OPTIONS=nocheck debuild # disable checks to avoid issue with api check failing
sudo dpkg -i ../openssl*.deb

To ensure you are loading the kernel module (cryptodev):

  • load them on boot:
    # ensure these modules are loaded at bootup
    echo cryptodev >> /etc/modules
    
  • load them for current boot:
    # load them now
    modprobe cryptodev
    

OpenSSL Testing:

openssl engine # show engines available - look for cryptodev
openssl version -f # show compiler flags openssl was built with; look for -DHAVE_CRYPTODEV -DUSE_CRYPTODEV_DIGESTS

OpenSSL performance can be tested with the 'openssl speed' command:

openssl speed -evp aes-128-cbc -engine cryptodev -elapsed
  • -elapsed argument is used so throughput measurements are against wall clock time rather than cpu time

References:

Gateworks BSP Support

The embedded linux community tends to prefer cryptodev so that is what we tend to support at Gateworks in our various BSP's:

  • Newport:
    • Ubuntu - software only (openssl needs to be rebuilt for cryptodev support)
    • OpenWrt - cryptodev
  • Ventana:
    • Ubuntu - software only (openssl needs to be rebuilt for cryptodev support)
    • OpenWrt - cryptodev
    • Yocto - cryptodev