保密性是计算机科学最重要的功能之一。如果电子保密突然崩溃为完全透明,我们将无法进行电子商务,我们将无法进行私密通信,我们过去的通信将全球可见,并且我们将在无数方面受到严重影响,这将从根本上改变我们的工作和生活能力。想想我们每天花多少时间使用密码、锁屏图案、无线钥匙和生物识别技术来维护我们的保密性,这些技术限制访问以保护我们以及它们失败的后果。
公钥密码系统构成了我们保密性的关键方面。每天都会进行数十亿次通过公共媒介建立私密通信的能力。如果出现能够揭示这种私密对话的技术,其后果将是无法估量的。
在量子计算领域,这样一种技术正在兴起。能够执行 Shor 算法 以直接威胁常用公钥方案(RSA、传统 Diffie-Hellman 和椭圆曲线)的潜在硬件可能比我们预期的更接近实现。D-Wave 公司 承诺交付 一台拥有 5,000 量子比特的绝热量子计算机,但这台机器无法直接运行 Shor 算法,但如果可以,TLS 和 SSH 将受到严重威胁。纠正我们的密码系统迫在眉睫。
与普遍存在的 CMOS 技术渗透到我们的电子设备中不同,量子逻辑 是一种截然不同的设计,它适应不确定性和不确定性,从“量子比特”的形式开始,量子比特是一种二元值,但违反直觉地可以同时为正和负。这些新型计算设备的威胁是非常真实的,以至于美国国家标准与技术研究院 发起了一项竞赛,以征集抗量子公钥密码系统。
在这种争议中,TinySSH,一个专注于嵌入式的极简 SSH 服务器,实现了一种混合密钥交换,涉及 NTRU Prime(NIST 竞赛中的 第二轮决赛入围者)与传统的 ed25519 椭圆曲线密钥相结合。这种方法允许 ed25519 密钥通常保持使用,但透明地添加了“量子前向保密”的外观。OpenSSH v8.0 采用了这种方法
commit dfd591618cdf2c96727ac0eb65f89cf54af0d97e
Author: djm@openbsd.org
Date: Mon Jan 21 10:20:12 2019 +0000
upstream: Add support for a PQC KEX/KEM:
sntrup4591761x25519-sha512@tinyssh.org using the Streamlined NTRU Prime
4591^761 implementation from SUPERCOP coupled with X25519 as a stop-loss. Not
enabled by default.
TinySSH 服务器严格遵守与 Daniel J. Bernstein 相关的密码学技术,主要依靠 chacha20-poly1305 处理 SSH 会话流量;不允许使用其他密码。同样,它也不允许密码登录,但要求用户 ed25519 密钥就位才能成功连接。这些约束可能看起来很严格,但它们也是最佳实践。
TinySSH 服务器可以补充或替换 Linux OpenSSH 守护程序,并且提供了使用 inetd
或 systemd 套接字激活执行此操作的说明。TinySSH 的极简主义立场也非常适合 Linux 容器设计,但要实现这一点需要一些技巧。
无论如何,NTRU 密钥交换已在 OpenSSH 中部署了足够长的时间,以至于普遍使用是一个合理的目标。它也 远远优于 ssh-rsa 密钥,ssh-rsa 密钥多年来一直是默认的 SSH2 用户和主机密钥类型,但现在由于依赖 SHA-1 而被严重削弱。虽然 TinySSH 的作者 Jan Mojžíš 暗示 NTRU 密钥交换尚未达到“准备好用于生产环境(包括后量子密码学)”的程度,但启用它肯定比继续依赖 ssh-rsa 更安全。
设计一个容器
一般来说,容器共享一个公共内核,但用户空间是分开的,这使它们与虚拟机区分开来。最直接的 Linux 容器可能从 BusyBox 开始。对于本练习,我获得了使用 musl libc(而不是 uclibc)编译的 1.31.0 版本。选择您合适的架构;我选择了标准的 x86_64 PC。
作为 root 用户,并将 BusyBox 复制到本地目录中,输入以下命令以组织和启动 /home/pqc
作为您的后量子容器
# mkdir -p /home/pqc/bin
# cp busybox-x86_64 /home/pqc/bin
# mkdir /home/pqc/root
# mkdir /home/pqc/ssh
# mkdir -p /home/pqc/var/log
# cd /home/pqc/bin
# chmod 755 busybox-x86_64
# ./busybox-x86_64 --list | awk '{print "ln -s busybox-x86_64 " $0}' | sh
# cd /home/pqc
# tar cf - /usr/share/zoneinfo | tar xvpf -
# ln -s bin sbin
# mkdir /home/pqc/etc
# echo 'NAME="Post-Quantum Container"' > /home/pqc/etc/os-release
# echo 'root::0:0:root:/root:/bin/sh' > /home/pqc/etc/passwd
# echo root:x:0: > /etc/group
# echo 'console::respawn:/bin/getty 38400 /dev/console' > /home/pqc/etc/inittab
# echo '::sysinit:/bin/syslogd' >> /home/pqc/etc/inittab
# echo '::sysinit:/bin/inetd' >> /home/pqc/etc/inittab
# echo 'tssh 2222/tcp' > /home/pqc/etc/services
# echo "tssh stream tcp nowait root /ssh/tinysshd tinysshd -lpsv \
-x sftp=/ssh/sftp-server /etc/tinyssh/sshkeydir" > /home/pqc/etc/inetd.conf
# systemd-nspawn -bD /home/pqc
在执行上面的最终 nspawn 命令后,将启动一个新的用户空间,允许您以 root 身份登录到模拟基本 Unix System V 的环境中
Spawning container pqc on /home/pqc.
Press ^] three times within 1s to kill container.
Jun 23 14:44:04 pqc syslog.info syslogd started: BusyBox v1.31.0
Jun 23 19:44:04 pqc daemon.info : starting pid 4, tty '': '/bin/inetd'
Jun 23 19:44:04 pqc daemon.err inetd[5]: tssh/tcp: unknown service
Jun 23 19:44:04 pqc daemon.info : starting pid 6, tty '/dev/console': '/bin/getty 38400 /dev/console'
pqc login: root
Jun 23 19:44:06 pqc auth.info login[6]: root login on 'console'
# ps
PID USER TIME COMMAND
1 root 0:00 init
3 root 0:00 /bin/syslogd
5 root 0:00 /bin/inetd
6 root 0:00 -sh
7 root 0:00 ps
#
上面的 inetd 守护程序配置为启动 TinySSH,TinySSH 尚未出现在您的容器镜像中。您可以构建 TinySSH 并返回到容器进行安装。
如果您从未见过 nspawn 容器,请花一些时间探索它,然后再继续。如果您想关闭它,请停止它
# halt
The system is going down NOW!
Sent SIGTERM to all processes
Jun 27 21:51:42 pqc daemon.info : The system is going down NOW!
Jun 27 16:51:42 pqc syslog.info syslogd exiting
Sent SIGKILL to all processes
Requesting system halt
Container pqc has been shut down.
小心不要意外停止主机。
如果您在上面的配置中为 root 帐户添加了密码,它将使用 /etc/passwd
文件中的旧 DES 哈希进行存储。只有 nspawn 控制台才允许密码登录;TinySSH 忽略密码。如果您更喜欢影子密码,请在容器内运行以下命令
# echo root:::::::: > /etc/shadow
# chmod 600 /etc/shadow
# passwd -a sha512 root
最终,您将希望禁用控制台 getty 并仅允许通过 TinySSH 登录。这可以通过注释掉 /home/pqc/etc/inittab
的第一行并为 systemd 放置以下服务文件来完成
# echo '[Unit]
Description=pqc container
[Service]
ExecStart=/usr/bin/systemd-nspawn -bD /home/pqc
' > /etc/systemd/system/pqc.service
您尚未准备好执行此操作。
构建 musl
可以通过各种机制在容器内使用 glibc 和现有主机代码。但是,这可能很困难,因为大多数程序中都有许多依赖项,复制起来可能很繁琐。以 Red Hat/CentOS 7 上的 sshd
服务器为例;将所有四十九个共享对象正确放置在容器中并非易事
$ ldd /usr/sbin/sshd
linux-vdso.so.1 => (0x00007ffeec564000)
libfipscheck.so.1 => /lib64/libfipscheck.so.1 (0x00007fafbfa3b000)
libwrap.so.0 => /lib64/libwrap.so.0 (0x00007fafbf830000)
libaudit.so.1 => /lib64/libaudit.so.1 (0x00007fafbf607000)
[...]
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007fafb978e000)
libattr.so.1 => /lib64/libattr.so.1 (0x00007fafb9589000)
libelf.so.1 => /lib64/libelf.so.1 (0x00007fafb9371000)
libbz2.so.1 => /lib64/libbz2.so.1 (0x00007fafb9161000)
musl C 库 允许在编译对象中大幅减少或完全消除运行时链接器依赖项。您可以至少使用它来构建功能正常的 TinySSH。
为了构建 musl,您必须安装 GNU C 编译器和相关工具。如果尚未加载它们,请以 root 身份运行以下命令来获取它们(在 Red Hat/CentOS 平台上)
# yum group install 'Development Tools'
下载 musl,然后解压缩并编译它,最好以非 root 用户身份
$ tar xvzf musl-1.2.0.tar.gz
$ cd musl-1.2.0/
$ ./configure
$ make
…然后,以 root 身份
# make install
大多数安装将在 /usr/local/musl
中进行,但 /lib/ld-musl-x86_64.so.1
除外(它在 /lib64
中会更一致,但当编译静态二进制文件时,这种奇怪的位置是无关紧要的)。
特别值得关注的是 /usr/local/musl/bin/musl-gcc
,这是一个简短的 shell 脚本,它使用带有备用 libc 链接的系统 C 编译器。
构建 TinySSH
TinySSH 在容器或基本操作系统安装中的灵活性需要构建过程中的细微变化,主要是将焦点从 glibc 转移到 musl,这并不困难。
处于各种淘汰阶段的旧系统也可以使用 TinySSH 来实现现代最佳实践密码。Red Hat/CentOS 5 可以很好地运行 TinySSH,但旧的 HP-UX 10.20 系统由于缺少 c99 支持而无法编译它。请注意,Red Hat/CentOS 8 包含支持 NTRU 的 OpenSSH 客户端和服务器;如果您的主机操作系统运行的是 OpenSSH v8 或更高版本,则 TinySSH 实际上仅适用于容器使用(在 Red Hat/CentOS 8 上启用 NTRU 密钥需要更改 /usr/share/crypto-policies/DEFAULT/opensshserver.txt
文件)。
下载 20190101.tar.gz
文件,并解压缩它
$ tar xvzf 20190101.tar.gz
$ cd tinyssh-20190101
没有 configure
步骤来执行构建,只需 make
$ make
sh -e make-tinyssh.sh
=== Sat Jun 27 18:00:33 CDT 2020 === obtaining compiler
=== Sat Jun 27 18:00:34 CDT 2020 === cc ok
=== Sat Jun 27 18:00:34 CDT 2020 === finishing
=== Sat Jun 27 18:00:34 CDT 2020 === checking compiler options
=== Sat Jun 27 18:00:34 CDT 2020 === -pedantic ok
[...]
=== Sat Jun 27 18:00:53 CDT 2020 === _tinyssh 6627
=== Sat Jun 27 18:00:53 CDT 2020 === 74069 words of code
=== Sat Jun 27 18:00:53 CDT 2020 === finishing
=== Sat Jun 27 18:00:53 CDT 2020 === counting words of code
=== Sat Jun 27 18:00:53 CDT 2020 === sysdep 936
=== Sat Jun 27 18:00:53 CDT 2020 === tinyssh 38680
=== Sat Jun 27 18:00:53 CDT 2020 === crypto 21330
=== Sat Jun 27 18:00:53 CDT 2020 === 60932 words of code
=== Sat Jun 27 18:00:53 CDT 2020 === finishing
这编译了一个 glibc 链接的 TinySSH,您可以显示依赖对象
$ ldd build/bin/tinysshd
linux-vdso.so.1 => (0x00007ffce33e1000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007f53ade04000)
libc.so.6 => /lib64/libc.so.6 (0x00007f53ada36000)
/lib64/ld-linux-x86-64.so.2 (0x00007f53ae007000)
此二进制文件在主机操作系统的 SSH 服务器上运行良好,但尝试将其放置在具有明显依赖项的 nspawn 环境中将因调用 getpwnam()
而失败。与其调试似乎是 glibc 名称服务交换机问题的原因,不如使用 musl 重建代码
make clean
CC='/usr/local/musl/bin/musl-gcc -static' make
ldd build/bin/tinysshd
上面命令的最终输出应该是“not a dynamic executable
”。
musl 库也支持使用动态共享对象,就像 glibc 一样。如果您正在 nspawn 中使用 musl 环境准备大量编译的 C 代码,请考虑在您的容器应用程序中使用共享库以减少内存消耗,甚至可以考虑重建 BusyBox 以使用共享对象。
无论如何,以 root 用户身份将静态 TinySSH 二进制文件移动到容器中
mv build/bin/tinysshd /home/pqc/ssh/
mv build/bin/tinysshd-makekey /home/pqc/ssh/
mv build/bin/tinysshd-printkey /home/pqc/ssh/
现在唯一缺少的是容器主机密钥和用户密钥。
安装密钥并测试登录
如果您之前停止了 pqc
容器,请重新启动它。确保您以 root 身份登录,并运行以下命令
mkdir /etc/tinyssh
/ssh/tinysshd-makekey /etc/tinyssh/sshkeydir
这将生成一个新的 ed25519 主机密钥。您可能更喜欢使用来自 OpenSSH 的现有密钥;这将在下面讨论。
此外,必须将 authorized_keys
文件安装到将托管登录的特定用户帐户中。如果您尚未生成此类密钥,请执行此操作。对于此测试用例,最好密钥没有密码
$ ssh-keygen -t ed25519 -f testkey
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in testkey.
Your public key has been saved in testkey.pub.
The key fingerprint is:
SHA256:tahsHrY5b0PqNMuxxDew35xS7FoLWNJ6VNOslUNCFao cfisher@yourhost.com
The key's randomart image is:
+--[ED25519 256]--+
| .o.+. |
| * . |
| = * |
| . = = . |
| o E.o |
| o X. o |
| /o=o. |
| Bo%+*.o |
| .O+++= |
+----[SHA256]-----+
将公钥安装到目标帐户中。此示例使用 root。如果您更喜欢非 root 目标,请创建用户并从 nspawn 控制台对其进行测试。将密钥安装到相应的容器目录中
# mkdir /home/pqc/root/.ssh
# cat testkey.pub >> /home/pqc/root/.ssh/authorized_keys
测试您的登录
# ssh -p 2222 -i testkey root@localhost
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
ED25519 key fingerprint is SHA256:1nnku5/Q8leUwnbB9mDcfPobvsQapj2JJA6FVVQjTJg.
ED25519 key fingerprint is MD5:bc:dc:b6:52:31:8a:59:1d:dc:c7:61:7c:2b:7c:37:01.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:2222' (ED25519) to the list of known hosts.
Enter passphrase for key 'testkey':
~ #
现在容器应该已准备好进行最佳实践 SSH 登录,可以选择使用 NTRU(可能)量子安全的密钥交换进行保护。
后量子登录和 sftp
NTRU 密钥的一个问题是,目前只有两个服务器和一个客户端实现了它们。如果您足够幸运,您的操作系统包含 OpenSSH v8 或更高版本,您可以直接测试 NTRU 交换
$ ssh -p 2222 -i testkey -o KexAlgorithms=sntrup4591761x25519-sha512@tinyssh.org root@localhost
如果您是许多未运行如此新版本的 OpenSSH 版本的 Linux 用户之一,您可以使用 musl 创建一个。我将在下面演示 OpenSSH 的其他组件(sftp-server、scp 等),因此即使是最新 OpenSSH 版本的用户也将有理由拥有 musl 版本。下载最新版本的 OpenSSH,然后使用以下命令执行 musl 构建
$ tar xvzf openssh-8.3p1.tar.gz
$ cd openssh-8.3p1
$ CC='/usr/local/musl/bin/musl-gcc -static' ./configure --without-openssl --without-zlib
$ make
在没有 OpenSSL 的情况下进行构建已经进行了很长时间的实验
$ ./configure --help | grep without-openssl | head -1
--without-openssl Disable use of OpenSSL; use only limited internal crypto **EXPERIMENTAL**
构建完成后立即测试 NTRU 登录
$ ./ssh -p 2222 -i ~/testkey -o KexAlgorithms=sntrup4591761x25519-sha512@tinyssh.org root@localhost
如果您使用的密钥带有密码,您可能会看到来自 musl 构建的 ssh 的以下错误
Load key "/home/cfisher/testkey": key encrypted using unsupported cipher
如果是这种情况,请将本机 ssh-agent
与 musl ssh
客户端一起使用,并删除稍后在 ssh
命令行上对密钥的 -i
引用
$ eval $(ssh-agent)
Agent pid 21067
$ ssh-add ~/testkey
Enter passphrase for /home/cfisher/testkey:
Identity added: /home/cfisher/testkey (cfisher@yourhost.com)
$ ./ssh -p 2222 \
-o KexAlgorithms=sntrup4591761x25519-sha512@tinyssh.org \
root@localhost
您可能已经注意到 inetd
对 TinySSH 的引用中提到了 sftp-server
。如果您想允许 sftp 或 scp,请将 musl 构建复制到容器中,并使用正在运行的代理测试登录(请注意我调用了 glibc sftp
)
# cp sftp-server /home/pqc/ssh
# cp scp /home/pqc/bin
$ echo 'put ssh-agent' | sftp -S ./ssh -o Port=2222 \
-o KexAlgorithms=sntrup4591761x25519-sha512@tinyssh.org \
root@localhost:/root
sftp 会话的输出应为
Connected to localhost.
Changing to: /root
sftp> put ssh-agent
Uploading ssh-agent to /root/ssh-agent
ssh-agent 100% 1054KB 14.6MB/s 00:00
现在不鼓励使用 scp discouraged,但它仍然可以使用。此示例假设代理正在运行
$ ./scp -S ./ssh -P 2222 -o KexAlgorithms=sntrup4591761x25519-sha512@tinyssh.org ssh root@localhost:/root
ssh 100% 2492KB 59.3MB/s 00:00
为 NTRU 选项设置 shell 别名可能会有所帮助
$ alias pqssh="/your/path/to/ssh \
-o KexAlgorithms=sntrup4591761x25519-sha512@tinyssh.org"
$ pqssh -i testkey -p 2222 root@localhost
如果应允许非本地主机登录到容器,则必须打开端口上的任何防火墙限制。一种方法是
iptables -w -I INPUT -p tcp --dport 2222 --syn -j ACCEPT
欢迎来到后量子密钥交换。
迁移主机密钥
如果您打算在 OpenSSH 和 TinySSH 服务器之间移动主机密钥,那么 TinySSH 密钥格式可能会成为问题,因为它不是 OpenSSH 期望的形式
# ls -al /home/pqc/etc/tinyssh/sshkeydir
total 8
drwxr-xr-x 1 root 0 42 Jun 27 18:36 .
drwxr-xr-x 1 root 0 18 Jun 27 18:36 ..
-rw------- 1 root 0 64 Jun 27 18:36 .ed25519.sk
-rw-r--r-- 1 root 0 32 Jun 27 18:36 ed25519.pk
tinysshd-printkey
实用程序只能打印公钥。将私钥移动到 OpenSSH 格式可能需要自定义代码,而这种代码似乎不存在。因此,tinysshd-makekey
实用程序对于生产主机密钥来说令人担忧。
最好维护主机密钥的 OpenSSH 兼容副本,并使用转换器生成 TinySSH 变体。当前的转换器 需要 Python 3(避免使用 旧的、基于 C 的 密钥转换器)。我在 Red Hat/CentOS 8 上加载了 Python 转换器
# python3 -m pip install tinyssh-keyconvert-0.3.2.zip
WARNING: Running pip install with root privileges is generally not a good idea. Try `__main__.py install --user` instead.
Processing ./tinyssh-keyconvert-0.3.2.zip
Installing collected packages: tinyssh-keyconvert
Running setup.py install for tinyssh-keyconvert ... done
Successfully installed tinyssh-keyconvert-0.3.2
OpenSSH ed25519 主机密钥通常存储在 /etc/ssh/ssh_host_ed25519_key
中,应在不使用密码的情况下创建。使用以下命令将此类密钥转换为 TinySSH 格式
$ tinyssh-keyconvert ssh_host_ed25519_key --dir .
$ ll ed25519.pk .ed25519.sk
-rw-r--r--. 1 fishecj itg 32 Jun 25 11:57 ed25519.pk
-rw-------. 1 fishecj itg 64 Jun 25 11:57 .ed25519.sk
将所有相关密钥复制到将使用它们的主机或容器。ssh_host_ed25519_key.pub
公钥不是严格必要的,因为可以使用 ssh-keygen -y
重新生成它。确保在安装完成后删除任何临时副本,因为丢失这些密钥将危及主机的通信安全
$ rm -i .ed25519.sk ed25519.pk ssh_host_ed25519_key
结论
对于上述方法存在许多反对意见。明显的反对意见包括:NTRU Prime 尚未获得官方认可;准备一个标准的 OpenSSH sshd
并不困难;TinySSH 不使用“权限分离”和/或 chroot();
;TinySSH 缺少重要功能(端口转发、sftp/scp、X11、VPN 等);应该执行更大的 musl SSH 构建,该构建不使用实验性功能。
关于官方 NTRU 认可,OpenSSH 打算在近期禁用 ssh-rsa。对于旧系统来说,这将是一次痛苦的变革,许多旧系统将留下孤立的 SSH 实现。随着这种程度的变革即将到来,应该施加压力以选择最佳可用密码系统,并且可以为包含 TinySSH NTRU Prime 提出理由。没有管理员希望这样做两次。
TinySSH 服务器的配置难度远低于 OpenSSH sshd
的完整实现。该服务器的作者声称“TinySSH 不可能配置错误”;sshd
则不然。易于管理是一个因素,尤其是在推广到许多服务器时。
TinySSH 的安全记录似乎非常干净,其设计避免了 C 语言的已知问题。此服务器强制执行用户的最佳实践,这可能既是安全优势,也是培训责任。也许最终,失去权限分离是一个合理的权衡。
用户很容易养成不良习惯,并依赖 OpenSSH 中异乎寻常或已弃用的功能。这些功能应谨慎地扩展到有经验且有证明需求的用户。
最后,如果仅将 scp
和/或 sftp-server
服务器组件与 TinySSH 一起使用,则实验性构建可能不相关。OpenSSL 也不包含任何 NTRU 实现,因此这方面可能不会受到任何降级
为了解决更大的问题,SSH 面临着 RSA 密钥立即弃用和转换的巨大动荡(这使得 TinySSH 决定省略 RSA 是明智之举)。忽视 NIST 在 2016 年提出且至今未解答的后量子问题,将愚蠢地浪费更广泛的 NTRU Prime 操作经验的机会,这将对 SSH 和 TLS 都有价值。NIST 于 2016 年启动了后量子密码学竞赛,最终草案计划于 2022-24 年完成。AES 在四年内就已确定,但当前的竞赛已大大延迟。
这艘船需要扬帆起航。
评论已关闭。