Replacing PulseAudio with PipeWire

PipeWire is a multimedia server, best known for it’s video support in Wayland. It also provides an audio server which can replace PulseAudio. The appeal, for me at least, to switch over from PulseAudio to PipeWire stems from PipeWire’s better support of bluetooth audio, and especially support for modern A2DP codecs such as AptX, AptX HD and LDAC.

Starting with PipeWire 0.3.20 introduced native mSBC support. This profile support mSBC codec versus CSVD supported by the older HSP/HFP profiles. The difference is significant, as the CSVD only supported narrow band speech (NBS, 8kHz) compared with mSBC support for wide band speech (WBS, 16kHz). That is the difference between 90’s era call quality sound and modern call quality sound.

Update: PipeWire-0.3.30 made the replacement process simpler. See my updated post.

Installing PipeWire 0.3.23

As of writing this post, Debian Unstable only has PipeWire 0.3.19. We are going to install PipeWire from the experimental repo so we get the PipeWire 0.3.23 with the support for mSBC.

We start by enabling the experimental repo

$ sudo apt-add-repository "deb http://deb.debian.org/debian experimental main
$ sudo apt update

Install PipeWire from experimental:

$ sudo apt install -t experimental pipewire-audio-client-libraries libspa-0.2-bluetooth

(pipewire-audio-client-libraries will pull pipewire itself as a dependency)

Substituting PipeWire for PulseAudio

These instructions are based on the ones from Debian Wiki, Arch Wiki and Gentoo Wiki. Create the file

$ sudo touch /etc/pipewire/media-session.d/with-pulseaudio

It will instruct PipeWire to handle Bluetooth audio devices.

Copy the pipewire-pulse systemd service:

$ sudo cp /usr/share/doc/pipewire/examples/systemd/user/pipewire-pulse.{service,socket} /etc/systemd/user

Disable PulseAudio services and enable the PipeWire ones

$ systemctl --user disable pulseaudio.socket pulseaudio.service
$ systemctl --user stop pulseaudio.socket pulseaudio.service
$ systemctl --user enable pipewire pipewire-pulse
$ systemctl --user start pipewire pipewire-pulse

If everything worked well pactl info should report Server Name: PulseAudio (on PipeWire 0.3.23):

$ pactl info | grep "Server Name"
Server Name: PulseAudio (on PipeWire 0.3.23)

If not, you might need to restart (PulseAudio tends to be rather persistent). In case PulseAudio still doesn’t play nicely, you should mask it:

$ systemctl --user mask pulseaudio.service pulseaudio.socket
$ systemctl --user stop pulseaudio.service pulseaudio.socket

Removing PulseAudio completely is not a good move at this point in time. Some packages depend on it, although they could work with PipeWire just as well. For example, when I remvoed PipeWire libcanberra-pulse got removed as well which caused system notification sounds to break. Alternatively you could try to replace the PulseAudio package with a dummy using equivs but that seems like more effort than keeping the package.

Enabling mSBC and SBC XQ

Edit /etc/pipewire/media-session.d/bluez-monitor.conf and uncomment the following lines:

bluez5.msbc-support   = true
bluez5.sbc-xq-support = true

This will enable both mSBC and SBC XQ.

You can test that you’re headset is connected via mSBC using pw-cli info:

$ guyru@gdebian3:~$ pw-cli info all | grep bluez
info: unsupported type PipeWire:Interface:Profiler
info: unsupported type PipeWire:Interface:Metadata
info: unsupported type PipeWire:Interface:Metadata
*		device.api = "bluez5"
*		device.name = "bluez_card.94_DB_56_AC_36_52"
*		api.bluez5.path = "/org/bluez/hci0/dev_94_DB_56_AC_36_52"
*		api.bluez5.address = "94:DB:56:AC:36:52"
*		api.bluez5.device = ""
*		api.bluez5.class = "0x240404"
*		api.bluez5.transport = ""
*		api.bluez5.profile = "headset-head-unit"
*		api.bluez5.codec = "mSBC"
*		api.bluez5.address = "94:DB:56:AC:36:52"
*		node.name = "bluez_input.94_DB_56_AC_36_52.headset-head-unit"
*		factory.name = "api.bluez5.sco.source"
*		device.api = "bluez5"
*		api.bluez5.transport = ""
*		api.bluez5.profile = "headset-head-unit"
*		api.bluez5.codec = "mSBC"
*		api.bluez5.address = "94:DB:56:AC:36:52"
*		node.name = "bluez_output.94_DB_56_AC_36_52.headset-head-unit"
*		factory.name = "api.bluez5.sco.sink"
*		device.api = "bluez5"

In case mSBC is not supported you’ll see api.bluez5.codec = "CSVD" (and you’lll probably hear the difference).

Errors

Problem: Connecting to bluetooth headset fails, and the following error appears in journalctl:

bluetoothd[41893]: src/service.c:btd_service_connect() a2dp-sink profile connect failed for 94:DB:56:AC:36:52: Protocol not available

Solution: You’re missing the libspa-0.2-bluetooth package. Install it and restart PipeWire:

$ sudo apt install -t experimental libspa-0.2-bluetooth
$ systemctl --user restart pipewire pipewire-pulse

Problem: ALSA programs fail with the following error:

ALSA lib pcm_dmix.c:1075:(snd_pcm_dmix_open) unable to open slave
aplay: main:830: audio open error: Device or resource busy

Solution: You need to enable the ALSA backend for PipeWire:

$ sudo touch /etc/pipewire/media-session.d/with-alsa
$ systemctl --user restart pipewire pipewire-pulse

Rename Debian packages according to version

This is a small bash utility function to allow renaming deb archives according to their version.

rename-deb () 
{ 
    base="${1%.deb}";
    version="$(dpkg-deb -f $1 Version)" || return 1;
    new="$base-$version.deb";
    mv -i "$1" "$new";
    echo "$1 -> $new"
}

You can either run it one time in your shell, or define it in your ~/.bash_aliases.

Example:

$ rename-deb zoom_amd64.deb
zoom_amd64.deb -> zoom_amd64-5.5.7011.0206.deb

Checking Thunderbolt security on Linux

Thunderbolt connections may provide DMA access to the host and pose a security risk. There are two mechanisms to mitigate against Thunderbolt DMA attacks in Linux, and you would probably want to verify at least one of them is active.

IOMMU DMA Protection

This uses IOMMU to explicitly allow what memory Thunderbolt devices can access via DMA. This is the prefered way to protect against Thunderbolt-based DMA attacks. It is available on recent hardware (~2018 and forward) and requires Kernel >= 5.0. You can verify IOMMU DMA Protection is enabled using:

