【密码学】抗量子密码算法的尝试(Chrome, OpenSSL, BoringSSL)
随着,抗量子密码的发展,之前已经讲解过相关算法了,但是呢,还没看到具体的应用,目前,Chrome已经支持了部分的抗量子密码[1],然后,我们就来看一下,那么,究竟如何能体验到Chrome的这个特性呢。
初次尝试
对于如何体验呢,一般有两种选择,第一种呢,就是自己编译对应的算法,让openssl,支持这个算法,第二种呢,那就是找一个测试网站,来测试一下相关的功能,为了简单呢,我们先来看第二种方案,经过一些简单的搜索,最终找到了测试的网站[3]。
目前,这个网站,支持的算法还是比较多的,除了NIST刚发布的三个算法[4]之外,还有一些其他的算法。
但是,Chrome,目前仅仅支持,其中的几个,如果不支持,会得到如下的错误。
那么,我们只需要找一下,Chrome支持的具体算法, 然后再来测试一下[5],
注意,这里首先要手动开启chrome://flags/
里面的特性,
然后,这里需要重启Chrome才能生效,点击Relaunch
。
然后,我们找到对应测试网站当中的链接,接下来,
应该会遇到一个新的问题。
这个原因,是因为,这个网站证书的问题,这里,我们就是为了测试,所以,我们直接在这个页面输入thisisunsafe
,就可以直接访问了。
可以发现,非常的成功,说明这个网站是好使的。
再次尝试(Boringssl)
由于,Chrome所支持的算法有限,可以说就一个,如果想要体验其他的算法呢,那么就需要自己编译了,这里,那么我们完全是可以脱离掉Chrome,直接搞一个openssl来试一下,对于资料[2]当中呢,实际上是有openssl的provider的,但是吧,它同时支持了boringssl,那这件事情,就非常的Nice了,那肯定搞一下boringssl来试一下,至于为什么呢,个人习惯。
我们,跟着[6],来进行操作就好了,这里先描述一下对应的环境。
环境介绍
这里,我们采用了Ubuntu24.04进行编译的,至于为啥选择了Ubuntu,一个原因是因为,我mac没编译成功,然后,我也懒得找原因,应该那个库出现的问题,所以,目前,我仅测试了Ubuntu,当然,根据官方描述,应该也是可以支持Windows的,但是吧,这个,如果有读者尝试,那我只能,祝愿,读者好运。
前置依赖
由于,需要自己编译,所以我们需要安装一些依赖。
sudo apt install cmake gcc ninja-build libunwind-dev pkg-config python3 golang-go
源码下载
git clone --branch master --single-branch --depth 1 https://github.com/open-quantum-safe/boringssl.git <BORINGSSL_DIR>
LIBOQS下载&编译
这个库,提供了抗量子加密算法的相关依赖,因此,我们首先要来编译他,那么至于为什么要先下载boringssl的源码呢,因为,我们最终编译到的路径需要用到它。
git clone --branch main --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs.git
cd liboqs
mkdir build && cd build
cmake -G"Ninja" -DCMAKE_INSTALL_PREFIX=<BORINGSSL_DIR>/oqs -DOQS_USE_OPENSSL=OFF ..
ninja
ninja install
注意,这里最终编译的路径,必须是<BORINGSSL_DIR>/oqs
,否则,在进行编译boringssl源码的时候,会触发一个错误,就是找不到oqs。
这里,需要稍等片刻,当然取决于电脑本身的速度。
BoringSSL编译
然后,我们回到boringssl源码的目录,然后,运行如下的命令。
mkdir build
cd build
cmake -GNinja ..
ninja
不出意外,应该是会顺利编译结束的,如果出现意外,请检查那个步骤还没做好,因为,我测试的时候,开了一个云服务器,几乎干净的环境,至于为啥不用虚拟机呢,好吧,好像,也没有理由。
测试
根据资料[6],我们可以进行下测试,也就是ninja run_tests
,这里我的输出如下
nning Go tests
ok boringssl.googlesource.com/boringssl/ssl/test/runner/hpke (cached)
ok boringssl.googlesource.com/boringssl/util/ar (cached)
ok boringssl.googlesource.com/boringssl/util/fipstools/acvp/acvptool/testmodulewrapper (cached)
ok boringssl.googlesource.com/boringssl/util/fipstools/delocate (cached)
Running unit tests
crypto_test [shard 1/8]
crypto_test [shard 8/8]
crypto_test --gtest_also_run_disabled_tests --gtest_filter=RSATest.DISABLED_BlindingCacheConcurrency
urandom_test
urandom_test (custom environment)
urandom_test (custom environment)
urandom_test (custom environment)
urandom_test (custom environment)
urandom_test (custom environment)
crypto_test --fork_unsafe_buffering --gtest_filter=RandTest.*:-RandTest.Fork
decrepit_test [shard 1/8]
decrepit_test [shard 2/8]
decrepit_test [shard 3/8]
decrepit_test [shard 4/8]
decrepit_test [shard 5/8]
decrepit_test [shard 6/8]
decrepit_test [shard 7/8]
decrepit_test [shard 8/8]
ssl_test [shard 1/8]
crypto_test [shard 2/8]
ssl_test [shard 3/8]
crypto_test [shard 3/8]
crypto_test --gtest_also_run_disabled_tests --gtest_filter=BNTest.DISABLED_WycheproofPrimality
crypto_test [shard 5/8]
crypto_test [shard 6/8]
ssl_test [shard 5/8]
pki_test [shard 1/8]
pki_test [shard 2/8]
pki_test [shard 3/8]
pki_test [shard 4/8]
pki_test [shard 5/8]
pki_test [shard 6/8]
pki_test [shard 7/8]
pki_test [shard 8/8]
ssl_test [shard 7/8]
ssl_test [shard 4/8]
crypto_test [shard 7/8]
ssl_test [shard 6/8]
ssl_test [shard 2/8]
crypto_test [shard 4/8]
ssl_test [shard 8/8]
All unit tests passed!
Running SSL tests
0/0/9617/9617/9617
PASS
ok boringssl.googlesource.com/boringssl/ssl/test/runner 23.326s
目前,没有发现错误,就说明,我们的编译非常的成功。
对于,测试代码层面呢,可以参考下,oqs提供的样例代码,具体位置在oqs_scripts/try_handshake.py
下,这里简单贴一下吧。
# This script simply picks a random OQS or non-OQS key-exchange
# and signature algorithm, and checks whether the stock BoringSSL
# client and server can establish a handshake with the choices.
import argparse
import random
import subprocess
import time
kexs = [
'prime256v1',
'x25519',
##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_KEMS_START
'mlkem512',
'p256_mlkem512',
'x25519_mlkem512',
'mlkem768',
'p256_mlkem768',
'p384_mlkem768',
'mlkem1024',
'p384_mlkem1024',
'p521_mlkem1024',
'frodo640aes',
'p256_frodo640aes',
'x25519_frodo640aes',
'frodo640shake',
'p256_frodo640shake',
'x25519_frodo640shake',
'frodo976aes',
'p384_frodo976aes',
'frodo976shake',
'p384_frodo976shake',
'frodo1344aes',
'p521_frodo1344aes',
'frodo1344shake',
'p521_frodo1344shake',
'kyber512',
'p256_kyber512',
'x25519_kyber512',
'kyber768',
'p256_kyber768',
'p384_kyber768',
'kyber1024',
'p521_kyber1024',
'bikel1',
'p256_bikel1',
'x25519_bikel1',
'bikel3',
'p384_bikel3',
'bikel5',
'p521_bikel5',
'hqc128',
'p256_hqc128',
'x25519_hqc128',
'hqc192',
'p384_hqc192',
'hqc256',
'p521_hqc256',
##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_KEMS_END
]
sigs = [
'prime256v1',
##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_SIGS_START
'mldsa44',
'p256_mldsa44',
'mldsa65',
'p384_mldsa65',
'mldsa87',
'p521_mldsa87',
'dilithium2',
'dilithium3',
'dilithium5',
'falcon512',
'rsa3072_falcon512',
'falconpadded512',
'falcon1024',
'falconpadded1024',
'mayo1',
'mayo2',
'mayo3',
'mayo5',
'CROSSrsdp128balanced',
'sphincssha2128fsimple',
'sphincssha2128ssimple',
'sphincssha2192fsimple',
'sphincssha2192ssimple',
'sphincssha2256fsimple',
'sphincssha2256ssimple',
'sphincsshake128fsimple',
'sphincsshake128ssimple',
'sphincsshake192fsimple',
'sphincsshake192ssimple',
'sphincsshake256fsimple',
'sphincsshake256ssimple',
##### OQS_TEMPLATE_FRAGMENT_LIST_ALL_SIGS_END
]
def try_handshake(bssl):
random_sig = random.choice(sigs)
server = subprocess.Popen([bssl, 'server',
'-accept', '26150',
'-sig-alg', random_sig],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# The server should (hopefully?) start
# in 10 seconds.
time.sleep(10)
# Try to connect to it with the client
random_kex = random.choice(kexs)
client = subprocess.run([bssl, 'client',
'-connect', 'localhost:26150',
'-curves', random_kex],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
input=''.encode())
print("---bssl server output---")
print(server.communicate(timeout=5)[0].decode())
print("---bssl client output---")
print(client.stdout.decode())
if client.returncode != 0 or server.returncode != 0:
raise Exception('Cannot establish a connection with {} and {}'.format(random_kex, random_sig))
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Test handshake between bssl client and server using a random OQS key-exchange and signature algorithm.')
parser.add_argument('bssl', type=str,
nargs='?',
const='1',
default='build/tool/bssl',
help='Path to the bssl executable')
args = parser.parse_args()
try_handshake(args.bssl)
当然,具体细节,可以参考对应的文档,运行之后,可以得到输出。
---bssl server output---
Connected.
Version: TLSv1.3
Resumed session: no
Cipher: TLS_AES_128_GCM_SHA256
ECDHE group: p384_hqc192
Secure renegotiation: yes
Extended master secret: yes
Next protocol negotiated:
ALPN protocol:
Early data: no
Encrypted ClientHello: no
---bssl client output---
Connecting to 127.0.0.1:26150
Connected.
Version: TLSv1.3
Resumed session: no
Cipher: TLS_AES_128_GCM_SHA256
ECDHE group: p384_hqc192
Signature algorithm: p521_mldsa87
Secure renegotiation: yes
Extended master secret: yes
Next protocol negotiated:
ALPN protocol:
OCSP staple: no
SCT list: no
Early data: no
Encrypted ClientHello: no
Cert subject: C = US, O = BoringSSL
Cert issuer: C = US, O = BoringSSL
注意,这里,如果尝试,得到的输出,可能不尽相同,因为,这里,是随机选取的算法,因此,对于签名个算法和ECDHE group的选取上,每次运行就都有差异了。
好了,有关于boringssl的使用呢,我们就聊到这里。
OpenSSL
接下来,这里,我们来看一下openssl,因为据说,openssl1.x版本,好像是不是,大概率已经停止维护了,在OQS团队,给的提示如下,但是他们自己fork了改的,这里,我们就先不过多讨论,因为3.x版本,采用了更加干净整洁的架构,因此呢,直接来看3.0,如果有看过1.x源码的读者,应该知道其中的酸爽。
❝
The OpenSSL project has announced that its support for OpenSSL 1.1.1 will stop in September, 2023, and that all users should switch to OpenSSL 3. Consequently, the Open Quantum Safe project is discontinuing development of our OQS-OpenSSL 1.1.1 fork. No more releases are planned for OQS-OpenSSL 1.1.1. The OQS Provider for OpenSSL 3 (described above) provides full support for post-quantum key exchange and authentication in TLS 1.3, X.509, and S/MIME.
❞
这里,就不翻译了,相信,读者看得懂。
对于,provider的方式呢,就非常的轻松加愉快了,注意,这里的测试,直接动了opoenssl本身的库,如果是「生产环境,请慎重尝试。」想要自己玩的,搞个虚拟机玩玩就好了。
首先,需要安装依赖,因为,这里,我们还是需要自己编译。
sudo apt install -y cmake libssl-dev ninja-build
当然,也可以复用,刚才玩完的,那个boringssl的依赖,问题不大。
然后,看一下,当前openssl的版本,看一下,是不是3.x,如果不是,自行升级一下,我这如下
OpenSSL 3.0.13 30 Jan 2024 (Library: OpenSSL 3.0.13 30 Jan 2024)
然后呢,就可以添加provider了。
git clone https://github.com/open-quantum-safe/oqs-provider.git
cd oqs-provider
scripts/fullbuild.sh
sudo cmake --install _build
这里,可能也要稍微等一会会儿,取决于,电脑配置,然后运行一下测试
scripts/runtests.sh
具体的输出,如下。
然后,我们,需要更新一下对应的配置文件,也就是/etc/ssl/openssl.cnf
这个文件。
# PQC via OpenQuantumSafe
[provider_sect]
default = default_sect
oqsprovider = oqsprovider_sect
[default_sect]
activate = 1
[oqsprovider_sect]
activate = 1
然后,检查一下,效果,执行
openssl list -providers
可以发现,如下的输出
Providers:
default
name: OpenSSL Default Provider
version: 3.0.13
status: active
oqsprovider
name: OpenSSL OQS Provider
version: 0.7.1-dev
status: active
说明,搞好了,我们来查看一下签名算法
openssl list -signature-algorithms -provider oqsprovider
最后的,可以换成自己需要查找的。
{ 1.2.840.113549.1.1.1, 2.5.8.1.1, RSA, rsaEncryption } @ default
{ 1.2.840.10040.4.1, 1.2.840.10040.4.3, 1.3.14.3.2.12, 1.3.14.3.2.13, 1.3.14.3.2.27, DSA, DSA-old, DSA-SHA, DSA-SHA1, DSA-SHA1-old, dsaEncryption, dsaEncryption-old, dsaWithSHA, dsaWithSHA1, dsaWithSHA1-old } @ default
{ 1.3.101.112, ED25519 } @ default
{ 1.3.101.113, ED448 } @ default
{ 1.2.156.10197.1.301, SM2 } @ default
ECDSA @ default
HMAC @ default
SIPHASH @ default
POLY1305 @ default
CMAC @ default
dilithium2 @ oqsprovider
p256_dilithium2 @ oqsprovider
rsa3072_dilithium2 @ oqsprovider
dilithium3 @ oqsprovider
p384_dilithium3 @ oqsprovider
dilithium5 @ oqsprovider
p521_dilithium5 @ oqsprovider
mldsa44 @ oqsprovider
p256_mldsa44 @ oqsprovider
rsa3072_mldsa44 @ oqsprovider
mldsa44_pss2048 @ oqsprovider
mldsa44_rsa2048 @ oqsprovider
mldsa44_ed25519 @ oqsprovider
mldsa44_p256 @ oqsprovider
mldsa44_bp256 @ oqsprovider
mldsa65 @ oqsprovider
p384_mldsa65 @ oqsprovider
mldsa65_pss3072 @ oqsprovider
mldsa65_rsa3072 @ oqsprovider
mldsa65_p256 @ oqsprovider
mldsa65_bp256 @ oqsprovider
mldsa65_ed25519 @ oqsprovider
mldsa87 @ oqsprovider
p521_mldsa87 @ oqsprovider
mldsa87_p384 @ oqsprovider
mldsa87_bp384 @ oqsprovider
mldsa87_ed448 @ oqsprovider
falcon512 @ oqsprovider
p256_falcon512 @ oqsprovider
rsa3072_falcon512 @ oqsprovider
falconpadded512 @ oqsprovider
p256_falconpadded512 @ oqsprovider
rsa3072_falconpadded512 @ oqsprovider
falcon1024 @ oqsprovider
p521_falcon1024 @ oqsprovider
falconpadded1024 @ oqsprovider
p521_falconpadded1024 @ oqsprovider
sphincssha2128fsimple @ oqsprovider
p256_sphincssha2128fsimple @ oqsprovider
rsa3072_sphincssha2128fsimple @ oqsprovider
sphincssha2128ssimple @ oqsprovider
p256_sphincssha2128ssimple @ oqsprovider
rsa3072_sphincssha2128ssimple @ oqsprovider
sphincssha2192fsimple @ oqsprovider
p384_sphincssha2192fsimple @ oqsprovider
sphincsshake128fsimple @ oqsprovider
p256_sphincsshake128fsimple @ oqsprovider
rsa3072_sphincsshake128fsimple @ oqsprovider
mayo1 @ oqsprovider
p256_mayo1 @ oqsprovider
mayo2 @ oqsprovider
p256_mayo2 @ oqsprovider
mayo3 @ oqsprovider
p384_mayo3 @ oqsprovider
mayo5 @ oqsprovider
p521_mayo5 @ oqsprovider
CROSSrsdp128balanced @ oqsprovider
然后,再看看一下,KEM算法
openssl list -kem-algorithms -provider oqsprovider
{ 1.2.840.113549.1.1.1, 2.5.8.1.1, RSA, rsaEncryption } @ default
frodo640aes @ oqsprovider
p256_frodo640aes @ oqsprovider
x25519_frodo640aes @ oqsprovider
frodo640shake @ oqsprovider
p256_frodo640shake @ oqsprovider
x25519_frodo640shake @ oqsprovider
frodo976aes @ oqsprovider
p384_frodo976aes @ oqsprovider
x448_frodo976aes @ oqsprovider
frodo976shake @ oqsprovider
p384_frodo976shake @ oqsprovider
x448_frodo976shake @ oqsprovider
frodo1344aes @ oqsprovider
p521_frodo1344aes @ oqsprovider
frodo1344shake @ oqsprovider
p521_frodo1344shake @ oqsprovider
kyber512 @ oqsprovider
p256_kyber512 @ oqsprovider
x25519_kyber512 @ oqsprovider
kyber768 @ oqsprovider
p384_kyber768 @ oqsprovider
x448_kyber768 @ oqsprovider
x25519_kyber768 @ oqsprovider
p256_kyber768 @ oqsprovider
kyber1024 @ oqsprovider
p521_kyber1024 @ oqsprovider
mlkem512 @ oqsprovider
p256_mlkem512 @ oqsprovider
x25519_mlkem512 @ oqsprovider
mlkem768 @ oqsprovider
p384_mlkem768 @ oqsprovider
x448_mlkem768 @ oqsprovider
X25519MLKEM768 @ oqsprovider
SecP256r1MLKEM768 @ oqsprovider
mlkem1024 @ oqsprovider
p521_mlkem1024 @ oqsprovider
p384_mlkem1024 @ oqsprovider
bikel1 @ oqsprovider
p256_bikel1 @ oqsprovider
x25519_bikel1 @ oqsprovider
bikel3 @ oqsprovider
p384_bikel3 @ oqsprovider
x448_bikel3 @ oqsprovider
bikel5 @ oqsprovider
p521_bikel5 @ oqsprovider
hqc128 @ oqsprovider
p256_hqc128 @ oqsprovider
x25519_hqc128 @ oqsprovider
hqc192 @ oqsprovider
p384_hqc192 @ oqsprovider
x448_hqc192 @ oqsprovider
hqc256 @ oqsprovider
p521_hqc256 @ oqsprovider
好了,接下来,我们来实际测试一下,具体参考[7],当中的样例。
实际测试
这里,我们生成证书文件,来测试下。
penssl req -x509 -new -newkey dilithium3 -keyout dilithium3_CA.key -out dilithium3_CA.crt -nodes -subj "/CN=test CA" -days 365 -config /etc/ssl/openssl.cnf
openssl genpkey -algorithm dilithium3 -out dilithium3_srv.key
openssl req -new -newkey dilithium3 -keyout dilithium3_srv.key -out dilithium3_srv.csr -nodes -subj "/CN=test server" -config /etc/ssl/openssl.cnf
openssl x509 -req -in dilithium3_srv.csr -out dilithium3_srv.crt -CA dilithium3_CA.crt -CAkey dilithium3_CA.key -CAcreateserial -days 365
注意,这里,和文档有些差异,因为配置文件位置的不同,最终我们会得到几个文件。
dilithium3_CA.crt dilithium3_CA.key dilithium3_CA.srl dilithium3_srv.crt dilithium3_srv.csr dilithium3_srv.key
然后,这里我们对于文件签名,这里先搞一个自签名证书。
openssl req -x509 -new -newkey dilithium3 -keyout qsc.key -out qsc.crt -nodes -subj "/CN=oqstest" -days 365 -config /etc/ssl/openssl.cnf
然后,我们对文件签名。
penssl dgst -sign qsc.key -out dgstsignfile test.txt
最终,会得到,一个签名文件,也就是dgstsignfile
,然后,我们生成公钥。
openssl x509 -in qsc.crt -pubkey -noout > qsc.pubkey
执行验签,
openssl dgst -signature dgstsignfile -verify qsc.pubkey test.txt
可以发现是成功的,非常的Nice,好了到这里,我们简单的实验也就结束了,大家有兴趣 可以自己玩玩。
总结
这里,我们首先,先通过测试网站,观察了,Chrome确实已经支持了「部分」抗量子加密的算法的协议,Firefox,应该其实也支持了,具体我没测,有兴趣研究的读者可以自行测试下,然后对于更多的协议,后面,可以接入openssl-provider、boringssl,等其他方式,在自己的相关项目当中集成,跟着文档来走,一般还是比较顺利的,当然,还有其他的嵌入方式,比如NGINX,ssh,等等,这个,有机会再来聊吧。
随着抗量子加密的发展呢,应该会有越来越多的库来支持抗量子加密的相关算法,目前openquantumsafe团队,应该算是,目前,「我找到的」,支持的算法最多,支持的库最多的开源项目了,这里,叠一个甲,目前,截止到发文,并且是我找到的,因为,开源库太多了,我也没仔细看,好了,本篇文章到这里就结束了,快乐的时光过得特别快,又到了说再见的时候了,咱们下次再见。
参考资料
-
https://thehackernews.com/2024/09/google-chrome-switches-to-ml-kem-for.html -
https://openquantumsafe.org/ -
https://test.openquantumsafe.org/ -
https://csrc.nist.gov/projects/post-quantum-cryptography/ -
https://support.google.com/chrome/a/answer/7679408 -
https://github.com/open-quantum-safe/boringssl/blob/master/README.md -
https://github.com/open-quantum-safe/oqs-provider/blob/main/USAGE.md
原文始发于微信公众号(Coder小Q):【密码学】抗量子密码算法的尝试(Chrome, OpenSSL, BoringSSL)
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论