Commit 3a373e2c authored by Stefan Behnel's avatar Stefan Behnel

Make pickle checksum calculation succeed even if one of the hash algorithms is blocked at runtime.

Also, pass "usedforsecurity=False" in Py3.9+ to unblock MD5 also on some security constrained systems (FIPS).

Closes https://github.com/cython/cython/issues/4909
parent 4d626caa
......@@ -8,6 +8,7 @@ cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object,
import copy
import hashlib
import sys
from . import PyrexTypes
from . import Naming
......@@ -1700,24 +1701,9 @@ if VALUE is not None:
if not e.type.is_pyobject:
e.type.create_to_py_utility_code(env)
e.type.create_from_py_utility_code(env)
all_members_names = sorted([e.name for e in all_members])
all_members_names = [e.name for e in all_members]
checksums = _calculate_pickle_checksums(all_members_names)
# Cython 0.x used MD5 for the checksum, which a few Python installations remove for security reasons.
# SHA-256 should be ok for years to come, but early Cython 3.0 alpha releases used SHA-1,
# which may not be.
checksum_algos = []
try:
checksum_algos.append(hashlib.md5)
except AttributeError:
pass
checksum_algos.append(hashlib.sha256)
checksum_algos.append(hashlib.sha1)
member_names_string = ' '.join(all_members_names).encode('utf-8')
checksums = [
'0x' + mkchecksum(member_names_string).hexdigest()[:7]
for mkchecksum in checksum_algos
]
unpickle_func_name = '__pyx_unpickle_%s' % node.class_name
# TODO(robertwb): Move the state into the third argument
......@@ -2136,6 +2122,23 @@ if VALUE is not None:
return property
def _calculate_pickle_checksums(member_names):
# Cython 0.x used MD5 for the checksum, which a few Python installations remove for security reasons.
# SHA-256 should be ok for years to come, but early Cython 3.0 alpha releases used SHA-1,
# which may not be.
member_names_string = ' '.join(member_names).encode('utf-8')
hash_kwargs = {'usedforsecurity': False} if sys.version_info >= (3, 9) else {}
checksums = []
for algo_name in ['md5', 'sha256', 'sha1']:
try:
mkchecksum = getattr(hashlib, algo_name)
checksums.append('0x' + mkchecksum(member_names_string, **hash_kwargs).hexdigest()[:7])
except (AttributeError, ValueError):
# The algorithm (i.e. MD5) might not be there at all, or might be blocked at runtime
continue
return checksums
class CalculateQualifiedNamesTransform(EnvTransform):
"""
Calculate and store the '__qualname__' and the global
......
import os
import os.path
import unittest
from Cython.TestUtils import TransformTest
from Cython.Compiler.ParseTreeTransforms import *
from Cython.Compiler.ParseTreeTransforms import _calculate_pickle_checksums
from Cython.Compiler.Nodes import *
from Cython.Compiler import Main, Symtab
......@@ -276,6 +278,11 @@ class TestDebugTransform(DebuggerTestCase):
raise
class TestAnalyseDeclarationsTransform(unittest.TestCase):
def test_calculate_pickle_checksums(self):
checksums = _calculate_pickle_checksums(['member1', 'member2', 'member3'])
assert 2 <= len(checksums) <= 3, checksums # expecting ['0xc0af380' (MD5), '0x0c75bd4', '0xa7a7b94']
if __name__ == "__main__":
import unittest
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment