Crypto hardware acceleration
加密硬件加速
介绍
本文主要讲述如何在 OpenSSL 中使用加密硬件加速(crypto hardware acceleration)。许多互联网应用程序,如 OpenSSH 和 OpenVPN,依赖于 OpenSSL 进行加密/解密。因此,使用硬件实现可以加速加密速度,减少CPU使用率。
硬件支持
AT91SAM9G46、AT91SAM9CN11、AT91SAMA5D3、AT91SAMA5D4支持的加密算法。
前提条件
硬件加速是作为内核空间的驱动程序实现的。为了在用户空间应用程序中使用它,需要第三方内核模块将用户空间的请求转换到内核空间。它提供了用户空间使用的接口,OpenSSL 可以使用它。有两个候选项,一个是ocf-linux,另一个是 cryptodev-linux。还有一个名为 afalg 的第三个候选项,支持的算法较少。它们可以在 buildroot 中进行选择和构建。
cryptodev-linux
Cryptodev-linux 是一个允许访问 Linux 内核加密驱动程序的设备,从而允许用户空间应用程序利用硬件加速器。Cryptodev-linux 作为一个独立的模块实现,除了标准的Linux内核外,不需要其他依赖。它的 API 与 OpenBSD 的 cryptodev 用户空间 API(/dev/crypto)兼容。
ocf-linux
OCF-Linux 是 OpenBSD/FreeBSD Cryptographic Framework(OCF)的 Linux 移植版。
af_alg
从 OpenSSL 1.1.0 开始,可以使用 AF_ALG 引擎。AF_ALG 接口使用套接字来访问内核加密算法,因此您将不会看到与之关联的 /dev/crypto 接口。
构建openssl二进制文件和用户空间接口
openssl二进制文件
进入buildroot源代码目录:
make menuconfig
确保 openssl 二进制文件和相关的辅助脚本将被安装到目标文件系统中:
Target packages
--> Libraries
--> Crypto
--> cryptodev
--> openssl support (BR2_PACKAGE_OPENSSL [=y])
--> ssl library (<choice> [=y])
--> openssl (BR2_PACKAGE_LIBOPENSSL [=y])
进入buildroot源代码目录并选择cryptodev。可以在以下位置选择cryptodev-linux:
Target packages
--> Libraries
--> Crypto
--> cryptodev
如果你想使用ocf-linux,请选择它:
如果你想使用额外的openssl引擎,比如af_alg,请选择以下内容:
如果cryptodev已经构建并安装在根文件系统中,在板子启动时,输入以下命令:
modprobe cryptodev
一个设备节点 /dev/crypto 将会出现。如果没有出现,硬件驱动无法在用户空间程序中使用。
注意,Linux 内核必须在 buildroot 中启用。
内核配置
Atmel 硬件驱动必须在内核配置中启用。进入 Linux 源代码目录:
make menuconfig
Cryptographic API
--> Hardware crypto devices
以下配置将在 .config 文件中被启用:
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_ATMEL_AES=y
CONFIG_CRYPTO_DEV_ATMEL_TDES=y
CONFIG_CRYPTO_DEV_ATMEL_SHA=y
如果您将它们选择为模块,请在板子启动后输入以下命令:
modprobe atmel-sha
modprobe atmel-aes
modprobe atmel-tdes
硬件驱动加载完成后,算法将被注册到加密框架中。使用以下命令查看它们:
root@sama5d4ek:~# cat /proc/crypto | grep atmel
driver : atmel-ofb-tdes
driver : atmel-cfb32-tdes
driver : atmel-cfb16-tdes
driver : atmel-cfb8-tdes
driver : atmel-cfb-tdes
driver : atmel-cbc-tdes
driver : atmel-ecb-tdes
driver : atmel-ofb-des
driver : atmel-cfb32-des
driver : atmel-cfb16-des
driver : atmel-cfb8-des
driver : atmel-cfb-des
driver : atmel-cbc-des
driver : atmel-ecb-des
driver : atmel-sha512
driver : atmel-sha384
driver : atmel-sha224
driver : atmel-sha256
driver : atmel-sha1
driver : atmel-cfb64-aes
driver : atmel-ctr-aes
driver : atmel-cfb8-aes
driver : atmel-cfb16-aes
driver : atmel-cfb32-aes
driver : atmel-cfb-aes
driver : atmel-ofb-aes
driver : atmel-cbc-aes
driver : atmel-ecb-aes
应用
OpenSSL
OpenSSL 是一个实现安全套接字层(SSL)和传输层安全性协议以及全功能通用密码库的开源工具包。
我们将它与 cryptodev-linux 一起使用,它构建了 OpenSSL 与密码硬件驱动之间的链接。
当给定"speed"参数时,OpenSSL 可以执行基准测试。用于基准测试的其他参数包括:
-
evp:算法名称
- SHA:sha1, sha256, sha224, sha384, 和 sha512
- DES/TDES:des-cbc 和 des-ede3-cbc
- AES:aes-128-cbc, aes-192-cbc 和 aes-256-cbc
-
elapsed:性能计算考虑了用户空间和内核空间消耗的时间。不带此参数时,只使用用户空间时间。
-
mr:生成机器可读输出
Linux使用 “time” 命令来获取CPU负载。运行 OpenSSL 速度测试之前和之后,检查加密 IP 上的中断数目。
cat /proc/interrupts
CPU0
...
27: 0 atmel-aic5 12 Level atmel-sha
28: 0 atmel-aic5 9 Level atmel-aes
...
49: 0 atmel-aic5 11 Level atmel-tdes
记住中断的数量,然后运行 OpenSSL 速度测试。以下是使用 128 位密钥的 AES 的示例:
time -v openssl speed -evp aes-128-cbc -elapsed -mr
验证一下 AES IP 上中断的数量是否增加了:
cat /proc/interrupts
CPU0
...
27: 0 atmel-aic5 12 Level atmel-sha
28: 247 atmel-aic5 9 Level atmel-aes
...
49: 0 atmel-aic5 11 Level atmel-tdes
如果你想通过 afalg 加速算法,按照以下步骤操作:
time -v openssl speed -evp aes-128-cbc -engine afalg -elapsed -mr
验证 AES IP 上中断的数量是否增加:
CPU0
...
27: 0 atmel-aic5 12 Level atmel-sha
28: 495 atmel-aic5 9 Level atmel-aes
...
49: 0 atmel-aic5 11 Level atmel-tdes
OpenSSH
OpenSSH(OpenBSD Secure Shell)是一组计算机程序,使用 SSH 协议在计算机网络上提供加密通信会话。
对于测试,我们使用 “scp” 程序从 Atmel 板复制一个大小为 20M 字节的文件到PC,然后再从 PC 复制到 Atmel 板上。同时测试客户端和服务器模式。
使用 RSA 公钥进行加密。
为了减少内存访问对测量结果的影响,文件将复制到 /tmp 目录中。
此外,Atmel板和PC通过以太网电缆直接连接。
传递给scp的参数如下:
- -c:算法名称:aes128-cbc,aes192-cbc,aes256-cbc和3des-cbc。
- 源文件
- 目标文件
- -v:详细模式
以 AES 128 位密钥为例:
- Atmel 板是 SSH 客户端:命令从它上面执行:
- 从 Atmel 板到PC(写访问):
scp -v -c aes128-cbc /tmp/test_20M PC_user@PC_IP:/tmp
-
- 从PC到Atmel板(读取访问):
scp -v -c aes128-cbc PC_user@PC_IP:/tmp/test_20M /tmp/
- Atmel板是SSH服务器:命令从PC上执行:
- 从Atmel板到PC(读取访问):
scp -v -c aes128-cbc board_user@board_IP:/tmp/test_20M /tmp
-
- 从PC到Atmel板(写访问):
scp -v -c aes128-cbc /tmp/test_20M board_user@board_IP:/tmp
OpenVPN
OpenVPN是一款开源软件应用程序,实现了创建安全连接的虚拟专用网(VPN:Virtual Private Network)技术。OpenVPN 使用 OpenSSL 库来提供数据和控制通道的加密。
对于测试,我们正在使用Atmel板和PC之间的点对点连接。Atmel 板和 PC 通过以太网电缆直接连接。PC是服务器,而 Atmel 板是客户端。
服务器和客户端的配置文件是基于 OpenVPN 源代码中提供的示例配置文件:static-office.conf和static-home.conf。
Atmel板的配置文件:
- atmel-board.conf:
dev tun
#Server
remote 192.168.2.2
ifconfig 10.1.0.2 10.1.0.1
up ./atmel-board.up
secret static.key
script-security 3 system
no-replay
tun-mtu 60000
fragment 0
mssfix 0
- atmel-board.up:
#!/bin/sh
route add -net 10.0.0.0 netmask 255.255.255.0 gw $5
PC配置文件:
- PC.conf:
dev tun
ifconfig 10.1.0.1 10.1.0.2
up ./PC.up
secret static.key
script-security 3 system
no-replay
tun-mtu 60000
fragment 0
mssfix 0
- PC.up:
#!/bin/sh
route add -net 10.0.1.0 netmask 255.255.255.0 gw $5
为了更改加密算法,我们在 Atmel 板和 PC 的 OpenVPN 启动时添加以下参数:–cipher algorithm_name (DES-EDE3-CBC, AES-128-CBC和AES-256-CBC)。
此外,在 Atmel 板上,我们还添加以下参数给 OpenVPN,告诉它使用硬件加密驱动程序:–engine cryptodev。
AES 256位密钥示例:
- Atmel板
- 软件驱动程序:
openvpn --config atmel-board.conf --cipher AES-2 56-CBC
-
- 硬件驱动程序:
openvpn --config atmel-board.conf --engine cryptodev --cipher AES-2 56-CBC
- PC:
openvpn --config PC.conf --cipher AES-2 56-CBC
VPN建立后,使用"iperf"工具进行性能测试。测试包括客户端和服务器模式。
- 在服务器上执行的命令:
iperf -s
在客户端上执行的命令:
iperf -c server_IP
常见问题解答
问:硬件加速支持哪些算法?
答:SHA-1、SHA-224、SHA-256、SHA-384、SHA-512。DES、TDES、AES以及FIPS中定义的所有模式。
问:如何获取软件和硬件之间的性能比较?
答:在内核中禁用Atmel硬件驱动程序。加密框架将选择默认的软件实现。可以使用 OpenSSL 来获取性能比较,无论 Atmel 硬件驱动程序是否启用。
问:如何在自己的应用程序中使用密码接口?
答:cryptodev-linux 的文档中提供了几个示例,可以在你的应用程序中进行参考。
问:如何知道内核中是否使用了加密硬件加速?
答:执行以下命令,并检查注册算法的优先级。如果有多个相同的算法注册,内核将采用最高优先级。请确保没有其他算法的优先级高于Atmel 加密驱动程序的优先级。
root@buildroot:~# cat /proc/crypto
name : ofb(des3_ede)
driver : atmel-ofb-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 16
max keysize : 24
ivsize : 8
geniv : <default>
name : cfb32(des3_ede)
driver : atmel-cfb32-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 4
min keysize : 16
max keysize : 16
ivsize : 8
geniv : <default>
name : cfb16(des3_ede)
driver : atmel-cfb16-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 2
min keysize : 16
max keysize : 16
ivsize : 8
geniv : <default>
name : cfb8(des3_ede)
driver : atmel-cfb8-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 1
min keysize : 16
max keysize : 16
ivsize : 8
geniv : <default>
name : cfb(des3_ede)
driver : atmel-cfb-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 16
max keysize : 16
ivsize : 8
geniv : <default>
name : cbc(des3_ede)
driver : atmel-cbc-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 16
max keysize : 24
ivsize : 8
geniv : <default>
name : ecb(des3_ede)
driver : atmel-ecb-tdes
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 16
max keysize : 24
ivsize : 0
geniv : <default>
name : ofb(des)
driver : atmel-ofb-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 8
max keysize : 8
ivsize : 8
geniv : <default>
name : cfb32(des)
driver : atmel-cfb32-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 4
min keysize : 8
max keysize : 8
ivsize : 8
geniv : <default>
name : cfb16(des)
driver : atmel-cfb16-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 2
min keysize : 8
max keysize : 8
ivsize : 8
geniv : <default>
name : cfb8(des)
driver : atmel-cfb8-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 1
min keysize : 8
max keysize : 8
ivsize : 8
geniv : <default>
name : cfb(des)
driver : atmel-cfb-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 8
max keysize : 8
ivsize : 8
geniv : <default>
name : cbc(des)
driver : atmel-cbc-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 8
max keysize : 8
ivsize : 8
geniv : <default>
name : ecb(des)
driver : atmel-ecb-des
module : atmel_tdes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 8
max keysize : 8
ivsize : 0
geniv : <default>
name : sha512
driver : atmel-sha512
module : atmel_sha
priority : 100
refcnt : 1
selftest : passed
type : ahash
async : yes
blocksize : 128
digestsize : 64
name : sha384
driver : atmel-sha384
module : atmel_sha
priority : 100
refcnt : 1
selftest : passed
type : ahash
async : yes
blocksize : 128
digestsize : 48
name : sha224
driver : atmel-sha224
module : atmel_sha
priority : 100
refcnt : 1
selftest : passed
type : ahash
async : yes
blocksize : 64
digestsize : 28
name : sha256
driver : atmel-sha256
module : atmel_sha
priority : 100
refcnt : 1
selftest : passed
type : ahash
async : yes
blocksize : 64
digestsize : 32
name : sha1
driver : atmel-sha1
module : atmel_sha
priority : 100
refcnt : 1
selftest : passed
type : ahash
async : yes
blocksize : 64
digestsize : 20
name : cfb64(aes)
driver : atmel-cfb64-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : ctr(aes)
driver : atmel-ctr-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 16
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : cfb8(aes)
driver : atmel-cfb8-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 8
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : cfb16(aes)
driver : atmel-cfb16-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 2
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : cfb32(aes)
driver : atmel-cfb32-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 4
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : cfb(aes)
driver : atmel-cfb-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 16
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : ofb(aes)
driver : atmel-ofb-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 16
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : cbc(aes)
driver : atmel-cbc-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 16
min keysize : 16
max keysize : 32
ivsize : 16
geniv : <default>
name : ecb(aes)
driver : atmel-ecb-aes
module : atmel_aes
priority : 100
refcnt : 1
selftest : passed
type : ablkcipher
async : yes
blocksize : 16
min keysize : 16
max keysize : 32
ivsize : 0
geniv : <default>
name : stdrng
driver : krng
module : kernel
priority : 200
refcnt : 1
selftest : passed
type : rng
seedsize : 0
name : lzo
driver : lzo-generic
module : kernel
priority : 0
refcnt : 2
selftest : passed
type : compression
name : crc32c
driver : crc32c-generic
module : kernel
priority : 100
refcnt : 1
selftest : passed
type : shash
blocksize : 1
digestsize : 4
name : deflate
driver : deflate-generic
module : kernel
priority : 0
refcnt : 2
selftest : passed
type : compression
name : aes
driver : aes-generic
module : kernel
priority : 100
refcnt : 2
selftest : passed
type : cipher
blocksize : 16
min keysize : 16
max keysize : 32
name : des3_ede
driver : des3_ede-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : cipher
blocksize : 8
min keysize : 24
max keysize : 24
name : des
driver : des-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : cipher
blocksize : 8
min keysize : 8
max keysize : 8
name : sha384
driver : sha384-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 128
digestsize : 48
name : sha512
driver : sha512-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 128
digestsize : 64
name : sha224
driver : sha224-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 64
digestsize : 28
name : sha256
driver : sha256-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 64
digestsize : 32
name : sha1
driver : sha1-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 64
digestsize : 20
name : md5
driver : md5-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 64
digestsize : 16
name : md4
driver : md4-generic
module : kernel
priority : 0
refcnt : 1
selftest : passed
type : shash
blocksize : 64
digestsize : 16
Ref:
https://www.linux4sam.org/bin/view/Linux4SAM/CryptoConfig