cat /sys/bus/thunderbolt/devices/domain0/iommu_dma_protection
1

Value of 1 means it is enabled. This setting is controlled through UEFI. At least in Lenovo systems it is named cat "Kernel DMA Protection" (like the Microsoft name for this feature). You can find it under the Security tab.

Thunderbolt protection

This is the old style of protection, that preceded IOMMU protection. If configured properly, it allows the user to explicitly authorize Thunderbolt devices before granting them DMA access.

$ cat /sys/bus/thunderbolt/devices/domain0/security 
none

none means no protection at all (that will also be the case if you have IOMMU DMA protection enabled). user requires the user to authorize a Thunderbolt device each time it’s connected. secure is like user but devices authorized in the past do not require re-authorization. dponly only allow DisplayPort pass-through.

Quick crypto benchmarks

These are two easy ways to benchmark crypto operation speeds on a Linux machine. The first one is geared towards disk encryption operations:

$ /usr/sbin/cryptsetup benchmark 
# Tests are approximate using memory only (no storage IO).
PBKDF2-sha1      1691251 iterations per second for 256-bit key
PBKDF2-sha256    2144327 iterations per second for 256-bit key
PBKDF2-sha512    1615679 iterations per second for 256-bit key
PBKDF2-ripemd160  916587 iterations per second for 256-bit key
PBKDF2-whirlpool  701858 iterations per second for 256-bit key
argon2i       6 iterations, 1048576 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
argon2id      6 iterations, 1048576 memory, 4 parallel threads (CPUs) for 256-bit key (requested 2000 ms time)
#     Algorithm |       Key |      Encryption |      Decryption
        aes-cbc        128b      1209.7 MiB/s      3687.8 MiB/s
    serpent-cbc        128b        99.9 MiB/s       794.0 MiB/s
    twofish-cbc        128b       230.1 MiB/s       421.7 MiB/s
        aes-cbc        256b       937.9 MiB/s      2944.4 MiB/s
    serpent-cbc        256b       104.2 MiB/s       794.3 MiB/s
    twofish-cbc        256b       239.7 MiB/s       425.8 MiB/s
        aes-xts        256b      3634.5 MiB/s      3638.9 MiB/s
    serpent-xts        256b       762.0 MiB/s       747.9 MiB/s
    twofish-xts        256b       408.1 MiB/s       423.3 MiB/s
        aes-xts        512b      2956.6 MiB/s      2750.4 MiB/s
    serpent-xts        512b       746.9 MiB/s       752.9 MiB/s
    twofish-xts        512b       390.8 MiB/s       421.4 MiB/s

You can actually see how fast AES is compared to other block ciphers due to AES-NI.

The second is based on OpenSSL and provides by default a much more thorough benchmark:

