mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #7120 from youknowone/hashlib
Update hashlib from v3.14.3 and align _hashlib to CPython
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -3226,6 +3226,7 @@ dependencies = [
|
||||
"foreign-types-shared",
|
||||
"gethostname",
|
||||
"hex",
|
||||
"hmac",
|
||||
"indexmap",
|
||||
"itertools 0.14.0",
|
||||
"libc",
|
||||
@@ -3250,6 +3251,7 @@ dependencies = [
|
||||
"page_size",
|
||||
"parking_lot",
|
||||
"paste",
|
||||
"pbkdf2",
|
||||
"pem-rfc7468 1.0.0",
|
||||
"phf 0.13.1",
|
||||
"pkcs8",
|
||||
|
||||
103
Lib/hashlib.py
vendored
103
Lib/hashlib.py
vendored
@@ -33,7 +33,7 @@ Hash objects have these methods:
|
||||
- hexdigest(): Like digest() except the digest is returned as a string
|
||||
of double length, containing only hexadecimal digits.
|
||||
- copy(): Return a copy (clone) of the hash object. This can be used to
|
||||
efficiently compute the digests of datas that share a common
|
||||
efficiently compute the digests of data that share a common
|
||||
initial substring.
|
||||
|
||||
For example, to obtain the digest of the byte string 'Nobody inspects the
|
||||
@@ -65,7 +65,7 @@ algorithms_guaranteed = set(__always_supported)
|
||||
algorithms_available = set(__always_supported)
|
||||
|
||||
__all__ = __always_supported + ('new', 'algorithms_guaranteed',
|
||||
'algorithms_available', 'pbkdf2_hmac', 'file_digest')
|
||||
'algorithms_available', 'file_digest')
|
||||
|
||||
|
||||
__builtin_constructor_cache = {}
|
||||
@@ -92,13 +92,13 @@ def __get_builtin_constructor(name):
|
||||
import _md5
|
||||
cache['MD5'] = cache['md5'] = _md5.md5
|
||||
elif name in {'SHA256', 'sha256', 'SHA224', 'sha224'}:
|
||||
import _sha256
|
||||
cache['SHA224'] = cache['sha224'] = _sha256.sha224
|
||||
cache['SHA256'] = cache['sha256'] = _sha256.sha256
|
||||
import _sha2
|
||||
cache['SHA224'] = cache['sha224'] = _sha2.sha224
|
||||
cache['SHA256'] = cache['sha256'] = _sha2.sha256
|
||||
elif name in {'SHA512', 'sha512', 'SHA384', 'sha384'}:
|
||||
import _sha512
|
||||
cache['SHA384'] = cache['sha384'] = _sha512.sha384
|
||||
cache['SHA512'] = cache['sha512'] = _sha512.sha512
|
||||
import _sha2
|
||||
cache['SHA384'] = cache['sha384'] = _sha2.sha384
|
||||
cache['SHA512'] = cache['sha512'] = _sha2.sha512
|
||||
elif name in {'blake2b', 'blake2s'}:
|
||||
import _blake2
|
||||
cache['blake2b'] = _blake2.blake2b
|
||||
@@ -141,38 +141,37 @@ def __get_openssl_constructor(name):
|
||||
return __get_builtin_constructor(name)
|
||||
|
||||
|
||||
def __py_new(name, data=b'', **kwargs):
|
||||
def __py_new(name, *args, **kwargs):
|
||||
"""new(name, data=b'', **kwargs) - Return a new hashing object using the
|
||||
named algorithm; optionally initialized with data (which must be
|
||||
a bytes-like object).
|
||||
"""
|
||||
return __get_builtin_constructor(name)(data, **kwargs)
|
||||
return __get_builtin_constructor(name)(*args, **kwargs)
|
||||
|
||||
|
||||
def __hash_new(name, data=b'', **kwargs):
|
||||
def __hash_new(name, *args, **kwargs):
|
||||
"""new(name, data=b'') - Return a new hashing object using the named algorithm;
|
||||
optionally initialized with data (which must be a bytes-like object).
|
||||
"""
|
||||
if name in __block_openssl_constructor:
|
||||
# Prefer our builtin blake2 implementation.
|
||||
return __get_builtin_constructor(name)(data, **kwargs)
|
||||
return __get_builtin_constructor(name)(*args, **kwargs)
|
||||
try:
|
||||
return _hashlib.new(name, data, **kwargs)
|
||||
return _hashlib.new(name, *args, **kwargs)
|
||||
except ValueError:
|
||||
# If the _hashlib module (OpenSSL) doesn't support the named
|
||||
# hash, try using our builtin implementations.
|
||||
# This allows for SHA224/256 and SHA384/512 support even though
|
||||
# the OpenSSL library prior to 0.9.8 doesn't provide them.
|
||||
return __get_builtin_constructor(name)(data)
|
||||
return __get_builtin_constructor(name)(*args, **kwargs)
|
||||
|
||||
|
||||
try:
|
||||
import _hashlib
|
||||
new = __hash_new
|
||||
__get_hash = __get_openssl_constructor
|
||||
# TODO: RUSTPYTHON set in _hashlib instance PyFrozenSet algorithms_available
|
||||
'''algorithms_available = algorithms_available.union(
|
||||
_hashlib.openssl_md_meth_names)'''
|
||||
algorithms_available = algorithms_available.union(
|
||||
_hashlib.openssl_md_meth_names)
|
||||
except ImportError:
|
||||
_hashlib = None
|
||||
new = __py_new
|
||||
@@ -181,76 +180,14 @@ except ImportError:
|
||||
try:
|
||||
# OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA
|
||||
from _hashlib import pbkdf2_hmac
|
||||
__all__ += ('pbkdf2_hmac',)
|
||||
except ImportError:
|
||||
from warnings import warn as _warn
|
||||
_trans_5C = bytes((x ^ 0x5C) for x in range(256))
|
||||
_trans_36 = bytes((x ^ 0x36) for x in range(256))
|
||||
pass
|
||||
|
||||
def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
|
||||
"""Password based key derivation function 2 (PKCS #5 v2.0)
|
||||
|
||||
This Python implementations based on the hmac module about as fast
|
||||
as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster
|
||||
for long passwords.
|
||||
"""
|
||||
_warn(
|
||||
"Python implementation of pbkdf2_hmac() is deprecated.",
|
||||
category=DeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
if not isinstance(hash_name, str):
|
||||
raise TypeError(hash_name)
|
||||
|
||||
if not isinstance(password, (bytes, bytearray)):
|
||||
password = bytes(memoryview(password))
|
||||
if not isinstance(salt, (bytes, bytearray)):
|
||||
salt = bytes(memoryview(salt))
|
||||
|
||||
# Fast inline HMAC implementation
|
||||
inner = new(hash_name)
|
||||
outer = new(hash_name)
|
||||
blocksize = getattr(inner, 'block_size', 64)
|
||||
if len(password) > blocksize:
|
||||
password = new(hash_name, password).digest()
|
||||
password = password + b'\x00' * (blocksize - len(password))
|
||||
inner.update(password.translate(_trans_36))
|
||||
outer.update(password.translate(_trans_5C))
|
||||
|
||||
def prf(msg, inner=inner, outer=outer):
|
||||
# PBKDF2_HMAC uses the password as key. We can re-use the same
|
||||
# digest objects and just update copies to skip initialization.
|
||||
icpy = inner.copy()
|
||||
ocpy = outer.copy()
|
||||
icpy.update(msg)
|
||||
ocpy.update(icpy.digest())
|
||||
return ocpy.digest()
|
||||
|
||||
if iterations < 1:
|
||||
raise ValueError(iterations)
|
||||
if dklen is None:
|
||||
dklen = outer.digest_size
|
||||
if dklen < 1:
|
||||
raise ValueError(dklen)
|
||||
|
||||
dkey = b''
|
||||
loop = 1
|
||||
from_bytes = int.from_bytes
|
||||
while len(dkey) < dklen:
|
||||
prev = prf(salt + loop.to_bytes(4))
|
||||
# endianness doesn't matter here as long to / from use the same
|
||||
rkey = from_bytes(prev)
|
||||
for i in range(iterations - 1):
|
||||
prev = prf(prev)
|
||||
# rkey = rkey ^ prev
|
||||
rkey ^= from_bytes(prev)
|
||||
loop += 1
|
||||
dkey += rkey.to_bytes(inner.digest_size)
|
||||
|
||||
return dkey[:dklen]
|
||||
|
||||
try:
|
||||
# OpenSSL's scrypt requires OpenSSL 1.1+
|
||||
from _hashlib import scrypt
|
||||
from _hashlib import scrypt # noqa: F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@@ -294,6 +231,8 @@ def file_digest(fileobj, digest, /, *, _bufsize=2**18):
|
||||
view = memoryview(buf)
|
||||
while True:
|
||||
size = fileobj.readinto(buf)
|
||||
if size is None:
|
||||
raise BlockingIOError("I/O operation would block.")
|
||||
if size == 0:
|
||||
break # EOF
|
||||
digestobj.update(view[:size])
|
||||
|
||||
312
Lib/test/test_hashlib.py
vendored
312
Lib/test/test_hashlib.py
vendored
@@ -1,6 +1,4 @@
|
||||
# Test hashlib module
|
||||
#
|
||||
# $Id$
|
||||
# Test the hashlib module.
|
||||
#
|
||||
# Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org)
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
@@ -12,50 +10,46 @@ import hashlib
|
||||
import importlib
|
||||
import io
|
||||
import itertools
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import sysconfig
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
import warnings
|
||||
from test import support
|
||||
from test.support import _4G, bigmemtest
|
||||
from test.support import hashlib_helper
|
||||
from test.support.import_helper import import_fresh_module
|
||||
from test.support import os_helper
|
||||
from test.support import requires_resource
|
||||
from test.support import threading_helper
|
||||
from test.support import warnings_helper
|
||||
from http.client import HTTPException
|
||||
|
||||
# Were we compiled --with-pydebug or with #define Py_DEBUG?
|
||||
COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount')
|
||||
|
||||
# default builtin hash module
|
||||
default_builtin_hashes = {'md5', 'sha1', 'sha256', 'sha512', 'sha3', 'blake2'}
|
||||
default_builtin_hashes = {'md5', 'sha1', 'sha2', 'sha3', 'blake2'}
|
||||
# --with-builtin-hashlib-hashes override
|
||||
builtin_hashes = sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES")
|
||||
if builtin_hashes is None:
|
||||
builtin_hashes = default_builtin_hashes
|
||||
else:
|
||||
builtin_hashes = {
|
||||
m.strip() for m in builtin_hashes.strip('"').lower().split(",")
|
||||
}
|
||||
builtin_hash_names = builtin_hashes.strip('"').lower().split(",")
|
||||
builtin_hashes = set(map(str.strip, builtin_hash_names))
|
||||
|
||||
# hashlib with and without OpenSSL backend for PBKDF2
|
||||
# only import builtin_hashlib when all builtin hashes are available.
|
||||
# Otherwise import prints noise on stderr
|
||||
# Public 'hashlib' module with OpenSSL backend for PBKDF2.
|
||||
openssl_hashlib = import_fresh_module('hashlib', fresh=['_hashlib'])
|
||||
if builtin_hashes == default_builtin_hashes:
|
||||
builtin_hashlib = import_fresh_module('hashlib', blocked=['_hashlib'])
|
||||
else:
|
||||
builtin_hashlib = None
|
||||
|
||||
try:
|
||||
from _hashlib import HASH, HASHXOF, openssl_md_meth_names, get_fips_mode
|
||||
import _hashlib
|
||||
except ImportError:
|
||||
HASH = None
|
||||
HASHXOF = None
|
||||
openssl_md_meth_names = frozenset()
|
||||
|
||||
_hashlib = None
|
||||
# The extension module may exist but only define some of these. gh-141907
|
||||
HASH = getattr(_hashlib, 'HASH', None)
|
||||
HASHXOF = getattr(_hashlib, 'HASHXOF', None)
|
||||
openssl_md_meth_names = getattr(_hashlib, 'openssl_md_meth_names', frozenset())
|
||||
get_fips_mode = getattr(_hashlib, 'get_fips_mode', None)
|
||||
if not get_fips_mode:
|
||||
def get_fips_mode():
|
||||
return 0
|
||||
|
||||
@@ -66,9 +60,12 @@ except ImportError:
|
||||
|
||||
requires_blake2 = unittest.skipUnless(_blake2, 'requires _blake2')
|
||||
|
||||
# bpo-46913: Don't test the _sha3 extension on a Python UBSAN build
|
||||
SKIP_SHA3 = support.check_sanitizer(ub=True)
|
||||
requires_sha3 = unittest.skipUnless(not SKIP_SHA3, 'requires _sha3')
|
||||
try:
|
||||
import _sha3
|
||||
except ImportError:
|
||||
_sha3 = None
|
||||
|
||||
requires_sha3 = unittest.skipUnless(_sha3, 'requires _sha3')
|
||||
|
||||
|
||||
def hexstr(s):
|
||||
@@ -108,8 +105,8 @@ class HashLibTestCase(unittest.TestCase):
|
||||
|
||||
shakes = {'shake_128', 'shake_256'}
|
||||
|
||||
# Issue #14693: fallback modules are always compiled under POSIX
|
||||
_warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG
|
||||
# gh-58898: Fallback modules are always compiled under POSIX.
|
||||
_warn_on_extension_import = (os.name == 'posix' or support.Py_DEBUG)
|
||||
|
||||
def _conditional_import_module(self, module_name):
|
||||
"""Import a module and return a reference to it or None on failure."""
|
||||
@@ -117,7 +114,11 @@ class HashLibTestCase(unittest.TestCase):
|
||||
return importlib.import_module(module_name)
|
||||
except ModuleNotFoundError as error:
|
||||
if self._warn_on_extension_import and module_name in builtin_hashes:
|
||||
warnings.warn('Did a C extension fail to compile? %s' % error)
|
||||
logging.getLogger(__name__).warning(
|
||||
'Did a C extension fail to compile? %s',
|
||||
error,
|
||||
exc_info=error,
|
||||
)
|
||||
return None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -131,27 +132,24 @@ class HashLibTestCase(unittest.TestCase):
|
||||
|
||||
self.constructors_to_test = {}
|
||||
for algorithm in algorithms:
|
||||
if SKIP_SHA3 and algorithm.startswith('sha3_'):
|
||||
continue
|
||||
self.constructors_to_test[algorithm] = set()
|
||||
|
||||
# For each algorithm, test the direct constructor and the use
|
||||
# of hashlib.new given the algorithm name.
|
||||
for algorithm, constructors in self.constructors_to_test.items():
|
||||
constructors.add(getattr(hashlib, algorithm))
|
||||
def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
|
||||
if data is None:
|
||||
return hashlib.new(_alg, **kwargs)
|
||||
return hashlib.new(_alg, data, **kwargs)
|
||||
constructors.add(_test_algorithm_via_hashlib_new)
|
||||
def c(*args, __algorithm_name=algorithm, **kwargs):
|
||||
return hashlib.new(__algorithm_name, *args, **kwargs)
|
||||
c.__name__ = f'do_test_algorithm_via_hashlib_new_{algorithm}'
|
||||
constructors.add(c)
|
||||
|
||||
_hashlib = self._conditional_import_module('_hashlib')
|
||||
self._hashlib = _hashlib
|
||||
if _hashlib:
|
||||
# These two algorithms should always be present when this module
|
||||
# These algorithms should always be present when this module
|
||||
# is compiled. If not, something was compiled wrong.
|
||||
self.assertTrue(hasattr(_hashlib, 'openssl_md5'))
|
||||
self.assertTrue(hasattr(_hashlib, 'openssl_sha1'))
|
||||
self.assertHasAttr(_hashlib, 'openssl_md5')
|
||||
self.assertHasAttr(_hashlib, 'openssl_sha1')
|
||||
for algorithm, constructors in self.constructors_to_test.items():
|
||||
constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
|
||||
if constructor:
|
||||
@@ -173,28 +171,24 @@ class HashLibTestCase(unittest.TestCase):
|
||||
_sha1 = self._conditional_import_module('_sha1')
|
||||
if _sha1:
|
||||
add_builtin_constructor('sha1')
|
||||
_sha256 = self._conditional_import_module('_sha256')
|
||||
if _sha256:
|
||||
_sha2 = self._conditional_import_module('_sha2')
|
||||
if _sha2:
|
||||
add_builtin_constructor('sha224')
|
||||
add_builtin_constructor('sha256')
|
||||
_sha512 = self._conditional_import_module('_sha512')
|
||||
if _sha512:
|
||||
add_builtin_constructor('sha384')
|
||||
add_builtin_constructor('sha512')
|
||||
_sha3 = self._conditional_import_module('_sha3')
|
||||
if _sha3:
|
||||
add_builtin_constructor('sha3_224')
|
||||
add_builtin_constructor('sha3_256')
|
||||
add_builtin_constructor('sha3_384')
|
||||
add_builtin_constructor('sha3_512')
|
||||
add_builtin_constructor('shake_128')
|
||||
add_builtin_constructor('shake_256')
|
||||
if _blake2:
|
||||
add_builtin_constructor('blake2s')
|
||||
add_builtin_constructor('blake2b')
|
||||
|
||||
if not SKIP_SHA3:
|
||||
_sha3 = self._conditional_import_module('_sha3')
|
||||
if _sha3:
|
||||
add_builtin_constructor('sha3_224')
|
||||
add_builtin_constructor('sha3_256')
|
||||
add_builtin_constructor('sha3_384')
|
||||
add_builtin_constructor('sha3_512')
|
||||
add_builtin_constructor('shake_128')
|
||||
add_builtin_constructor('shake_256')
|
||||
|
||||
super(HashLibTestCase, self).__init__(*args, **kwargs)
|
||||
|
||||
@property
|
||||
@@ -252,6 +246,80 @@ class HashLibTestCase(unittest.TestCase):
|
||||
self._hashlib.new("md5", usedforsecurity=False)
|
||||
self._hashlib.openssl_md5(usedforsecurity=False)
|
||||
|
||||
@unittest.skipIf(get_fips_mode(), "skip in FIPS mode")
|
||||
def test_clinic_signature(self):
|
||||
for constructor in self.hash_constructors:
|
||||
with self.subTest(constructor.__name__):
|
||||
constructor(b'')
|
||||
constructor(data=b'')
|
||||
constructor(string=b'') # should be deprecated in the future
|
||||
|
||||
digest_name = constructor(b'').name
|
||||
with self.subTest(digest_name):
|
||||
hashlib.new(digest_name, b'')
|
||||
hashlib.new(digest_name, data=b'')
|
||||
hashlib.new(digest_name, string=b'')
|
||||
# Make sure that _hashlib contains the constructor
|
||||
# to test when using a combination of libcrypto and
|
||||
# interned hash implementations.
|
||||
if self._hashlib and digest_name in self._hashlib._constructors:
|
||||
self._hashlib.new(digest_name, b'')
|
||||
self._hashlib.new(digest_name, data=b'')
|
||||
self._hashlib.new(digest_name, string=b'')
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; duplicate positional/keyword arg error message differs
|
||||
@unittest.skipIf(get_fips_mode(), "skip in FIPS mode")
|
||||
def test_clinic_signature_errors(self):
|
||||
nomsg = b''
|
||||
mymsg = b'msg'
|
||||
conflicting_call = re.escape(
|
||||
"'data' and 'string' are mutually exclusive "
|
||||
"and support for 'string' keyword parameter "
|
||||
"is slated for removal in a future version."
|
||||
)
|
||||
duplicated_param = re.escape("given by name ('data') and position")
|
||||
unexpected_param = re.escape("got an unexpected keyword argument '_'")
|
||||
for args, kwds, errmsg in [
|
||||
# Reject duplicated arguments before unknown keyword arguments.
|
||||
((nomsg,), dict(data=nomsg, _=nomsg), duplicated_param),
|
||||
((mymsg,), dict(data=nomsg, _=nomsg), duplicated_param),
|
||||
# Reject duplicated arguments before conflicting ones.
|
||||
*itertools.product(
|
||||
[[nomsg], [mymsg]],
|
||||
[dict(data=nomsg), dict(data=nomsg, string=nomsg)],
|
||||
[duplicated_param]
|
||||
),
|
||||
# Reject unknown keyword arguments before conflicting ones.
|
||||
*itertools.product(
|
||||
[()],
|
||||
[
|
||||
dict(_=None),
|
||||
dict(data=nomsg, _=None),
|
||||
dict(string=nomsg, _=None),
|
||||
dict(string=nomsg, data=nomsg, _=None),
|
||||
],
|
||||
[unexpected_param]
|
||||
),
|
||||
((nomsg,), dict(_=None), unexpected_param),
|
||||
((mymsg,), dict(_=None), unexpected_param),
|
||||
# Reject conflicting arguments.
|
||||
[(nomsg,), dict(string=nomsg), conflicting_call],
|
||||
[(mymsg,), dict(string=nomsg), conflicting_call],
|
||||
[(), dict(data=nomsg, string=nomsg), conflicting_call],
|
||||
]:
|
||||
for constructor in self.hash_constructors:
|
||||
digest_name = constructor(b'').name
|
||||
with self.subTest(constructor.__name__, args=args, kwds=kwds):
|
||||
with self.assertRaisesRegex(TypeError, errmsg):
|
||||
constructor(*args, **kwds)
|
||||
with self.subTest(digest_name, args=args, kwds=kwds):
|
||||
with self.assertRaisesRegex(TypeError, errmsg):
|
||||
hashlib.new(digest_name, *args, **kwds)
|
||||
if (self._hashlib and
|
||||
digest_name in self._hashlib._constructors):
|
||||
with self.assertRaisesRegex(TypeError, errmsg):
|
||||
self._hashlib.new(digest_name, *args, **kwds)
|
||||
|
||||
def test_unknown_hash(self):
|
||||
self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
|
||||
self.assertRaises(TypeError, hashlib.new, 1)
|
||||
@@ -259,6 +327,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||
def test_new_upper_to_lower(self):
|
||||
self.assertEqual(hashlib.new("SHA256").name, "sha256")
|
||||
|
||||
@support.thread_unsafe("modifies sys.modules")
|
||||
def test_get_builtin_constructor(self):
|
||||
get_builtin_constructor = getattr(hashlib,
|
||||
'__get_builtin_constructor')
|
||||
@@ -356,6 +425,35 @@ class HashLibTestCase(unittest.TestCase):
|
||||
self.assertEqual(m1.digest(*args), m4_copy.digest(*args))
|
||||
self.assertEqual(m4.digest(*args), m4_digest)
|
||||
|
||||
@requires_resource('cpu')
|
||||
def test_sha256_update_over_4gb(self):
|
||||
zero_1mb = b"\0" * 1024 * 1024
|
||||
h = hashlib.sha256()
|
||||
for i in range(0, 4096):
|
||||
h.update(zero_1mb)
|
||||
h.update(b"hello world")
|
||||
self.assertEqual(h.hexdigest(), "a5364f7a52ebe2e25f1838a4ca715a893b6fd7a23f2a0d9e9762120da8b1bf53")
|
||||
|
||||
@requires_resource('cpu')
|
||||
def test_sha3_256_update_over_4gb(self):
|
||||
zero_1mb = b"\0" * 1024 * 1024
|
||||
h = hashlib.sha3_256()
|
||||
for i in range(0, 4096):
|
||||
h.update(zero_1mb)
|
||||
h.update(b"hello world")
|
||||
self.assertEqual(h.hexdigest(), "e2d4535e3b613135c14f2fe4e026d7ad8d569db44901740beffa30d430acb038")
|
||||
|
||||
@requires_resource('cpu')
|
||||
def test_blake2_update_over_4gb(self):
|
||||
# blake2s or blake2b doesn't matter based on how our C code is structured, this tests the
|
||||
# common loop macro logic.
|
||||
zero_1mb = b"\0" * 1024 * 1024
|
||||
h = hashlib.blake2s()
|
||||
for i in range(0, 4096):
|
||||
h.update(zero_1mb)
|
||||
h.update(b"hello world")
|
||||
self.assertEqual(h.hexdigest(), "8a268e83dd30528bc0907fa2008c91de8f090a0b6e0e60a5ff0d999d8485526f")
|
||||
|
||||
def check(self, name, data, hexdigest, shake=False, **kwargs):
|
||||
length = len(hexdigest)//2
|
||||
hexdigest = hexdigest.lower()
|
||||
@@ -391,21 +489,18 @@ class HashLibTestCase(unittest.TestCase):
|
||||
digests = [name]
|
||||
digests.extend(self.constructors_to_test[name])
|
||||
|
||||
with open(os_helper.TESTFN, "wb") as f:
|
||||
with tempfile.TemporaryFile() as f:
|
||||
f.write(data)
|
||||
|
||||
try:
|
||||
for digest in digests:
|
||||
buf = io.BytesIO(data)
|
||||
buf.seek(0)
|
||||
self.assertEqual(
|
||||
hashlib.file_digest(buf, digest).hexdigest(), hexdigest
|
||||
)
|
||||
with open(os_helper.TESTFN, "rb") as f:
|
||||
digestobj = hashlib.file_digest(f, digest)
|
||||
f.seek(0)
|
||||
digestobj = hashlib.file_digest(f, digest)
|
||||
self.assertEqual(digestobj.hexdigest(), hexdigest)
|
||||
finally:
|
||||
os.unlink(os_helper.TESTFN)
|
||||
|
||||
def check_no_unicode(self, algorithm_name):
|
||||
# Unicode objects are not allowed as input.
|
||||
@@ -452,9 +547,9 @@ class HashLibTestCase(unittest.TestCase):
|
||||
self.assertEqual(len(m.hexdigest()), 2*digest_size)
|
||||
self.assertEqual(m.name, name)
|
||||
# split for sha3_512 / _sha3.sha3 object
|
||||
self.assertIn(name.split("_")[0], repr(m))
|
||||
self.assertIn(name.split("_")[0], repr(m).lower())
|
||||
|
||||
def test_blocksize_name(self):
|
||||
def test_blocksize_and_name(self):
|
||||
self.check_blocksize_name('md5', 64, 16)
|
||||
self.check_blocksize_name('sha1', 64, 20)
|
||||
self.check_blocksize_name('sha224', 64, 28)
|
||||
@@ -462,8 +557,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||
self.check_blocksize_name('sha384', 128, 48)
|
||||
self.check_blocksize_name('sha512', 128, 64)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 'shake' not found in '<_hashlib.hashxof object at 0xc68a2c800>'
|
||||
@requires_sha3
|
||||
def test_blocksize_name_sha3(self):
|
||||
self.check_blocksize_name('sha3_224', 144, 28)
|
||||
@@ -477,9 +571,14 @@ class HashLibTestCase(unittest.TestCase):
|
||||
constructors = self.constructors_to_test[name]
|
||||
for hash_object_constructor in constructors:
|
||||
m = hash_object_constructor()
|
||||
if HASH is not None and isinstance(m, HASH):
|
||||
# _hashopenssl's variant does not have extra SHA3 attributes
|
||||
continue
|
||||
if name.startswith('shake_'):
|
||||
if HASHXOF is not None and isinstance(m, HASHXOF):
|
||||
# _hashopenssl's variant does not have extra SHA3 attributes
|
||||
continue
|
||||
else:
|
||||
if HASH is not None and isinstance(m, HASH):
|
||||
# _hashopenssl's variant does not have extra SHA3 attributes
|
||||
continue
|
||||
self.assertEqual(capacity + rate, 1600)
|
||||
self.assertEqual(m._capacity_bits, capacity)
|
||||
self.assertEqual(m._rate_bits, rate)
|
||||
@@ -696,8 +795,6 @@ class HashLibTestCase(unittest.TestCase):
|
||||
self.assertRaises(ValueError, constructor, node_offset=-1)
|
||||
self.assertRaises(OverflowError, constructor, node_offset=max_offset+1)
|
||||
|
||||
self.assertRaises(TypeError, constructor, data=b'')
|
||||
self.assertRaises(TypeError, constructor, string=b'')
|
||||
self.assertRaises(TypeError, constructor, '')
|
||||
|
||||
constructor(
|
||||
@@ -737,8 +834,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||
outer.update(keyed.digest())
|
||||
return outer.hexdigest()
|
||||
|
||||
# TODO: RUSTPYTHON add to constructor const value
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; add to constructor const value
|
||||
@requires_blake2
|
||||
def test_blake2b(self):
|
||||
self.check_blake2(hashlib.blake2b, 16, 16, 64, 64, (1<<64)-1)
|
||||
@@ -760,8 +856,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"+
|
||||
"7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923")
|
||||
|
||||
# TODO: RUSTPYTHON implement all blake2 fields
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; implement all blake2 fields
|
||||
@requires_blake2
|
||||
def test_case_blake2b_all_parameters(self):
|
||||
# This checks that all the parameters work in general, and also that
|
||||
@@ -780,15 +875,14 @@ class HashLibTestCase(unittest.TestCase):
|
||||
inner_size=7,
|
||||
last_node=True)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; blake2 key parameter not supported
|
||||
@requires_blake2
|
||||
def test_blake2b_vectors(self):
|
||||
for msg, key, md in read_vectors('blake2b'):
|
||||
key = bytes.fromhex(key)
|
||||
self.check('blake2b', msg, md, key=key)
|
||||
|
||||
# TODO: RUSTPYTHON add to constructor const value
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; add to constructor const value
|
||||
@requires_blake2
|
||||
def test_blake2s(self):
|
||||
self.check_blake2(hashlib.blake2s, 8, 8, 32, 32, (1<<48)-1)
|
||||
@@ -808,8 +902,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||
self.check('blake2s', b"abc",
|
||||
"508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982")
|
||||
|
||||
# TODO: RUSTPYTHON implement all blake2 fields
|
||||
@unittest.expectedFailure
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; implement all blake2 fields
|
||||
@requires_blake2
|
||||
def test_case_blake2s_all_parameters(self):
|
||||
# This checks that all the parameters work in general, and also that
|
||||
@@ -828,7 +921,7 @@ class HashLibTestCase(unittest.TestCase):
|
||||
inner_size=7,
|
||||
last_node=True)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; blake2 key parameter not supported
|
||||
@requires_blake2
|
||||
def test_blake2s_vectors(self):
|
||||
for msg, key, md in read_vectors('blake2s'):
|
||||
@@ -899,10 +992,13 @@ class HashLibTestCase(unittest.TestCase):
|
||||
|
||||
def test_gil(self):
|
||||
# Check things work fine with an input larger than the size required
|
||||
# for multithreaded operation (which is hardwired to 2048).
|
||||
gil_minsize = 2048
|
||||
|
||||
# for multithreaded operation. Currently, all cryptographic modules
|
||||
# have the same constant value (2048) but in the future it might not
|
||||
# be the case.
|
||||
mods = ['_md5', '_sha1', '_sha2', '_sha3', '_blake2', '_hashlib']
|
||||
gil_minsize = hashlib_helper.find_gil_minsize(mods)
|
||||
for cons in self.hash_constructors:
|
||||
# constructors belong to one of the above modules
|
||||
m = cons(usedforsecurity=False)
|
||||
m.update(b'1')
|
||||
m.update(b'#' * gil_minsize)
|
||||
@@ -911,6 +1007,8 @@ class HashLibTestCase(unittest.TestCase):
|
||||
m = cons(b'x' * gil_minsize, usedforsecurity=False)
|
||||
m.update(b'1')
|
||||
|
||||
def test_sha256_gil(self):
|
||||
gil_minsize = hashlib_helper.find_gil_minsize(['_sha2', '_hashlib'])
|
||||
m = hashlib.sha256()
|
||||
m.update(b'1')
|
||||
m.update(b'#' * gil_minsize)
|
||||
@@ -988,7 +1086,8 @@ class HashLibTestCase(unittest.TestCase):
|
||||
def test_hash_disallow_instantiation(self):
|
||||
# internal types like _hashlib.HASH are not constructable
|
||||
support.check_disallow_instantiation(self, HASH)
|
||||
support.check_disallow_instantiation(self, HASHXOF)
|
||||
if HASHXOF is not None:
|
||||
support.check_disallow_instantiation(self, HASHXOF)
|
||||
|
||||
def test_readonly_types(self):
|
||||
for algorithm, constructors in self.constructors_to_test.items():
|
||||
@@ -1110,15 +1209,7 @@ class KDFTests(unittest.TestCase):
|
||||
iterations=1, dklen=None)
|
||||
self.assertEqual(out, self.pbkdf2_results['sha1'][0][0])
|
||||
|
||||
@unittest.skipIf(builtin_hashlib is None, "test requires builtin_hashlib")
|
||||
def test_pbkdf2_hmac_py(self):
|
||||
with warnings_helper.check_warnings():
|
||||
self._test_pbkdf2_hmac(
|
||||
builtin_hashlib.pbkdf2_hmac, builtin_hashes
|
||||
)
|
||||
|
||||
@unittest.skipUnless(hasattr(openssl_hashlib, 'pbkdf2_hmac'),
|
||||
' test requires OpenSSL > 1.0')
|
||||
@unittest.skipIf(openssl_hashlib is None, "requires OpenSSL bindings")
|
||||
def test_pbkdf2_hmac_c(self):
|
||||
self._test_pbkdf2_hmac(openssl_hashlib.pbkdf2_hmac, openssl_md_meth_names)
|
||||
|
||||
@@ -1169,29 +1260,38 @@ class KDFTests(unittest.TestCase):
|
||||
def test_file_digest(self):
|
||||
data = b'a' * 65536
|
||||
d1 = hashlib.sha256()
|
||||
self.addCleanup(os.unlink, os_helper.TESTFN)
|
||||
with open(os_helper.TESTFN, "wb") as f:
|
||||
with tempfile.NamedTemporaryFile(delete_on_close=False) as fp:
|
||||
for _ in range(10):
|
||||
d1.update(data)
|
||||
f.write(data)
|
||||
fp.write(data)
|
||||
fp.close()
|
||||
|
||||
with open(os_helper.TESTFN, "rb") as f:
|
||||
d2 = hashlib.file_digest(f, hashlib.sha256)
|
||||
with open(fp.name, "rb") as f:
|
||||
d2 = hashlib.file_digest(f, hashlib.sha256)
|
||||
|
||||
self.assertEqual(d1.hexdigest(), d2.hexdigest())
|
||||
self.assertEqual(d1.name, d2.name)
|
||||
self.assertIs(type(d1), type(d2))
|
||||
self.assertEqual(d1.hexdigest(), d2.hexdigest())
|
||||
self.assertEqual(d1.name, d2.name)
|
||||
self.assertIs(type(d1), type(d2))
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with open(fp.name, "r") as f:
|
||||
hashlib.file_digest(f, "sha256")
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with open(fp.name, "wb") as f:
|
||||
hashlib.file_digest(f, "sha256")
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
hashlib.file_digest(None, "sha256")
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with open(os_helper.TESTFN, "r") as f:
|
||||
hashlib.file_digest(f, "sha256")
|
||||
class NonBlocking:
|
||||
def readinto(self, buf):
|
||||
return None
|
||||
def readable(self):
|
||||
return True
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with open(os_helper.TESTFN, "wb") as f:
|
||||
hashlib.file_digest(f, "sha256")
|
||||
with self.assertRaises(BlockingIOError):
|
||||
hashlib.file_digest(NonBlocking(), hashlib.sha256)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
1
Lib/test/test_hmac.py
vendored
1
Lib/test/test_hmac.py
vendored
@@ -1583,7 +1583,6 @@ class PyMiscellaneousTests(unittest.TestCase):
|
||||
hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash)
|
||||
self.fail('Expected warning about small block_size')
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AttributeError: module '_hashlib' has no attribute 'hmac_digest'
|
||||
@hashlib_helper.requires_hashdigest('sha256')
|
||||
def test_with_fallback(self):
|
||||
cache = getattr(hashlib, '__builtin_constructor_cache')
|
||||
|
||||
1
Lib/test/test_inspect/test_inspect.py
vendored
1
Lib/test/test_inspect/test_inspect.py
vendored
@@ -5161,7 +5161,6 @@ class TestSignatureObject(unittest.TestCase):
|
||||
sig = test.__signature__ = inspect.Signature(parameters=(spam_param,))
|
||||
self.assertEqual(sig, inspect.signature(test))
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; Ellipsis)
|
||||
def test_signature_on_mangled_parameters(self):
|
||||
class Spam:
|
||||
def foo(self, __p1:1=2, *, __p2:2=3):
|
||||
|
||||
1
Lib/test/test_keywordonlyarg.py
vendored
1
Lib/test/test_keywordonlyarg.py
vendored
@@ -156,7 +156,6 @@ class KeywordOnlyArgTestCase(unittest.TestCase):
|
||||
# used to fail with a SystemError.
|
||||
lambda *, k1=unittest: None
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_mangling(self):
|
||||
class X:
|
||||
def f(self, *, __a=42):
|
||||
|
||||
1
Lib/test/test_positional_only_arg.py
vendored
1
Lib/test/test_positional_only_arg.py
vendored
@@ -338,7 +338,6 @@ class PositionalOnlyTestCase(unittest.TestCase):
|
||||
|
||||
self.assertEqual(f(42), (42, {}))
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_mangling(self):
|
||||
class X:
|
||||
def f(self, __a=42, /):
|
||||
|
||||
2
Lib/test/test_smtplib.py
vendored
2
Lib/test/test_smtplib.py
vendored
@@ -1176,7 +1176,6 @@ class SMTPSimTests(unittest.TestCase):
|
||||
finally:
|
||||
smtp.close()
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
@hashlib_helper.requires_hashdigest('md5', openssl=True)
|
||||
def testAUTH_CRAM_MD5(self):
|
||||
self.serv.add_feature("AUTH CRAM-MD5")
|
||||
@@ -1229,7 +1228,6 @@ class SMTPSimTests(unittest.TestCase):
|
||||
self.assertEqual(resp, (235, b'Authentication Succeeded'))
|
||||
smtp.close()
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON
|
||||
def test_auth_function(self):
|
||||
supported = {'PLAIN', 'LOGIN'}
|
||||
try:
|
||||
|
||||
@@ -3717,7 +3717,7 @@ impl Compiler {
|
||||
// Compile kwdefaults and build dict
|
||||
for (arg, default) in &kw_with_defaults {
|
||||
self.emit_load_const(ConstantData::Str {
|
||||
value: arg.name.as_str().into(),
|
||||
value: self.mangle(arg.name.as_str()).into_owned().into(),
|
||||
});
|
||||
self.compile_expression(default)?;
|
||||
}
|
||||
@@ -6983,7 +6983,7 @@ impl Compiler {
|
||||
let default_kw_count = kw_with_defaults.len();
|
||||
for (arg, default) in &kw_with_defaults {
|
||||
self.emit_load_const(ConstantData::Str {
|
||||
value: arg.name.as_str().into(),
|
||||
value: self.mangle(arg.name.as_str()).into_owned().into(),
|
||||
});
|
||||
self.compile_expression(default)?;
|
||||
}
|
||||
|
||||
@@ -61,12 +61,14 @@ rand_core = { workspace = true }
|
||||
mt19937 = "3.1"
|
||||
|
||||
# Crypto:
|
||||
digest = "0.10.3"
|
||||
digest = "0.10.7"
|
||||
md-5 = "0.10.1"
|
||||
sha-1 = "0.10.0"
|
||||
sha2 = "0.10.2"
|
||||
sha3 = "0.10.1"
|
||||
blake2 = "0.10.4"
|
||||
hmac = "0.12"
|
||||
pbkdf2 = { version = "0.12", features = ["hmac"] }
|
||||
|
||||
## unicode stuff
|
||||
unicode_names2 = { workspace = true }
|
||||
|
||||
@@ -9,11 +9,11 @@ mod _blake2 {
|
||||
|
||||
#[pyfunction]
|
||||
fn blake2b(args: BlakeHashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_blake2b(args).into_pyobject(vm))
|
||||
Ok(local_blake2b(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn blake2s(args: BlakeHashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_blake2s(args).into_pyobject(vm))
|
||||
Ok(local_blake2s(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
// spell-checker:ignore usedforsecurity HASHXOF
|
||||
// spell-checker:ignore usedforsecurity HASHXOF hashopenssl dklen
|
||||
// NOTE: Function names like `openssl_md5` match CPython's `_hashopenssl.c` interface
|
||||
// for compatibility, but the implementation uses pure Rust crates (md5, sha2, etc.),
|
||||
// not OpenSSL.
|
||||
|
||||
pub(crate) use _hashlib::module_def;
|
||||
|
||||
@@ -7,7 +10,9 @@ pub mod _hashlib {
|
||||
use crate::common::lock::PyRwLock;
|
||||
use crate::vm::{
|
||||
Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
|
||||
builtins::{PyBytes, PyStrRef, PyTypeRef, PyValueError},
|
||||
builtins::{
|
||||
PyBaseExceptionRef, PyBytes, PyFrozenSet, PyStr, PyStrRef, PyTypeRef, PyValueError,
|
||||
},
|
||||
class::StaticType,
|
||||
convert::ToPyObject,
|
||||
function::{ArgBytesLike, ArgStrOrBytesLike, FuncArgs, OptionalArg},
|
||||
@@ -17,17 +22,59 @@ pub mod _hashlib {
|
||||
use digest::{DynDigest, core_api::BlockSizeUser};
|
||||
use digest::{ExtendableOutput, Update};
|
||||
use dyn_clone::{DynClone, clone_trait_object};
|
||||
use hmac::Mac;
|
||||
use md5::Md5;
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224, Sha256, Sha384, Sha512};
|
||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512, Shake128, Shake256};
|
||||
|
||||
const HASH_ALGORITHMS: &[&str] = &[
|
||||
"md5",
|
||||
"sha1",
|
||||
"sha224",
|
||||
"sha256",
|
||||
"sha384",
|
||||
"sha512",
|
||||
"sha3_224",
|
||||
"sha3_256",
|
||||
"sha3_384",
|
||||
"sha3_512",
|
||||
"shake_128",
|
||||
"shake_256",
|
||||
"blake2b",
|
||||
"blake2s",
|
||||
];
|
||||
|
||||
#[pyattr]
|
||||
const _GIL_MINSIZE: usize = 2048;
|
||||
|
||||
#[pyattr]
|
||||
#[pyexception(name = "UnsupportedDigestmodError", base = PyValueError, impl)]
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
pub struct UnsupportedDigestmodError(PyValueError);
|
||||
|
||||
#[pyattr]
|
||||
fn openssl_md_meth_names(vm: &VirtualMachine) -> PyObjectRef {
|
||||
PyFrozenSet::from_iter(
|
||||
vm,
|
||||
HASH_ALGORITHMS.iter().map(|n| vm.ctx.new_str(*n).into()),
|
||||
)
|
||||
.expect("failed to create openssl_md_meth_names frozenset")
|
||||
.into_ref(&vm.ctx)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
fn _constructors(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let dict = vm.ctx.new_dict();
|
||||
for name in HASH_ALGORITHMS {
|
||||
let s = vm.ctx.new_str(*name);
|
||||
dict.set_item(&*s, s.clone().into(), vm).unwrap();
|
||||
}
|
||||
dict.into()
|
||||
}
|
||||
|
||||
#[derive(FromArgs, Debug)]
|
||||
#[allow(unused)]
|
||||
struct NewHashArgs {
|
||||
@@ -37,15 +84,19 @@ pub mod _hashlib {
|
||||
data: OptionalArg<ArgBytesLike>,
|
||||
#[pyarg(named, default = true)]
|
||||
usedforsecurity: bool,
|
||||
#[pyarg(named, optional)]
|
||||
string: OptionalArg<ArgBytesLike>,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[allow(unused)]
|
||||
pub struct BlakeHashArgs {
|
||||
#[pyarg(positional, optional)]
|
||||
#[pyarg(any, optional)]
|
||||
pub data: OptionalArg<ArgBytesLike>,
|
||||
#[pyarg(named, default = true)]
|
||||
usedforsecurity: bool,
|
||||
#[pyarg(named, optional)]
|
||||
pub string: OptionalArg<ArgBytesLike>,
|
||||
}
|
||||
|
||||
impl From<NewHashArgs> for BlakeHashArgs {
|
||||
@@ -53,6 +104,7 @@ pub mod _hashlib {
|
||||
Self {
|
||||
data: args.data,
|
||||
usedforsecurity: args.usedforsecurity,
|
||||
string: args.string,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,16 +113,19 @@ pub mod _hashlib {
|
||||
#[allow(unused)]
|
||||
pub struct HashArgs {
|
||||
#[pyarg(any, optional)]
|
||||
pub string: OptionalArg<ArgBytesLike>,
|
||||
pub data: OptionalArg<ArgBytesLike>,
|
||||
#[pyarg(named, default = true)]
|
||||
usedforsecurity: bool,
|
||||
#[pyarg(named, optional)]
|
||||
pub string: OptionalArg<ArgBytesLike>,
|
||||
}
|
||||
|
||||
impl From<NewHashArgs> for HashArgs {
|
||||
fn from(args: NewHashArgs) -> Self {
|
||||
Self {
|
||||
string: args.data,
|
||||
data: args.data,
|
||||
usedforsecurity: args.usedforsecurity,
|
||||
string: args.string,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,6 +173,91 @@ pub mod _hashlib {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[allow(unused)]
|
||||
struct HmacDigestArgs {
|
||||
#[pyarg(positional)]
|
||||
key: ArgBytesLike,
|
||||
#[pyarg(positional)]
|
||||
msg: ArgBytesLike,
|
||||
#[pyarg(positional)]
|
||||
digest: PyObjectRef,
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[allow(unused)]
|
||||
struct Pbkdf2HmacArgs {
|
||||
#[pyarg(any)]
|
||||
hash_name: PyStrRef,
|
||||
#[pyarg(any)]
|
||||
password: ArgBytesLike,
|
||||
#[pyarg(any)]
|
||||
salt: ArgBytesLike,
|
||||
#[pyarg(any)]
|
||||
iterations: i64,
|
||||
#[pyarg(any, optional)]
|
||||
dklen: OptionalArg<PyObjectRef>,
|
||||
}
|
||||
|
||||
fn resolve_data(
|
||||
data: OptionalArg<ArgBytesLike>,
|
||||
string: OptionalArg<ArgBytesLike>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<OptionalArg<ArgBytesLike>> {
|
||||
match (data.into_option(), string.into_option()) {
|
||||
(Some(d), None) => Ok(OptionalArg::Present(d)),
|
||||
(None, Some(s)) => Ok(OptionalArg::Present(s)),
|
||||
(None, None) => Ok(OptionalArg::Missing),
|
||||
(Some(_), Some(_)) => Err(vm.new_type_error(
|
||||
"'data' and 'string' are mutually exclusive \
|
||||
and support for 'string' keyword parameter \
|
||||
is slated for removal in a future version."
|
||||
.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_digestmod(digestmod: &PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
|
||||
if let Some(name) = digestmod.downcast_ref::<PyStr>() {
|
||||
return Ok(name.as_str().to_lowercase());
|
||||
}
|
||||
if let Ok(name_obj) = digestmod.get_attr("__name__", vm)
|
||||
&& let Some(name) = name_obj.downcast_ref::<PyStr>()
|
||||
&& let Some(algo) = name.as_str().strip_prefix("openssl_")
|
||||
{
|
||||
return Ok(algo.to_owned());
|
||||
}
|
||||
Err(vm.new_exception_msg(
|
||||
UnsupportedDigestmodError::static_type().to_owned(),
|
||||
"unsupported digestmod".to_owned(),
|
||||
))
|
||||
}
|
||||
|
||||
fn hash_digest_size(name: &str) -> Option<usize> {
|
||||
match name {
|
||||
"md5" => Some(16),
|
||||
"sha1" => Some(20),
|
||||
"sha224" => Some(28),
|
||||
"sha256" => Some(32),
|
||||
"sha384" => Some(48),
|
||||
"sha512" => Some(64),
|
||||
"sha3_224" => Some(28),
|
||||
"sha3_256" => Some(32),
|
||||
"sha3_384" => Some(48),
|
||||
"sha3_512" => Some(64),
|
||||
"blake2b" => Some(64),
|
||||
"blake2s" => Some(32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn unsupported_hash(name: &str, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
vm.new_exception_msg(
|
||||
UnsupportedDigestmodError::static_type().to_owned(),
|
||||
format!("unsupported hash type {name}"),
|
||||
)
|
||||
}
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(module = "_hashlib", name = "HASH")]
|
||||
#[derive(PyPayload)]
|
||||
@@ -309,93 +449,163 @@ pub mod _hashlib {
|
||||
|
||||
#[pyfunction(name = "new")]
|
||||
fn hashlib_new(args: NewHashArgs, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
match args.name.as_str().to_lowercase().as_str() {
|
||||
"md5" => Ok(local_md5(args.into()).into_pyobject(vm)),
|
||||
"sha1" => Ok(local_sha1(args.into()).into_pyobject(vm)),
|
||||
"sha224" => Ok(local_sha224(args.into()).into_pyobject(vm)),
|
||||
"sha256" => Ok(local_sha256(args.into()).into_pyobject(vm)),
|
||||
"sha384" => Ok(local_sha384(args.into()).into_pyobject(vm)),
|
||||
"sha512" => Ok(local_sha512(args.into()).into_pyobject(vm)),
|
||||
"sha3_224" => Ok(local_sha3_224(args.into()).into_pyobject(vm)),
|
||||
"sha3_256" => Ok(local_sha3_256(args.into()).into_pyobject(vm)),
|
||||
"sha3_384" => Ok(local_sha3_384(args.into()).into_pyobject(vm)),
|
||||
"sha3_512" => Ok(local_sha3_512(args.into()).into_pyobject(vm)),
|
||||
"shake_128" => Ok(local_shake_128(args.into()).into_pyobject(vm)),
|
||||
"shake_256" => Ok(local_shake_256(args.into()).into_pyobject(vm)),
|
||||
"blake2b" => Ok(local_blake2b(args.into()).into_pyobject(vm)),
|
||||
"blake2s" => Ok(local_blake2s(args.into()).into_pyobject(vm)),
|
||||
"md5" => Ok(PyHasher::new("md5", HashWrapper::new::<Md5>(data)).into_pyobject(vm)),
|
||||
"sha1" => Ok(PyHasher::new("sha1", HashWrapper::new::<Sha1>(data)).into_pyobject(vm)),
|
||||
"sha224" => {
|
||||
Ok(PyHasher::new("sha224", HashWrapper::new::<Sha224>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha256" => {
|
||||
Ok(PyHasher::new("sha256", HashWrapper::new::<Sha256>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha384" => {
|
||||
Ok(PyHasher::new("sha384", HashWrapper::new::<Sha384>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha512" => {
|
||||
Ok(PyHasher::new("sha512", HashWrapper::new::<Sha512>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha3_224" => {
|
||||
Ok(PyHasher::new("sha3_224", HashWrapper::new::<Sha3_224>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha3_256" => {
|
||||
Ok(PyHasher::new("sha3_256", HashWrapper::new::<Sha3_256>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha3_384" => {
|
||||
Ok(PyHasher::new("sha3_384", HashWrapper::new::<Sha3_384>(data)).into_pyobject(vm))
|
||||
}
|
||||
"sha3_512" => {
|
||||
Ok(PyHasher::new("sha3_512", HashWrapper::new::<Sha3_512>(data)).into_pyobject(vm))
|
||||
}
|
||||
"shake_128" => Ok(
|
||||
PyHasherXof::new("shake_128", HashXofWrapper::new_shake_128(data))
|
||||
.into_pyobject(vm),
|
||||
),
|
||||
"shake_256" => Ok(
|
||||
PyHasherXof::new("shake_256", HashXofWrapper::new_shake_256(data))
|
||||
.into_pyobject(vm),
|
||||
),
|
||||
"blake2b" => Ok(
|
||||
PyHasher::new("blake2b", HashWrapper::new::<Blake2b512>(data)).into_pyobject(vm),
|
||||
),
|
||||
"blake2s" => Ok(
|
||||
PyHasher::new("blake2s", HashWrapper::new::<Blake2s256>(data)).into_pyobject(vm),
|
||||
),
|
||||
other => Err(vm.new_value_error(format!("Unknown hashing algorithm: {other}"))),
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_md5")]
|
||||
pub fn local_md5(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("md5", HashWrapper::new::<Md5>(args.string))
|
||||
pub fn local_md5(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new("md5", HashWrapper::new::<Md5>(data)))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha1")]
|
||||
pub fn local_sha1(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha1", HashWrapper::new::<Sha1>(args.string))
|
||||
pub fn local_sha1(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new("sha1", HashWrapper::new::<Sha1>(data)))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha224")]
|
||||
pub fn local_sha224(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha224", HashWrapper::new::<Sha224>(args.string))
|
||||
pub fn local_sha224(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new("sha224", HashWrapper::new::<Sha224>(data)))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha256")]
|
||||
pub fn local_sha256(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha256", HashWrapper::new::<Sha256>(args.string))
|
||||
pub fn local_sha256(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new("sha256", HashWrapper::new::<Sha256>(data)))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha384")]
|
||||
pub fn local_sha384(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha384", HashWrapper::new::<Sha384>(args.string))
|
||||
pub fn local_sha384(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new("sha384", HashWrapper::new::<Sha384>(data)))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha512")]
|
||||
pub fn local_sha512(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha512", HashWrapper::new::<Sha512>(args.string))
|
||||
pub fn local_sha512(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new("sha512", HashWrapper::new::<Sha512>(data)))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha3_224")]
|
||||
pub fn local_sha3_224(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha3_224", HashWrapper::new::<Sha3_224>(args.string))
|
||||
pub fn local_sha3_224(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new(
|
||||
"sha3_224",
|
||||
HashWrapper::new::<Sha3_224>(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha3_256")]
|
||||
pub fn local_sha3_256(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha3_256", HashWrapper::new::<Sha3_256>(args.string))
|
||||
pub fn local_sha3_256(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new(
|
||||
"sha3_256",
|
||||
HashWrapper::new::<Sha3_256>(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha3_384")]
|
||||
pub fn local_sha3_384(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha3_384", HashWrapper::new::<Sha3_384>(args.string))
|
||||
pub fn local_sha3_384(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new(
|
||||
"sha3_384",
|
||||
HashWrapper::new::<Sha3_384>(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_sha3_512")]
|
||||
pub fn local_sha3_512(args: HashArgs) -> PyHasher {
|
||||
PyHasher::new("sha3_512", HashWrapper::new::<Sha3_512>(args.string))
|
||||
pub fn local_sha3_512(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new(
|
||||
"sha3_512",
|
||||
HashWrapper::new::<Sha3_512>(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_shake_128")]
|
||||
pub fn local_shake_128(args: HashArgs) -> PyHasherXof {
|
||||
PyHasherXof::new("shake_128", HashXofWrapper::new_shake_128(args.string))
|
||||
pub fn local_shake_128(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasherXof> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasherXof::new(
|
||||
"shake_128",
|
||||
HashXofWrapper::new_shake_128(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_shake_256")]
|
||||
pub fn local_shake_256(args: HashArgs) -> PyHasherXof {
|
||||
PyHasherXof::new("shake_256", HashXofWrapper::new_shake_256(args.string))
|
||||
pub fn local_shake_256(args: HashArgs, vm: &VirtualMachine) -> PyResult<PyHasherXof> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasherXof::new(
|
||||
"shake_256",
|
||||
HashXofWrapper::new_shake_256(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_blake2b")]
|
||||
pub fn local_blake2b(args: BlakeHashArgs) -> PyHasher {
|
||||
PyHasher::new("blake2b", HashWrapper::new::<Blake2b512>(args.data))
|
||||
pub fn local_blake2b(args: BlakeHashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new(
|
||||
"blake2b",
|
||||
HashWrapper::new::<Blake2b512>(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction(name = "openssl_blake2s")]
|
||||
pub fn local_blake2s(args: BlakeHashArgs) -> PyHasher {
|
||||
PyHasher::new("blake2s", HashWrapper::new::<Blake2s256>(args.data))
|
||||
pub fn local_blake2s(args: BlakeHashArgs, vm: &VirtualMachine) -> PyResult<PyHasher> {
|
||||
let data = resolve_data(args.data, args.string, vm)?;
|
||||
Ok(PyHasher::new(
|
||||
"blake2s",
|
||||
HashWrapper::new::<Blake2s256>(data),
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_fips_mode() -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -434,7 +644,6 @@ pub mod _hashlib {
|
||||
|
||||
#[pyfunction]
|
||||
fn hmac_new(args: NewHMACHashArgs, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
// Raise UnsupportedDigestmodError so Python's hmac.py falls back to pure-Python implementation
|
||||
let _ = args;
|
||||
Err(vm.new_exception_msg(
|
||||
UnsupportedDigestmodError::static_type().to_owned(),
|
||||
@@ -442,12 +651,94 @@ pub mod _hashlib {
|
||||
))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn hmac_digest(args: HmacDigestArgs, vm: &VirtualMachine) -> PyResult<PyBytes> {
|
||||
let name = resolve_digestmod(&args.digest, vm)?;
|
||||
|
||||
let key_buf = args.key.borrow_buf();
|
||||
let msg_buf = args.msg.borrow_buf();
|
||||
|
||||
macro_rules! do_hmac {
|
||||
($hash_ty:ty) => {{
|
||||
let mut mac = <hmac::Hmac<$hash_ty> as Mac>::new_from_slice(&key_buf)
|
||||
.map_err(|_| vm.new_value_error("invalid key length".to_owned()))?;
|
||||
Mac::update(&mut mac, &msg_buf);
|
||||
Ok(mac.finalize().into_bytes().to_vec().into())
|
||||
}};
|
||||
}
|
||||
|
||||
match name.as_str() {
|
||||
"md5" => do_hmac!(Md5),
|
||||
"sha1" => do_hmac!(Sha1),
|
||||
"sha224" => do_hmac!(Sha224),
|
||||
"sha256" => do_hmac!(Sha256),
|
||||
"sha384" => do_hmac!(Sha384),
|
||||
"sha512" => do_hmac!(Sha512),
|
||||
"sha3_224" => do_hmac!(Sha3_224),
|
||||
"sha3_256" => do_hmac!(Sha3_256),
|
||||
"sha3_384" => do_hmac!(Sha3_384),
|
||||
"sha3_512" => do_hmac!(Sha3_512),
|
||||
_ => Err(unsupported_hash(&name, vm)),
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn pbkdf2_hmac(args: Pbkdf2HmacArgs, vm: &VirtualMachine) -> PyResult<PyBytes> {
|
||||
let name = args.hash_name.as_str().to_lowercase();
|
||||
|
||||
if args.iterations < 1 {
|
||||
return Err(vm.new_value_error("iteration value must be greater than 0.".to_owned()));
|
||||
}
|
||||
let rounds = u32::try_from(args.iterations)
|
||||
.map_err(|_| vm.new_overflow_error("iteration value is too great.".to_owned()))?;
|
||||
|
||||
let dklen: usize = match args.dklen.into_option() {
|
||||
Some(obj) if vm.is_none(&obj) => {
|
||||
hash_digest_size(&name).ok_or_else(|| unsupported_hash(&name, vm))?
|
||||
}
|
||||
Some(obj) => {
|
||||
let len: i64 = obj.try_into_value(vm)?;
|
||||
if len < 1 {
|
||||
return Err(vm.new_value_error("key length must be greater than 0.".to_owned()));
|
||||
}
|
||||
usize::try_from(len).map_err(|_| {
|
||||
vm.new_overflow_error("key length is too great.".to_owned())
|
||||
})?
|
||||
}
|
||||
None => hash_digest_size(&name).ok_or_else(|| unsupported_hash(&name, vm))?,
|
||||
};
|
||||
|
||||
let password_buf = args.password.borrow_buf();
|
||||
let salt_buf = args.salt.borrow_buf();
|
||||
let mut dk = vec![0u8; dklen];
|
||||
|
||||
macro_rules! do_pbkdf2 {
|
||||
($hash_ty:ty) => {{
|
||||
pbkdf2::pbkdf2_hmac::<$hash_ty>(&password_buf, &salt_buf, rounds, &mut dk);
|
||||
Ok(dk.into())
|
||||
}};
|
||||
}
|
||||
|
||||
match name.as_str() {
|
||||
"md5" => do_pbkdf2!(Md5),
|
||||
"sha1" => do_pbkdf2!(Sha1),
|
||||
"sha224" => do_pbkdf2!(Sha224),
|
||||
"sha256" => do_pbkdf2!(Sha256),
|
||||
"sha384" => do_pbkdf2!(Sha384),
|
||||
"sha512" => do_pbkdf2!(Sha512),
|
||||
"sha3_224" => do_pbkdf2!(Sha3_224),
|
||||
"sha3_256" => do_pbkdf2!(Sha3_256),
|
||||
"sha3_384" => do_pbkdf2!(Sha3_384),
|
||||
"sha3_512" => do_pbkdf2!(Sha3_512),
|
||||
_ => Err(unsupported_hash(&name, vm)),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ThreadSafeDynDigest: DynClone + DynDigest + Sync + Send {}
|
||||
impl<T> ThreadSafeDynDigest for T where T: DynClone + DynDigest + Sync + Send {}
|
||||
|
||||
clone_trait_object!(ThreadSafeDynDigest);
|
||||
|
||||
/// Generic wrapper patching around the hashing libraries.
|
||||
#[derive(Clone)]
|
||||
pub struct HashWrapper {
|
||||
block_size: usize,
|
||||
|
||||
@@ -7,6 +7,6 @@ mod _md5 {
|
||||
|
||||
#[pyfunction]
|
||||
fn md5(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_md5(args).into_pyobject(vm))
|
||||
Ok(local_md5(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@ mod _sha1 {
|
||||
|
||||
#[pyfunction]
|
||||
fn sha1(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha1(args).into_pyobject(vm))
|
||||
Ok(local_sha1(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ mod _sha256 {
|
||||
|
||||
#[pyfunction]
|
||||
fn sha224(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha224(args).into_pyobject(vm))
|
||||
Ok(local_sha224(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn sha256(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha256(args).into_pyobject(vm))
|
||||
Ok(local_sha256(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
|
||||
@@ -10,31 +10,31 @@ mod _sha3 {
|
||||
|
||||
#[pyfunction]
|
||||
fn sha3_224(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha3_224(args).into_pyobject(vm))
|
||||
Ok(local_sha3_224(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn sha3_256(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha3_256(args).into_pyobject(vm))
|
||||
Ok(local_sha3_256(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn sha3_384(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha3_384(args).into_pyobject(vm))
|
||||
Ok(local_sha3_384(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn sha3_512(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha3_512(args).into_pyobject(vm))
|
||||
Ok(local_sha3_512(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn shake_128(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_shake_128(args).into_pyobject(vm))
|
||||
Ok(local_shake_128(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn shake_256(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_shake_256(args).into_pyobject(vm))
|
||||
Ok(local_shake_256(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ mod _sha512 {
|
||||
|
||||
#[pyfunction]
|
||||
fn sha384(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha384(args).into_pyobject(vm))
|
||||
Ok(local_sha384(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn sha512(args: HashArgs, vm: &VirtualMachine) -> PyResult {
|
||||
Ok(local_sha512(args).into_pyobject(vm))
|
||||
Ok(local_sha512(args, vm)?.into_pyobject(vm))
|
||||
}
|
||||
|
||||
pub(crate) fn module_exec(vm: &VirtualMachine, module: &Py<PyModule>) -> PyResult<()> {
|
||||
|
||||
@@ -397,7 +397,7 @@ impl VirtualMachine {
|
||||
)?;
|
||||
let mode = if write { "w" } else { "r" };
|
||||
stdio.set_attr("mode", self.ctx.new_str(mode), self)?;
|
||||
Ok(stdio)
|
||||
Ok::<_, self::PyBaseExceptionRef>(stdio)
|
||||
};
|
||||
|
||||
// Sandbox stdio: lightweight wrapper using Rust's std::io directly
|
||||
|
||||
Reference in New Issue
Block a user