Python 3.8 中是否支持 MD4 哈希算法?

10

我正在尝试为一个使用NTLM身份验证的服务器实现SOAP客户端。我使用的库(requests-ntlm2依赖于ntlm-auth)通过标准库的hashlib实现了NTLM协议核心中的MD4算法。

虽然hashlib似乎支持MD4:

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

我的系统中也是如此,同时openssl库也是如此:

(victory) C:\code\python\services>openssl
help:
[...]
Message Digest commands (see the `dgst' command for more details)
blake2b512        blake2s256        md4               md5
mdc2              rmd160            sha1              sha224
sha256            sha3-224          sha3-256          sha3-384
sha3-512          sha384            sha512            sha512-224
sha512-256        shake128          shake256          sm3
[...]

当身份验证尝试运行时,Python会产生一个ValueError:unsupported hash type md4错误。以下是回溯的相关部分:

C:\ProgramData\Miniconda3\envs\victory\lib\site-packages\ntlm_auth\compute_hash.py in _ntowfv1(password)
    165         return nt_hash
    166 
--> 167     digest = hashlib.new('md4', password.encode('utf-16-le')).digest()
    168 
    169     return digest

C:\ProgramData\Miniconda3\envs\victory\lib\hashlib.py in __hash_new(name, data, **kwargs)
    161         # This allows for SHA224/256 and SHA384/512 support even though
    162         # the OpenSSL library prior to 0.9.8 doesn't provide them.
--> 163         return __get_builtin_constructor(name)(data)
    164 
    165 

C:\ProgramData\Miniconda3\envs\victory\lib\hashlib.py in __get_builtin_constructor(name)
    118         return constructor
    119 
--> 120     raise ValueError('unsupported hash type ' + name)
    121 
    122 

ValueError: unsupported hash type md4

即使我只是尝试从hashlib中调用MD4,我仍然得到相同的结果:

>>> import hashlib
>>> hashlib.new('md4')
Traceback (most recent call last):
  File "C:\ProgramData\Miniconda3\envs\victory\lib\hashlib.py", line 157, in __hash_new
    return _hashlib.new(name, data)
ValueError: [digital envelope routines] initialization error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\ProgramData\Miniconda3\envs\victory\lib\hashlib.py", line 163, in __hash_new
    return __get_builtin_constructor(name)(data)
  File "C:\ProgramData\Miniconda3\envs\victory\lib\hashlib.py", line 120, in __get_builtin_constructor
    raise ValueError('unsupported hash type ' + name)
ValueError: unsupported hash type md4

任何有关正在发生的情况的见解和/或任何帮助将不胜感激。

这对我来说很好用。 - Frank Yellin
@FrankYellin,你使用的是相同的堆栈(Windows、Python 3.8、requests-ntlm2)吗?'hashlib.new('md4')' 正常工作吗? - spitoglou
我没有专业的知识可添加,但我在使用Windows操作系统,并且安装了最新版本的Python 3.9。虽然PATH路径下没有OpenSSL,但是我可以成功地使用hashlib.new('md4') - Cory Petosky
如果没有其他选择,那么可以使用纯Python实现的md4。https://gist.github.com/kangtastic/c3349fc4f9d659ee362b12d7d8c639b6 - Frank Yellin
1
你使用的openssl版本是什么?我曾经遇到过类似的问题,之前可以正常运行的代码现在却出现了相同的错误信息。在网上搜索了很久后,我终于发现罪魁祸首是使用的openssl版本。我重新构建了环境,并明确指定了openssl=1.1.1 - 这对我解决了问题。 - martino
显示剩余2条评论
6个回答

7

针对 Ubuntu (Jammy/Focal).

将以下内容添加到您的/etc/ssl/openssl.cnf中,以将md4重新启用为hashlib。

[provider_sect]
default = default_sect
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1

这里提供一个解决方案https://bugs.launchpad.net/ubuntu/+source/python3.10/+bug/1971580/comments/3

根据你的版本或发行版,openssl.cnf文件的路径可能是/usr/lib/openssl.cnf或其他路径。


3
运行得非常好(Y)。你救了我一命,兄弟!我唯一的区别是在/etc/ssl/openssl.cnf中添加这些行。 - Tes3awy
1
/usr/lib 看起来像是打错了,应该是 /etc/lib 吧? - antonone
@antonone 谢谢。我觉得这取决于发行版,Ubuntu 版本也是如此。 - imbr

6

截至2023年5月的更新

此问题已在requests-ntlm>=1.2.0中解决,现在使用SPNEGO:https://github.com/requests/requests-ntlm/pull/126

使用此版本时,不再需要进行OpenSSL配置更改。

提示:由于这是“不支持哈希类型md4”的顶级结果之一(当我在现代Linux发行版上使用Ansible定位Windows时遇到的错误),因此仅需在当前的Ansible安装中更新此库即可解决问题:

python3 -m pip install -U requests-ntlm

4

跟随 @imbr 的 " 适用于 Ubuntu Jammy " 操作:

我发现在我的系统上编辑/添加文件 /usr/lib/openssl.cnf 没有任何作用。2小时后,我发现这是因为在 Ubuntu 中的 openssl 包中附带了一个位于 /etc/ssl/openssl.cnf 的文件。 来源:https://packages.ubuntu.com/jammy/amd64/openssl/filelist

合并来自 @imbr 的配置解决了这个问题:D

[provider_sect]
default = default_sect
legacy = legacy_sect

[default_sect]
activate = 1

[legacy_sect]
activate = 1

注意:我正在发布一篇新文章,因为我没有足够的堆栈溢出声望直接评论@imbr的帖子。


@dvaerum 我修改了我的Openssl.cnf文件,但仍然出现“不支持的哈希类型md4”错误。在我的环境中,“hashlib.algorithms_available”未列出md4算法。 PS- 我创建了一个虚拟环境,其中包含Python 3.9和OpenSSL 3.0的默认软件包。然后我修改了存储在----\env\Library中的Openssl.cnf文件。 - Ashish
@Ashish 你是在使用Windows吗?我问这个问题是因为你在路径中使用了反斜杠。如果是Windows,我不知道你应该怎么做 ‍♂️ 否则问题可能是你没有使用OpenSSL正在查找的其中一个补丁,请尝试我使用的路径。 - dvaerum
是的,我正在使用Windows :(。作为解决方法,我创建了一个带有Opensdl 1.1.1的虚拟环境,现在Hashlib中可用md4。 - Ashish

2

看起来我的conda环境出了一些问题。我创建了一个新的完全相同的环境,自此之后一直在工作,而且没有必要更改其他任何内容。


这真的很可怕。我不喜欢一个损坏的Conda环境会导致hashlib生成虚假结果这个事实。 - Frank Yellin
@spitoglou 你有没有找出数据损坏的原因?我也遇到了同样的问题,环境突然崩溃确实很可怕。 - Saaru Lindestøkke
@SaaruLindestøkke 很抱歉回复晚了,不过很遗憾我还没能够准确找出问题所在... - spitoglou

1
在我的情况下,我正在运行一个docker镜像python:3.7,并没有指定子版本。 @imbr提到的修复方法确实有效。 通过运行openssl version -d,我找到了openssl.cnf文件的位置。
但是,在我的开发站点上,它使用的是python:3.7.15,而在生产服务器上是python:3.7.17。 从发布说明中可以看出,openssl在17号进行了更新,详情请参考https://www.python.org/downloads/release/python-3717/

-1
hashlib.new('md4', "test".encode()).hexdigest()

4
请记住,Stack Overflow 不仅旨在解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区的初学者和不熟悉语法的成员来说,这尤其重要。鉴于此,您能否[编辑]您的答案,包括对您正在做什么的解释以及为什么您认为这是最佳方法的解释? - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接