$ openssl speed 
Doing md4 for 3s on 16 size blocks: 19471550 md4's in 3.00s
Doing md4 for 3s on 64 size blocks: 15103053 md4's in 3.00s
Doing md4 for 3s on 256 size blocks: 9059338 md4's in 3.00s
Doing md4 for 3s on 1024 size blocks: 3412145 md4's in 3.00s
Doing md4 for 3s on 8192 size blocks: 498545 md4's in 3.00s
Doing md4 for 3s on 16384 size blocks: 253216 md4's in 3.00s
Doing md5 for 3s on 16 size blocks: 28957162 md5's in 3.00s
Doing md5 for 3s on 64 size blocks: 16360429 md5's in 3.00s
Doing md5 for 3s on 256 size blocks: 7154365 md5's in 3.00s
Doing md5 for 3s on 1024 size blocks: 2218149 md5's in 3.00s
Doing md5 for 3s on 8192 size blocks: 297722 md5's in 3.00s
Doing md5 for 3s on 16384 size blocks: 147715 md5's in 3.00s
Doing hmac(md5) for 3s on 16 size blocks: 11929825 hmac(md5)'s in 3.00s
Doing hmac(md5) for 3s on 64 size blocks: 9120709 hmac(md5)'s in 3.00s
Doing hmac(md5) for 3s on 256 size blocks: 5318155 hmac(md5)'s in 3.00s
Doing hmac(md5) for 3s on 1024 size blocks: 2001226 hmac(md5)'s in 3.00s
Doing hmac(md5) for 3s on 8192 size blocks: 291987 hmac(md5)'s in 3.00s
Doing hmac(md5) for 3s on 16384 size blocks: 148269 hmac(md5)'s in 3.00s
Doing sha1 for 3s on 16 size blocks: 32235670 sha1's in 3.00s
Doing sha1 for 3s on 64 size blocks: 18479233 sha1's in 3.00s
Doing sha1 for 3s on 256 size blocks: 9153365 sha1's in 3.00s
Doing sha1 for 3s on 1024 size blocks: 3007449 sha1's in 3.00s
Doing sha1 for 3s on 8192 size blocks: 417697 sha1's in 3.00s
Doing sha1 for 3s on 16384 size blocks: 209985 sha1's in 3.00s
Doing sha256 for 3s on 16 size blocks: 17740446 sha256's in 3.00s
Doing sha256 for 3s on 64 size blocks: 9850795 sha256's in 3.00s
Doing sha256 for 3s on 256 size blocks: 4567892 sha256's in 3.00s
Doing sha256 for 3s on 1024 size blocks: 1408055 sha256's in 3.00s
Doing sha256 for 3s on 8192 size blocks: 190363 sha256's in 3.00s
Doing sha256 for 3s on 16384 size blocks: 95699 sha256's in 3.00s
Doing sha512 for 3s on 16 size blocks: 12097608 sha512's in 3.00s
Doing sha512 for 3s on 64 size blocks: 12203513 sha512's in 3.00s
Doing sha512 for 3s on 256 size blocks: 5178856 sha512's in 3.00s
Doing sha512 for 3s on 1024 size blocks: 1948042 sha512's in 3.00s
Doing sha512 for 3s on 8192 size blocks: 280301 sha512's in 3.00s
Doing sha512 for 3s on 16384 size blocks: 140813 sha512's in 3.00s
Doing whirlpool for 3s on 16 size blocks: 8456994 whirlpool's in 3.00s
Doing whirlpool for 3s on 64 size blocks: 4540393 whirlpool's in 3.00s
Doing whirlpool for 3s on 256 size blocks: 1868465 whirlpool's in 3.00s
Doing whirlpool for 3s on 1024 size blocks: 544008 whirlpool's in 2.99s
Doing whirlpool for 3s on 8192 size blocks: 74183 whirlpool's in 3.00s
Doing whirlpool for 3s on 16384 size blocks: 37414 whirlpool's in 3.00s
Doing rmd160 for 3s on 16 size blocks: 10071219 rmd160's in 3.00s
Doing rmd160 for 3s on 64 size blocks: 6032766 rmd160's in 3.00s
Doing rmd160 for 3s on 256 size blocks: 2779084 rmd160's in 3.00s
Doing rmd160 for 3s on 1024 size blocks: 880524 rmd160's in 3.00s
Doing rmd160 for 3s on 8192 size blocks: 118235 rmd160's in 3.00s
Doing rmd160 for 3s on 16384 size blocks: 59732 rmd160's in 3.00s
Doing rc4 for 3s on 16 size blocks: 148607832 rc4's in 3.00s
Doing rc4 for 3s on 64 size blocks: 39326183 rc4's in 3.00s
Doing rc4 for 3s on 256 size blocks: 8165860 rc4's in 3.00s
Doing rc4 for 3s on 1024 size blocks: 1913512 rc4's in 3.00s
Doing rc4 for 3s on 8192 size blocks: 236942 rc4's in 3.00s
Doing rc4 for 3s on 16384 size blocks: 117673 rc4's in 3.00s
Doing des cbc for 3s on 16 size blocks: 16847525 des cbc's in 3.00s
Doing des cbc for 3s on 64 size blocks: 4335887 des cbc's in 3.00s
Doing des cbc for 3s on 256 size blocks: 1087088 des cbc's in 3.00s
Doing des cbc for 3s on 1024 size blocks: 273049 des cbc's in 3.00s
Doing des cbc for 3s on 8192 size blocks: 34202 des cbc's in 3.00s
Doing des cbc for 3s on 16384 size blocks: 17021 des cbc's in 3.00s
Doing des ede3 for 3s on 16 size blocks: 6477330 des ede3's in 3.00s
Doing des ede3 for 3s on 64 size blocks: 1630515 des ede3's in 3.00s
Doing des ede3 for 3s on 256 size blocks: 408304 des ede3's in 3.00s
Doing des ede3 for 3s on 1024 size blocks: 101953 des ede3's in 3.00s
Doing des ede3 for 3s on 8192 size blocks: 12744 des ede3's in 2.99s
Doing des ede3 for 3s on 16384 size blocks: 6395 des ede3's in 3.00s
Doing aes-128 cbc for 3s on 16 size blocks: 50546274 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 64 size blocks: 13358038 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 256 size blocks: 3333758 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 1024 size blocks: 842151 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 8192 size blocks: 104943 aes-128 cbc's in 3.00s
Doing aes-128 cbc for 3s on 16384 size blocks: 52871 aes-128 cbc's in 3.00s
Doing aes-192 cbc for 3s on 16 size blocks: 44629776 aes-192 cbc's in 3.00s
Doing aes-192 cbc for 3s on 64 size blocks: 11527573 aes-192 cbc's in 3.00s
Doing aes-192 cbc for 3s on 256 size blocks: 2861904 aes-192 cbc's in 3.00s
Doing aes-192 cbc for 3s on 1024 size blocks: 719848 aes-192 cbc's in 3.00s
Doing aes-192 cbc for 3s on 8192 size blocks: 90802 aes-192 cbc's in 3.00s
Doing aes-192 cbc for 3s on 16384 size blocks: 45435 aes-192 cbc's in 3.00s
Doing aes-256 cbc for 3s on 16 size blocks: 39272215 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 64 size blocks: 10093402 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 256 size blocks: 2504776 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 1024 size blocks: 637977 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 8192 size blocks: 79787 aes-256 cbc's in 3.00s
Doing aes-256 cbc for 3s on 16384 size blocks: 39202 aes-256 cbc's in 3.00s
Doing aes-128 ige for 3s on 16 size blocks: 47968696 aes-128 ige's in 3.00s
Doing aes-128 ige for 3s on 64 size blocks: 12904621 aes-128 ige's in 3.00s
Doing aes-128 ige for 3s on 256 size blocks: 3298776 aes-128 ige's in 3.00s
Doing aes-128 ige for 3s on 1024 size blocks: 839361 aes-128 ige's in 3.00s
Doing aes-128 ige for 3s on 8192 size blocks: 105162 aes-128 ige's in 3.00s
Doing aes-128 ige for 3s on 16384 size blocks: 52661 aes-128 ige's in 3.00s
Doing aes-192 ige for 3s on 16 size blocks: 42104801 aes-192 ige's in 3.00s
Doing aes-192 ige for 3s on 64 size blocks: 11153161 aes-192 ige's in 3.00s
Doing aes-192 ige for 3s on 256 size blocks: 2861637 aes-192 ige's in 3.00s
Doing aes-192 ige for 3s on 1024 size blocks: 714282 aes-192 ige's in 2.99s
Doing aes-192 ige for 3s on 8192 size blocks: 89697 aes-192 ige's in 3.00s
Doing aes-192 ige for 3s on 16384 size blocks: 45105 aes-192 ige's in 3.00s
Doing aes-256 ige for 3s on 16 size blocks: 37372904 aes-256 ige's in 3.00s
Doing aes-256 ige for 3s on 64 size blocks: 9876719 aes-256 ige's in 3.00s
Doing aes-256 ige for 3s on 256 size blocks: 2494944 aes-256 ige's in 3.00s
Doing aes-256 ige for 3s on 1024 size blocks: 612649 aes-256 ige's in 3.00s
Doing aes-256 ige for 3s on 8192 size blocks: 78842 aes-256 ige's in 3.00s
Doing aes-256 ige for 3s on 16384 size blocks: 38146 aes-256 ige's in 3.00s
Doing ghash for 3s on 16 size blocks: 290449447 ghash's in 3.00s
Doing ghash for 3s on 64 size blocks: 279423358 ghash's in 3.00s
Doing ghash for 3s on 256 size blocks: 110269684 ghash's in 3.00s
Doing ghash for 3s on 1024 size blocks: 32100037 ghash's in 3.00s
Doing ghash for 3s on 8192 size blocks: 4100293 ghash's in 3.00s
Doing ghash for 3s on 16384 size blocks: 2050513 ghash's in 3.00s
Doing camellia-128 cbc for 3s on 16 size blocks: 25557277 camellia-128 cbc's in 3.00s
Doing camellia-128 cbc for 3s on 64 size blocks: 9739653 camellia-128 cbc's in 2.99s
Doing camellia-128 cbc for 3s on 256 size blocks: 2753092 camellia-128 cbc's in 3.00s
Doing camellia-128 cbc for 3s on 1024 size blocks: 705022 camellia-128 cbc's in 3.00s
Doing camellia-128 cbc for 3s on 8192 size blocks: 89548 camellia-128 cbc's in 3.00s
Doing camellia-128 cbc for 3s on 16384 size blocks: 44700 camellia-128 cbc's in 3.00s
Doing camellia-192 cbc for 3s on 16 size blocks: 22217978 camellia-192 cbc's in 3.00s
Doing camellia-192 cbc for 3s on 64 size blocks: 7553707 camellia-192 cbc's in 3.00s
Doing camellia-192 cbc for 3s on 256 size blocks: 2060504 camellia-192 cbc's in 3.00s
Doing camellia-192 cbc for 3s on 1024 size blocks: 531985 camellia-192 cbc's in 3.00s
Doing camellia-192 cbc for 3s on 8192 size blocks: 66556 camellia-192 cbc's in 3.00s
Doing camellia-192 cbc for 3s on 16384 size blocks: 32679 camellia-192 cbc's in 3.00s
Doing camellia-256 cbc for 3s on 16 size blocks: 22127633 camellia-256 cbc's in 3.00s
Doing camellia-256 cbc for 3s on 64 size blocks: 7448703 camellia-256 cbc's in 3.00s
Doing camellia-256 cbc for 3s on 256 size blocks: 1972494 camellia-256 cbc's in 3.00s
Doing camellia-256 cbc for 3s on 1024 size blocks: 529948 camellia-256 cbc's in 3.00s
Doing camellia-256 cbc for 3s on 8192 size blocks: 63902 camellia-256 cbc's in 3.00s
Doing camellia-256 cbc for 3s on 16384 size blocks: 33303 camellia-256 cbc's in 3.00s
Doing seed cbc for 3s on 16 size blocks: 19448527 seed cbc's in 2.96s
Doing seed cbc for 3s on 64 size blocks: 5086661 seed cbc's in 3.00s
Doing seed cbc for 3s on 256 size blocks: 1309579 seed cbc's in 3.00s
Doing seed cbc for 3s on 1024 size blocks: 326399 seed cbc's in 3.00s
Doing seed cbc for 3s on 8192 size blocks: 40847 seed cbc's in 2.97s
Doing seed cbc for 3s on 16384 size blocks: 20473 seed cbc's in 3.00s
Doing rc2 cbc for 3s on 16 size blocks: 11590538 rc2 cbc's in 3.00s
Doing rc2 cbc for 3s on 64 size blocks: 2993882 rc2 cbc's in 3.00s
Doing rc2 cbc for 3s on 256 size blocks: 756250 rc2 cbc's in 2.99s
Doing rc2 cbc for 3s on 1024 size blocks: 189369 rc2 cbc's in 3.00s
Doing rc2 cbc for 3s on 8192 size blocks: 23335 rc2 cbc's in 3.00s
Doing rc2 cbc for 3s on 16384 size blocks: 11620 rc2 cbc's in 3.00s
Doing blowfish cbc for 3s on 16 size blocks: 28823881 blowfish cbc's in 3.00s
Doing blowfish cbc for 3s on 64 size blocks: 7731814 blowfish cbc's in 3.00s
Doing blowfish cbc for 3s on 256 size blocks: 1819269 blowfish cbc's in 2.98s
Doing blowfish cbc for 3s on 1024 size blocks: 453845 blowfish cbc's in 2.96s
Doing blowfish cbc for 3s on 8192 size blocks: 59271 blowfish cbc's in 3.00s
Doing blowfish cbc for 3s on 16384 size blocks: 29739 blowfish cbc's in 3.00s
Doing cast cbc for 3s on 16 size blocks: 24843807 cast cbc's in 3.00s
Doing cast cbc for 3s on 64 size blocks: 7142122 cast cbc's in 3.00s
Doing cast cbc for 3s on 256 size blocks: 1720810 cast cbc's in 2.98s
Doing cast cbc for 3s on 1024 size blocks: 457591 cast cbc's in 2.99s
Doing cast cbc for 3s on 8192 size blocks: 56722 cast cbc's in 3.00s
Doing cast cbc for 3s on 16384 size blocks: 28285 cast cbc's in 3.00s
Doing rand for 3s on 16 size blocks: 3372230 rand's in 2.84s
Doing rand for 3s on 64 size blocks: 3356834 rand's in 2.75s
Doing rand for 3s on 256 size blocks: 3138476 rand's in 2.79s
Doing rand for 3s on 1024 size blocks: 2728751 rand's in 2.82s
Doing rand for 3s on 8192 size blocks: 1092880 rand's in 2.94s
Doing rand for 3s on 16384 size blocks: 651510 rand's in 2.96s
Doing 512 bits private rsa's for 10s: 290761 512 bits private RSA's in 10.00s
Doing 512 bits public rsa's for 10s: 4638554 512 bits public RSA's in 10.00s
Doing 1024 bits private rsa's for 10s: 134299 1024 bits private RSA's in 9.91s
Doing 1024 bits public rsa's for 10s: 1959617 1024 bits public RSA's in 9.98s
Doing 2048 bits private rsa's for 10s: 19348 2048 bits private RSA's in 9.99s
Doing 2048 bits public rsa's for 10s: 658878 2048 bits public RSA's in 10.00s
Doing 3072 bits private rsa's for 10s: 6641 3072 bits private RSA's in 10.01s
Doing 3072 bits public rsa's for 10s: 323266 3072 bits public RSA's in 10.00s
Doing 4096 bits private rsa's for 10s: 2972 4096 bits private RSA's in 10.00s
Doing 4096 bits public rsa's for 10s: 190751 4096 bits public RSA's in 10.00s
Doing 7680 bits private rsa's for 10s: 314 7680 bits private RSA's in 10.00s
Doing 7680 bits public rsa's for 10s: 54717 7680 bits public RSA's in 10.00s
Doing 15360 bits private rsa's for 10s: 60 15360 bits private RSA's in 10.08s
Doing 15360 bits public rsa's for 10s: 14720 15360 bits public RSA's in 10.00s
Doing 512 bits sign dsa's for 10s: 194123 512 bits DSA signs in 9.98s
Doing 512 bits verify dsa's for 10s: 278869 512 bits DSA verify in 10.00s
Doing 1024 bits sign dsa's for 10s: 113554 1024 bits DSA signs in 9.97s
Doing 1024 bits verify dsa's for 10s: 147432 1024 bits DSA verify in 10.00s
Doing 2048 bits sign dsa's for 10s: 45620 2048 bits DSA signs in 9.98s
Doing 2048 bits verify dsa's for 10s: 49758 2048 bits DSA verify in 10.00s
Doing 160 bits sign ecdsa's for 10s: 56221 160 bits ECDSA signs in 9.98s 
Doing 160 bits verify ecdsa's for 10s: 59458 160 bits ECDSA verify in 10.00s
Doing 192 bits sign ecdsa's for 10s: 47616 192 bits ECDSA signs in 9.98s 
Doing 192 bits verify ecdsa's for 10s: 47970 192 bits ECDSA verify in 10.00s
Doing 224 bits sign ecdsa's for 10s: 210941 224 bits ECDSA signs in 9.99s 
Doing 224 bits verify ecdsa's for 10s: 96849 224 bits ECDSA verify in 10.00s
Doing 256 bits sign ecdsa's for 10s: 520231 256 bits ECDSA signs in 9.91s 
Doing 256 bits verify ecdsa's for 10s: 173754 256 bits ECDSA verify in 9.99s
Doing 384 bits sign ecdsa's for 10s: 12826 384 bits ECDSA signs in 9.98s 
Doing 384 bits verify ecdsa's for 10s: 15207 384 bits ECDSA verify in 9.99s
Doing 521 bits sign ecdsa's for 10s: 39062 521 bits ECDSA signs in 9.99s 
Doing 521 bits verify ecdsa's for 10s: 19335 521 bits ECDSA verify in 10.00s
Doing 163 bits sign ecdsa's for 10s: 48363 163 bits ECDSA signs in 9.98s 
Doing 163 bits verify ecdsa's for 10s: 24392 163 bits ECDSA verify in 9.99s
Doing 233 bits sign ecdsa's for 10s: 34469 233 bits ECDSA signs in 9.97s 
Doing 233 bits verify ecdsa's for 10s: 17115 233 bits ECDSA verify in 9.97s
Doing 283 bits sign ecdsa's for 10s: 19982 283 bits ECDSA signs in 9.99s 
Doing 283 bits verify ecdsa's for 10s: 10045 283 bits ECDSA verify in 9.99s
Doing 409 bits sign ecdsa's for 10s: 11777 409 bits ECDSA signs in 10.00s 
Doing 409 bits verify ecdsa's for 10s: 6008 409 bits ECDSA verify in 10.00s
Doing 571 bits sign ecdsa's for 10s: 5447 571 bits ECDSA signs in 10.00s 
Doing 571 bits verify ecdsa's for 10s: 2799 571 bits ECDSA verify in 10.00s
Doing 163 bits sign ecdsa's for 10s: 46234 163 bits ECDSA signs in 9.97s 
Doing 163 bits verify ecdsa's for 10s: 23370 163 bits ECDSA verify in 9.99s
Doing 233 bits sign ecdsa's for 10s: 32597 233 bits ECDSA signs in 10.00s 
Doing 233 bits verify ecdsa's for 10s: 16665 233 bits ECDSA verify in 10.00s
Doing 283 bits sign ecdsa's for 10s: 19004 283 bits ECDSA signs in 9.99s 
Doing 283 bits verify ecdsa's for 10s: 9755 283 bits ECDSA verify in 9.98s
Doing 409 bits sign ecdsa's for 10s: 11207 409 bits ECDSA signs in 10.00s 
Doing 409 bits verify ecdsa's for 10s: 5814 409 bits ECDSA verify in 10.00s
Doing 571 bits sign ecdsa's for 10s: 5148 571 bits ECDSA signs in 9.99s 
Doing 571 bits verify ecdsa's for 10s: 2610 571 bits ECDSA verify in 10.00s
Doing 256 bits sign ecdsa's for 10s: 29886 256 bits ECDSA signs in 9.99s 
Doing 256 bits verify ecdsa's for 10s: 31093 256 bits ECDSA verify in 10.00s
Doing 256 bits sign ecdsa's for 10s: 29985 256 bits ECDSA signs in 9.99s 
Doing 256 bits verify ecdsa's for 10s: 32135 256 bits ECDSA verify in 9.99s
Doing 384 bits sign ecdsa's for 10s: 12609 384 bits ECDSA signs in 9.99s 
Doing 384 bits verify ecdsa's for 10s: 14306 384 bits ECDSA verify in 10.00s
Doing 384 bits sign ecdsa's for 10s: 12962 384 bits ECDSA signs in 9.99s 
Doing 384 bits verify ecdsa's for 10s: 15561 384 bits ECDSA verify in 10.00s
Doing 512 bits sign ecdsa's for 10s: 8564 512 bits ECDSA signs in 9.99s 
Doing 512 bits verify ecdsa's for 10s: 10422 512 bits ECDSA verify in 9.99s
Doing 512 bits sign ecdsa's for 10s: 8795 512 bits ECDSA signs in 10.00s 
Doing 512 bits verify ecdsa's for 10s: 10798 512 bits ECDSA verify in 9.99s
Doing 160 bits  ecdh's for 10s: 61839 160-bits ECDH ops in 10.00s
Doing 192 bits  ecdh's for 10s: 50575 192-bits ECDH ops in 9.99s
Doing 224 bits  ecdh's for 10s: 160868 224-bits ECDH ops in 10.00s
Doing 256 bits  ecdh's for 10s: 234630 256-bits ECDH ops in 10.00s
Doing 384 bits  ecdh's for 10s: 13245 384-bits ECDH ops in 10.00s
Doing 521 bits  ecdh's for 10s: 32844 521-bits ECDH ops in 10.00s
Doing 163 bits  ecdh's for 10s: 50343 163-bits ECDH ops in 9.97s
Doing 233 bits  ecdh's for 10s: 35536 233-bits ECDH ops in 9.99s
Doing 283 bits  ecdh's for 10s: 21057 283-bits ECDH ops in 9.99s
Doing 409 bits  ecdh's for 10s: 12564 409-bits ECDH ops in 10.00s
Doing 571 bits  ecdh's for 10s: 5707 571-bits ECDH ops in 10.00s
Doing 163 bits  ecdh's for 10s: 47944 163-bits ECDH ops in 9.99s
Doing 233 bits  ecdh's for 10s: 35651 233-bits ECDH ops in 9.98s
Doing 283 bits  ecdh's for 10s: 20495 283-bits ECDH ops in 9.97s
Doing 409 bits  ecdh's for 10s: 12072 409-bits ECDH ops in 10.00s
Doing 571 bits  ecdh's for 10s: 4908 571-bits ECDH ops in 9.97s
Doing 256 bits  ecdh's for 10s: 30134 256-bits ECDH ops in 9.99s
Doing 256 bits  ecdh's for 10s: 30999 256-bits ECDH ops in 9.99s
Doing 384 bits  ecdh's for 10s: 13382 384-bits ECDH ops in 10.00s
Doing 384 bits  ecdh's for 10s: 13593 384-bits ECDH ops in 10.00s
Doing 512 bits  ecdh's for 10s: 9110 512-bits ECDH ops in 10.00s
Doing 512 bits  ecdh's for 10s: 8964 512-bits ECDH ops in 9.99s
Doing 253 bits  ecdh's for 10s: 347784 253-bits ECDH ops in 10.00s
Doing 448 bits  ecdh's for 10s: 22735 448-bits ECDH ops in 9.99s
Doing 253 bits sign Ed25519's for 10s: 272233 253 bits Ed25519 signs in 10.00s 
Doing 253 bits verify Ed25519's for 10s: 101997 253 bits Ed25519 verify in 10.00s
Doing 456 bits sign Ed448's for 10s: 37378 456 bits Ed448 signs in 10.00s 
Doing 456 bits verify Ed448's for 10s: 20706 456 bits Ed448 verify in 10.00s
OpenSSL 1.1.1i  8 Dec 2020
built on: Tue Dec  8 19:32:32 2020 UTC
options:bn(64,64) rc4(16x,int) des(int) aes(partial) blowfish(ptr) 
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-dgP4jq/openssl-1.1.1i=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
The 'numbers' are in 1000s of bytes per second processed.
type             16 bytes     64 bytes    256 bytes   1024 bytes   8192 bytes  16384 bytes
md2                  0.00         0.00         0.00         0.00         0.00         0.00 
mdc2                 0.00         0.00         0.00         0.00         0.00         0.00 
md4             103848.27k   322198.46k   773063.51k  1164678.83k  1361360.21k  1382896.98k
md5             154438.20k   349022.49k   610505.81k   757128.19k   812979.54k   806720.85k
hmac(md5)        63625.73k   194575.13k   453815.89k   683085.14k   797319.17k   809746.43k
sha1            171923.57k   394223.64k   781087.15k  1026542.59k  1140591.27k  1146798.08k
rmd160           53713.17k   128699.01k   237148.50k   300552.19k   322860.37k   326216.36k
rc4             792575.10k   838958.57k   696820.05k   653145.43k   647009.62k   642651.48k
des cbc          89853.47k    92498.92k    92764.84k    93200.73k    93394.26k    92957.35k
des ede3         34545.76k    34784.32k    34841.94k    34799.96k    34916.00k    34925.23k
idea cbc             0.00         0.00         0.00         0.00         0.00         0.00 
seed cbc        105127.17k   108515.43k   111750.74k   111410.86k   112666.20k   111809.88k
rc2 cbc          61816.20k    63869.48k    64749.16k    64637.95k    63720.11k    63460.69k
rc5-32/12 cbc        0.00         0.00         0.00         0.00         0.00         0.00 
blowfish cbc    153727.37k   164945.37k   156286.20k   157005.84k   161849.34k   162414.59k
cast cbc        132500.30k   152365.27k   147827.97k   156713.44k   154888.87k   154473.81k
aes-128 cbc     269580.13k   284971.48k   284480.68k   287454.21k   286564.35k   288746.15k
aes-192 cbc     238025.47k   245921.56k   244215.81k   245708.12k   247949.99k   248135.68k
aes-256 cbc     209451.81k   215325.91k   213740.89k   217762.82k   217871.70k   214095.19k
camellia-128 cbc   136305.48k   208474.18k   234930.52k   240647.51k   244525.74k   244121.60k
camellia-192 cbc   118495.88k   161145.75k   175829.67k   181584.21k   181742.25k   178470.91k
camellia-256 cbc   118014.04k   158905.66k   168319.49k   180888.92k   174495.06k   181878.78k
sha256           94615.71k   210150.29k   389793.45k   480616.11k   519817.90k   522644.14k
sha512           64520.58k   260341.61k   441929.05k   664931.67k   765408.60k   769026.73k
whirlpool        45103.97k    96861.72k   159442.35k   186309.09k   202569.05k   204330.33k
aes-128 ige     255833.05k   275298.58k   281495.55k   286501.89k   287162.37k   287599.27k
aes-192 ige     224558.94k   237934.10k   244193.02k   244623.67k   244932.61k   246333.44k
aes-256 ige     199322.15k   210703.34k   212901.89k   209117.53k   215291.22k   208328.02k
ghash          1549063.72k  5961031.64k  9409679.70k 10956812.63k 11196533.42k 11198535.00k
rand             18998.48k    78122.68k   287974.86k   990865.61k  3045194.88k  3606195.89k
                  sign    verify    sign/s verify/s
