每天进步一点点:修复OpenSSL 3.0导致ripemd160魔法失效的问题

熟悉比特币(Bitcoin)公私钥机制的朋友,可能回知道,比特币中的地址其实是由公钥按固定流程生成。

image.png
(图源 :pixabay)

魔法操作:ripemd160

在《Mastering Bitcoin》一书中,有如下比特币公钥到地址生成流程的示意图:

Reveal spoiler

image.png

而HIVE的公私钥机制和比特币差不多,只不过不同于比特币的地址,HIVE多了账户的概念,更加简洁可靠。但是公钥在签名验证以及MEMO处理等用途中,同样是必不可少的角色。

为了让公钥看起来更加友好,HIVE中对公钥也进行了简单的编码处理,简单的来讲,对压缩的公钥进行ripemd160操作并取前四个字节作为校验码(checksum)追加到公钥的尾部,再对其进行base58编码,然后在添加上前缀“STM”。

细心的你,可能已经注意到了,无论是比特币的地址,还是HIVE编码后的私钥,都用到了一个魔法操作,那就是ripemd160

失灵的魔法&原因

我的一些涉及比特币地址以及HIVE公钥的代码也避免不了地用到了ripemd160,比如说,随机生成一个HIVE公私钥对。这些代码在我的系统上一直工作的好好的。

而前段时间运行一段简单代码(生成公私钥对)时,突然被提示出错,奇了怪哉,只在本地系统运行的代码,也没和网络API等接口打交道,为啥会出错呢?

仔细查看了一下出错信息,最后定位的关键出错信息

    ripemd160 = hashlib.new('ripemd160')
  File "/usr/lib/python3.10/hashlib.py", line 166, in __hash_new
    return __get_builtin_constructor(name)(data)
  File "/usr/lib/python3.10/hashlib.py", line 123, in __get_builtin_constructor
    raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type ripemd160

也就是说,调用hashlib使用其中的ripemd160,被提示这个方法不被支持。

我们可以通过以下代码来查看hashlib支持的算法:

import hashlib
hashlib.algorithms_available

打印出来的信息如下:

{'sha3_384', 'sha3_256', 'shake_256', 'md5', 'sha3_224', 'sha3_512', 'md5-sha1', 'blake2s', 'sha384', 'sm3', 'sha1', 'sha224', 'blake2b', 'sha512', 'sha512_224', 'sha256', 'sha512_256', 'shake_128'}

从上边的输出信息中,根本找不到ripemd160,所以hashlib确实不支持ripemd160啦!不过等等,就像我的代码突然不支持了'ripemd160'一样是因为hashlib,那么hashlib不支持ripemd160又是什么原因呢?还有就是,我这段时间都做过哪些操作,可能导致这个问题呢?

最终终于得出结论,之所以导致这个问题,是因为我把系统升级为Ubuntu 22.04 LTS,而这个版本中OpenSSL被升级为OpenSSL 3.0.2。

可以使用openssl version查看OpenSSL的版本信息:

OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)

而OpenSSL中做了一些修改,把一些算法归类到legacy组中,简单地讲,就是OpenSSL官方认为这些算法或者是过时了,或者是不安全,或者是没人用,通通丢到legacy这里,默认不加载啦,所以上边的代码就出问题啦。

修复魔法(手工加载)

那么是不是就无法使用ripemd160了?通过上边的分析,我们知道OpenSSL只是把ripemd160等算法丢到了legacy组中,而不是彻底移除。

所以相应的算法还是可以使用的,只是如果需要使用,那么需要在OpenSSL的配置文件中手工设置加载。

加载方法如下:

编辑OpenSSL的配置文件:

sudo vi /usr/lib/ssl/openssl.cnf

在此处追加legacy = legacy_sect:

# List of providers to load
[provider_sect]
default = default_sect
legacy = legacy_sect #新增内容

在此处也需做相应的修改:

# If no providers are activated explicitly, the default one is activated implicitly.
# See man 7 OSSL_PROVIDER-default for more details.
#
# If you add a section explicitly activating any other provider(s), you most
# probably need to explicitly activate the default provider, otherwise it
# becomes unavailable in openssl. As a consequence applications depending on
# OpenSSL may not work correctly which could lead to significant system
# problems including inability to remotely access the system.
[default_sect]
activate = 1 #修改内容:去掉行首的#
[legacy_sect] # 新增内容
activate = 1 # 新增内容

其中需要特别注意的是,一定要去掉原来文件中的#activate = 1行首的#,否则 default provider将不会默认被加载(参考上边代码中的注释部分)。

经过上述修改后,我们再测试hashlib.algorithms_available,就会发现其中ripemd160回来啦(考验眼神的时刻到了):

{'sha3_256', 'shake_128', 'sha3_512', 'md5', 'whirlpool', 'sha512_256', 'sha224', 'sha256', 'blake2b', 'sha3_384', 'sha512_224', 'md5-sha1', 'sha512', 'sha1', 'sha384', 'md4', 'sha3_224', 'blake2s', 'sm3', 'ripemd160', 'shake_256'}

再测试我自己的代码(生成公私钥对,发现我的代码也正常啦),撒花:★,°:.☆( ̄▽ ̄)/$:.°★

官网的大招

虽然我们通过修改OpenSSL的配置文件找回了ripemd160这个魔法,但是其实还是很繁琐或者说很麻烦的。尤其是对普通用户而言,这样的操作,简直是要了老命。

当然了,可能普通用户也用不到这个算法😳,但是总而言之,这么常用的算法(常用嘛?不常用嘛?)不应该做这样的修改才对。

令人开心的是,我在OpenSSL官方博客上看到一篇博文,大意讲的是官方为何要移除ripemd160以及他们已经意识到这个错误,并将在新版本中修复。

其中部分博文如下:

We were wrong. RIPEMD160 is used with bitcoin, which makes for a huge user base, and while one might argue that all that’s needed is to explicitly load the legacy provider – potentially by configuration–, it turns out to be difficult in ecosystems with multiple dependencies where OpenSSL is an embedded component under other layers of libraries, further exasperated for those who do not have the possibility to modify the OpenSSL configuration, or use their own.

看看人家这态度,知错就改,好赞👍👍👍👍👍。

那么我之前这番折腾莫非白费了嘛?好吧,其实并不白费,毕竟搞明白来龙去脉并且解决了相关问题。

虽然说新版本中会修复,不过等Ubuntu 22.04 LTS中集成新版本,不定又要等多久呢,总不能让自己的程序罢工傻等,对吧?

相关链接

Sort:  

看能学习的帖子真好(✪▽✪)

我看这文,感觉是在糟蹋O哥辛勤的成果。😆

分享的过程也是自己记录
便于自己以后遇到问题查找

嗯嗯,明白了,写文除了写给别人看也是为了给自己看。

厉害厉害厉害厉害厉害👍

程序员就是这么神。想学都学不来,威武

O神太厉害了,一年前的帖子帮我避坑👍🏻👍🏻