rsa  512 bits 0.000034s 0.000002s  29076.1 463855.4
rsa 1024 bits 0.000074s 0.000005s  13551.9 196354.4
rsa 2048 bits 0.000516s 0.000015s   1936.7  65887.8
rsa 3072 bits 0.001507s 0.000031s    663.4  32326.6
rsa 4096 bits 0.003365s 0.000052s    297.2  19075.1
rsa 7680 bits 0.031847s 0.000183s     31.4   5471.7
rsa 15360 bits 0.168000s 0.000679s      6.0   1472.0
                  sign    verify    sign/s verify/s
dsa  512 bits 0.000051s 0.000036s  19451.2  27886.9
dsa 1024 bits 0.000088s 0.000068s  11389.6  14743.2
dsa 2048 bits 0.000219s 0.000201s   4571.1   4975.8
                              sign    verify    sign/s verify/s
 160 bits ecdsa (secp160r1)   0.0002s   0.0002s   5633.4   5945.8
 192 bits ecdsa (nistp192)   0.0002s   0.0002s   4771.1   4797.0
 224 bits ecdsa (nistp224)   0.0000s   0.0001s  21115.2   9684.9
 256 bits ecdsa (nistp256)   0.0000s   0.0001s  52495.6  17392.8
 384 bits ecdsa (nistp384)   0.0008s   0.0007s   1285.2   1522.2
 521 bits ecdsa (nistp521)   0.0003s   0.0005s   3910.1   1933.5
 163 bits ecdsa (nistk163)   0.0002s   0.0004s   4846.0   2441.6
 233 bits ecdsa (nistk233)   0.0003s   0.0006s   3457.3   1716.6
 283 bits ecdsa (nistk283)   0.0005s   0.0010s   2000.2   1005.5
 409 bits ecdsa (nistk409)   0.0008s   0.0017s   1177.7    600.8
 571 bits ecdsa (nistk571)   0.0018s   0.0036s    544.7    279.9
 163 bits ecdsa (nistb163)   0.0002s   0.0004s   4637.3   2339.3
 233 bits ecdsa (nistb233)   0.0003s   0.0006s   3259.7   1666.5
 283 bits ecdsa (nistb283)   0.0005s   0.0010s   1902.3    977.5
 409 bits ecdsa (nistb409)   0.0009s   0.0017s   1120.7    581.4
 571 bits ecdsa (nistb571)   0.0019s   0.0038s    515.3    261.0
 256 bits ecdsa (brainpoolP256r1)   0.0003s   0.0003s   2991.6   3109.3
 256 bits ecdsa (brainpoolP256t1)   0.0003s   0.0003s   3001.5   3216.7
 384 bits ecdsa (brainpoolP384r1)   0.0008s   0.0007s   1262.2   1430.6
 384 bits ecdsa (brainpoolP384t1)   0.0008s   0.0006s   1297.5   1556.1
 512 bits ecdsa (brainpoolP512r1)   0.0012s   0.0010s    857.3   1043.2
 512 bits ecdsa (brainpoolP512t1)   0.0011s   0.0009s    879.5   1080.9
                              op      op/s
 160 bits ecdh (secp160r1)   0.0002s   6183.9
 192 bits ecdh (nistp192)   0.0002s   5062.6
 224 bits ecdh (nistp224)   0.0001s  16086.8
 256 bits ecdh (nistp256)   0.0000s  23463.0
 384 bits ecdh (nistp384)   0.0008s   1324.5
 521 bits ecdh (nistp521)   0.0003s   3284.4
 163 bits ecdh (nistk163)   0.0002s   5049.4
 233 bits ecdh (nistk233)   0.0003s   3557.2
 283 bits ecdh (nistk283)   0.0005s   2107.8
 409 bits ecdh (nistk409)   0.0008s   1256.4
 571 bits ecdh (nistk571)   0.0018s    570.7
 163 bits ecdh (nistb163)   0.0002s   4799.2
 233 bits ecdh (nistb233)   0.0003s   3572.2
 283 bits ecdh (nistb283)   0.0005s   2055.7
 409 bits ecdh (nistb409)   0.0008s   1207.2
 571 bits ecdh (nistb571)   0.0020s    492.3
 256 bits ecdh (brainpoolP256r1)   0.0003s   3016.4
 256 bits ecdh (brainpoolP256t1)   0.0003s   3103.0
 384 bits ecdh (brainpoolP384r1)   0.0007s   1338.2
 384 bits ecdh (brainpoolP384t1)   0.0007s   1359.3
 512 bits ecdh (brainpoolP512r1)   0.0011s    911.0
 512 bits ecdh (brainpoolP512t1)   0.0011s    897.3
 253 bits ecdh (X25519)   0.0000s  34778.4
 448 bits ecdh (X448)   0.0004s   2275.8
                              sign    verify    sign/s verify/s
 253 bits EdDSA (Ed25519)   0.0000s   0.0001s  27223.3  10199.7
 456 bits EdDSA (Ed448)   0.0003s   0.0005s   3737.8   2070.6

Enable HTTP/2 in nginx

Enabling HTTP/2 in nginx is quite simple. You need to add the http2 parameter to the listen 443 directive. So find the line that looks like:

listen 443 ssl;

and change it into

listen 443 ssl http2;

And reload your nginx configuration:

$ sudo systemctl reload nginx.service 

Few notes:

  • You only need to enable http2 in one of your server blocks. You don’t need to do so for every virtual server (unless they use a different port). See here.
  • Don’t add http2 to your port 80. Browsers don’t support unencrypted.

Quickly generate lots of random data

What is the quickest way to generate lots of random data on the command line? Usually when I had to wipe hard-drives I would simply use dd to copy from /dev/urandom over the device. However, `/dev/urandom is quite slow and wiping hard-disks can take a long time that way. So, I decided to benchmark a few methods to generate long random streams that are usable in such scenarios.

The benchmark is based on the dd command. For example:

$ dd if=/dev/urandom of=/dev/null bs=4k count=1M

This command will copy a 4GB of random bytes from /dev/urandom over /dev/null. This is probably the simplest method to create a large stream of random bytes, and as it turns out, also the slowest.

The second construct I tried is to use OpenSSL to create a stream of random data which I can read with dd and then write to the target. For example the following would use AES-128 with a random key:

$ openssl rand -hex 32 | openssl enc -aes-128-ctr -in /dev/zero -pass stdin -nosalt | dd if=/dev/stdin of=/dev/null bs=4k count=1M

Let’s breakup this command: openssl rand -hex 32 will generate a random encryption key to be used by the AES encryption. openssl enc -aes-128-ctr -in /dev/zero -pass stdin -nosalt does the actual encryption. It reads the (random) key from stdin and then uses it to encrypt /dev/zero using AES-128 in counter mode. As /dev/zero in an endless stream of zeros, it will simply output an endless stream of (pseudo-)random data. We can also repeat the same command only swapping aes-128-ctr with aes-256-ctr. For most (all?) usage scenarios it doesn’t provided any added security benefits but does have a (small) performance penalty.

Apart from AES, which is a block cipher, we can also try to use actual stream ciphers like the old rc4 and the modern chacha20.

Additionally, many new CPUs come with AES-NI extension which speeds up AES operations considerably. We can repeat the benchmark while disabling AES-NI to see how the different methods will perform if used a CPU that doesn’t support AES-NI.

Finally, I’ve repeated the test with /dev/zero as input, just to have an upper-limit in terms of performance to compare against.

Benchmark results
AES-NINo AES-NI
/dev/zero0.42609
/dev/urandom18.8967
chacha202.693063.79217
aes-128-ctr2.0410614.9022
aes-256-ctr2.2475618.9014
rc47.77392
Benchmark results, time (in seconds) to create 4GB of random data

Conclusions

The results clearly show that you should avoid /dev/urandom. It’s simply not suitable for this task and doesn’t perform well. The various methods of using OpenSSL perform much better. The best performance is achieved by the two AES variants, with aes-128-ctr being the fastest. However, if AES-NI is not supported by the CPU, AES takes a huge performance hit, and is even slower than the (not-so-)good and old RC4. However, ChaCha20 (a modern stream cipher) performs within 30% of AES if AES-NI is available, but if AES-NI is not supported ChaCha20 outperforms the AES variants. So, unless you know AES-NI is supported ChaCha20 is the safe choice.

Fix missing icons in digiKam

It looks like digiKam installed on a default Gnome environment has missing icons. For example the "pick" icons (the little flags for Rejected/Pending/Accepted) are missing. The reason is that the default Gnome icon pack, Adwaita is missing some of the icons used by digiKam.

The solution is to install the Breeze icon theme and then select it in digiKam:

$ sudo apt install breeze-icon-theme

and then in digikam Settings -> Configure digiKam -> Miscellaneous -> Appearance -> Icon theme and select "Breeze". Actually you can leave it as "Use Icon Theme From System" and it will use Adwaita and only fall back to Breeze for missing icons. However, I do find it more pleasant to have a consistent icon theme.

Short cryptsetup/LUKS tutorial

This short tutorial will guide you in encrypting a drive with cryptsetup and LUKS scheme.

Before starting, if the device had previous data on it, it’s best to delete any filesystem signatures that may be on it. Assuming that the drive we operate is /dev/sda you can use the following command to remove the signatures:

$ sudo wipefs --all /dev/sda --no-act

Remove the --no-act flag to actually modify the disk.

The next step is to actually format the drive using LUKS. This is done using the cryptsetup utility.

$ sudo cryptsetup luksFormat --type=luks2 /dev/sda

WARNING!
========
This will overwrite data on /dev/sda irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/sda: 
Verify passphrase: 

The command will prompt you to enter a passphrase for the encryption and should take a few seconds to complete.

The next step is to add an appropriate entry to crypttab which will simplify starting the dm-crypt mapping later. Add the following line to /etc/crypttab:

archive_crypt UUID=114d42e5-6aeb-4af0-8758-b4cc79dd1ba0 none luks,discard,noauto

where the UUID is obtained through lsblk /dev/sda -o UUID or a similar command. The archive_crypt is the name for the mapped device. It will appear as /dev/mapper/archive_crypt when the device is mapped. The none parameter specifies that no keyfile is used and the system should prompt for an encryption passphrase instead. The noauto, means not to attempt to load the device automatically upon boot. discard should be used if the underlying device is an SSD.

You can test everything works so far by opening and loading the LUKS device:

$ sudo cryptdisks_start archive_crypt

While the device is now encrypted, there is a possible leakage of metadata such as used blocks as an attacker can discern used vs unused blocks by examining the physical drive. This and other side-channel leaks can be mitigated by simply wiping the contents of the encrypted device.

$ openssl rand -hex 32 | openssl enc -chacha20 -in /dev/zero -pass stdin -nosalt | sudo dd if=/dev/stdin of=/dev/mapper/sda_crypt bs=4096 status=progress

We could also have used /dev/urandom but the above technique is much faster.

Now we can create the actual filesystem.

$ sudo mkfs.btrfs --label archive /dev/mapper/archive_crypt

At this point we’re actually pretty much done. You can add and entry to /etc/fstab to easily mount the filesystem and you’re done.

/dev/mapper/archive_crypt /home/guyru/archive btrfs noauto,user 0 0

Gave up waiting for suspend/resume device

My boot process was pretty slow in a new setup I had. It would stop for about 30 seconds and then give the following error:

Gave up waiting for suspend/resume device

Turns out I had a resumable device listed in /etc/initramfs-tools/conf.d/resume even though my swap is both encrypted with random keys and too small. Editing that file and setting RESUME=none and running sudo update-initramfs -u fixed the issue.

Fixing Zoom’s Screen Sharing on Debian Unstable

Zoom has a native Linux client which supports screen sharing in Wayland, at least on some platforms. Today when I tried to start a Share Screen I encountered the following error:

Error when trying to start Share Screen

Can not start share, we only support Wayland on GNOME with Ubuntu 17 and above, Fedora 25 and above, Debian 9 and above, CentOS 8 and above, OpenSUSE Leap 15 and above, Oracle Linux 8 and above, Arch Linux, AnterGos, Manjaro. If your OS is not on the list, please use x11 instead.

The feature works for me when I’m using Debian Stable (Buster), and also worked for the short while I’ve used Debian Testing (Bullseye). So, I guessed that the feature is broken due to wrong OS version detection. The fix is easy: Remove /etc/os-release (which is by default a symlink to /usr/lib/os-release) and append to the original contents the following lines:

VERSION_ID="99"
VERSION="99 (sid)"
VERSION_CODENAME="sid"

So the entire file should look like:

PRETTY_NAME="Debian GNU/Linux bullseye/sid"
NAME="Debian GNU/Linux"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
VERSION_ID="99"
VERSION="99 (sid)"
VERSION_CODENAME="sid"

Why it works?

When I first encountered the error, I guessed Zoom doesn’t actually attempt the Share Screen, but relies on a pre-configured list of supported distros and (minimal) versions. It worked for me with Debian Stable (10) and Testing (11), but what version number is Unstable? Debian Unstable doesn’t have a version number associated with it, so it must be the problem.

A quick strace revealed how Zoom retrieves the current distro name and version:

$ strace -f -tt zoom
...
107498 11:20:58.943764 openat(AT_FDCWD, "/etc/os-release", O_RDONLY|O_CLOEXEC
107513 11:20:58.943771 futex(0x565257f88760, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, {tv_sec=1592727659, tv_nsec=303765000}, FUTEX_BITSET_MATCH_ANY
107498 11:20:58.943779 <… openat resumed>) = 17
107498 11:20:58.943787 fcntl(17, F_SETFD, FD_CLOEXEC) = 0
107498 11:20:58.943802 fstat(17, {st_mode=S_IFREG|0644, st_size=200, …}) = 0
107498 11:20:58.943817 read(17, "PRETTY_NAME=\"Debian GNU/Linux bu"…, 200) = 200
...

As you can see Zoom reads (and probably later parses) the entire /etc/os-release file. This file contains identification data for the current running distro including name and version. Because Debian Sid doesn’t have the version variables set, Zoom erroneously misinterpret it as an old version instead of the newest. Thus, it refuses to enable the Share Screen feature. Adding the relevant version variables solves this issue.

See also: man os-release (5)