[pypy-commit] pypy py3.5-ssl: copy over _hashlib from pypy/modules to lib_pypy and start to rewrite first functions
plan_rich
pypy.commits at gmail.com
Mon Nov 28 11:32:23 EST 2016
Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-ssl
Changeset: r88707:9c52653f210c
Date: 2016-11-28 17:31 +0100
http://bitbucket.org/pypy/pypy/changeset/9c52653f210c/
Log: copy over _hashlib from pypy/modules to lib_pypy and start to
rewrite first functions
diff --git a/pypy/module/_hashlib/__init__.py b/pypy/module/_hashlib/__init__.py
deleted file mode 100644
--- a/pypy/module/_hashlib/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module._hashlib.interp_hashlib import (
- algorithms, fetch_names, HAS_FAST_PKCS5_PBKDF2_HMAC)
-
-
-class Module(MixedModule):
- interpleveldefs = {
- 'new' : 'interp_hashlib.new',
- }
-
- appleveldefs = {
- }
-
- for name in algorithms:
- interpleveldefs['openssl_' + name] = 'interp_hashlib.new_' + name
-
- if HAS_FAST_PKCS5_PBKDF2_HMAC:
- interpleveldefs['pbkdf2_hmac'] = 'interp_hashlib.pbkdf2_hmac'
-
- def startup(self, space):
- w_meth_names = fetch_names(space)
- space.setattr(self, space.wrap('openssl_md_meth_names'), w_meth_names)
diff --git a/pypy/module/_hashlib/interp_hashlib.py b/pypy/module/_hashlib/interp_hashlib.py
deleted file mode 100644
--- a/pypy/module/_hashlib/interp_hashlib.py
+++ /dev/null
@@ -1,209 +0,0 @@
-from __future__ import with_statement
-
-from rpython.rlib import rgc, ropenssl
-from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.rstring import StringBuilder
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.tool.sourcetools import func_renamer
-
-from pypy.interpreter.baseobjspace import W_Root
-from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.gateway import unwrap_spec, interp2app, WrappedDefault
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.module.thread.os_lock import Lock
-
-
-algorithms = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
-
-def hash_name_mapper_callback(obj_name, userdata):
- if not obj_name:
- return
- # Ignore aliased names, they pollute the list and OpenSSL appears
- # to have a its own definition of alias as the resulting list
- # still contains duplicate and alternate names for several
- # algorithms.
- if rffi.cast(lltype.Signed, obj_name[0].c_alias):
- return
- try:
- space = global_name_fetcher.space
- w_name = space.wrap(rffi.charp2str(obj_name[0].c_name))
- global_name_fetcher.meth_names.append(w_name)
- except OperationError as e:
- global_name_fetcher.w_error = e
-
-class NameFetcher:
- def setup(self, space):
- self.space = space
- self.meth_names = []
- self.w_error = None
- def _cleanup_(self):
- self.__dict__.clear()
-global_name_fetcher = NameFetcher()
-
-def fetch_names(space):
- global_name_fetcher.setup(space)
- ropenssl.init_digests()
- ropenssl.OBJ_NAME_do_all(ropenssl.OBJ_NAME_TYPE_MD_METH,
- hash_name_mapper_callback, None)
- if global_name_fetcher.w_error:
- raise global_name_fetcher.w_error
- meth_names = global_name_fetcher.meth_names
- global_name_fetcher.meth_names = None
- return space.call_function(space.w_frozenset, space.newlist(meth_names))
-
-class W_Hash(W_Root):
- NULL_CTX = lltype.nullptr(ropenssl.EVP_MD_CTX.TO)
- ctx = NULL_CTX
-
- def __init__(self, space, name, copy_from=NULL_CTX):
- self.name = name
- digest_type = self.digest_type_by_name(space)
- self.digest_size = ropenssl.EVP_MD_size(digest_type)
-
- # Allocate a lock for each HASH object.
- # An optimization would be to not release the GIL on small requests,
- # and use a custom lock only when needed.
- self.lock = Lock(space)
-
- ctx = ropenssl.EVP_MD_CTX_new()
- if ctx is None:
- raise MemoryError
- rgc.add_memory_pressure(ropenssl.HASH_MALLOC_SIZE + self.digest_size)
- try:
- if copy_from:
- if not ropenssl.EVP_MD_CTX_copy(ctx, copy_from):
- raise ValueError
- else:
- ropenssl.EVP_DigestInit(ctx, digest_type)
- self.ctx = ctx
- except:
- ropenssl.EVP_MD_CTX_free(ctx)
- raise
- self.register_finalizer(space)
-
- def _finalize_(self):
- ctx = self.ctx
- if ctx:
- self.ctx = lltype.nullptr(ropenssl.EVP_MD_CTX.TO)
- ropenssl.EVP_MD_CTX_free(ctx)
-
- def digest_type_by_name(self, space):
- digest_type = ropenssl.EVP_get_digestbyname(self.name)
- if not digest_type:
- raise oefmt(space.w_ValueError, "unknown hash function")
- return digest_type
-
- def descr_repr(self, space):
- addrstring = self.getaddrstring(space)
- return space.wrap("<%s HASH object at 0x%s>" % (
- self.name, addrstring))
-
- @unwrap_spec(string='bufferstr')
- def update(self, space, string):
- with rffi.scoped_nonmovingbuffer(string) as buf:
- with self.lock:
- # XXX try to not release the GIL for small requests
- ropenssl.EVP_DigestUpdate(self.ctx, buf, len(string))
-
- def copy(self, space):
- "Return a copy of the hash object."
- with self.lock:
- return W_Hash(space, self.name, copy_from=self.ctx)
-
- def digest(self, space):
- "Return the digest value as a string of binary data."
- digest = self._digest(space)
- return space.newbytes(digest)
-
- def hexdigest(self, space):
- "Return the digest value as a string of hexadecimal digits."
- digest = self._digest(space)
- hexdigits = '0123456789abcdef'
- result = StringBuilder(self.digest_size * 2)
- for c in digest:
- result.append(hexdigits[(ord(c) >> 4) & 0xf])
- result.append(hexdigits[ ord(c) & 0xf])
- return space.wrap(result.build())
-
- def get_digest_size(self, space):
- return space.wrap(self.digest_size)
-
- def get_block_size(self, space):
- digest_type = self.digest_type_by_name(space)
- block_size = ropenssl.EVP_MD_block_size(digest_type)
- return space.wrap(block_size)
-
- def get_name(self, space):
- return space.wrap(self.name)
-
- def _digest(self, space):
- ctx = ropenssl.EVP_MD_CTX_new()
- if ctx is None:
- raise MemoryError
- try:
- with self.lock:
- if not ropenssl.EVP_MD_CTX_copy(ctx, self.ctx):
- raise ValueError
- digest_size = self.digest_size
- with rffi.scoped_alloc_buffer(digest_size) as buf:
- ropenssl.EVP_DigestFinal(ctx, buf.raw, None)
- return buf.str(digest_size)
- finally:
- ropenssl.EVP_MD_CTX_free(ctx)
-
-
-W_Hash.typedef = TypeDef(
- 'HASH',
- __repr__=interp2app(W_Hash.descr_repr),
- update=interp2app(W_Hash.update),
- copy=interp2app(W_Hash.copy),
- digest=interp2app(W_Hash.digest),
- hexdigest=interp2app(W_Hash.hexdigest),
- #
- digest_size=GetSetProperty(W_Hash.get_digest_size),
- block_size=GetSetProperty(W_Hash.get_block_size),
- name=GetSetProperty(W_Hash.get_name),
-)
-W_Hash.typedef.acceptable_as_base_class = False
-
- at unwrap_spec(name=str, string='bufferstr')
-def new(space, name, string=''):
- w_hash = W_Hash(space, name)
- w_hash.update(space, string)
- return space.wrap(w_hash)
-
-# shortcut functions
-def make_new_hash(name, funcname):
- @func_renamer(funcname)
- @unwrap_spec(string='bufferstr')
- def new_hash(space, string=''):
- return new(space, name, string)
- return new_hash
-
-for _name in algorithms:
- _newname = 'new_%s' % (_name,)
- globals()[_newname] = make_new_hash(_name, _newname)
-
-
-HAS_FAST_PKCS5_PBKDF2_HMAC = ropenssl.PKCS5_PBKDF2_HMAC is not None
-if HAS_FAST_PKCS5_PBKDF2_HMAC:
- @unwrap_spec(name=str, password='bytes', salt='bytes', rounds=int,
- w_dklen=WrappedDefault(None))
- def pbkdf2_hmac(space, name, password, salt, rounds, w_dklen):
- digest = ropenssl.EVP_get_digestbyname(name)
- if not digest:
- raise oefmt(space.w_ValueError, "unknown hash function")
- if space.is_w(w_dklen, space.w_None):
- dklen = ropenssl.EVP_MD_size(digest)
- else:
- dklen = space.int_w(w_dklen)
- if dklen < 1:
- raise oefmt(space.w_ValueError,
- "key length must be greater than 0.")
- with rffi.scoped_alloc_buffer(dklen) as buf:
- r = ropenssl.PKCS5_PBKDF2_HMAC(
- password, len(password), salt, len(salt), rounds, digest,
- dklen, buf.raw)
- if not r:
- raise ValueError
- return space.newbytes(buf.str(dklen))
diff --git a/pypy/module/_hashlib/test/test_hashlib.py b/pypy/module/_hashlib/test/test_hashlib.py
deleted file mode 100644
--- a/pypy/module/_hashlib/test/test_hashlib.py
+++ /dev/null
@@ -1,100 +0,0 @@
-class AppTestHashlib:
- spaceconfig = {
- "usemodules": ['_hashlib', 'array', 'struct', 'binascii'],
- }
-
- def test_method_names(self):
- import _hashlib
- assert isinstance(_hashlib.openssl_md_meth_names, frozenset)
- assert "md5" in _hashlib.openssl_md_meth_names
-
- def test_simple(self):
- import _hashlib
- assert _hashlib.new('md5').__class__.__name__ == 'HASH'
- assert len(_hashlib.new('md5').hexdigest()) == 32
-
- def test_attributes(self):
- import hashlib
- for name, (expected_size, expected_block_size) in {
- 'md5': (16, 64),
- 'sha1': (20, 64),
- 'sha224': (28, 64),
- 'sha256': (32, 64),
- 'sha384': (48, 128),
- 'sha512': (64, 128),
- }.items():
- h = hashlib.new(name)
- assert h.name == name
- assert h.digest_size == expected_size
- assert h.block_size == expected_block_size
- #
- h.update(b'abc')
- h2 = h.copy()
- h.update(b'def')
- digest = h.digest()
- hexdigest = h.hexdigest()
- h2.update(b'd')
- h2.update(b'ef')
- assert digest == h2.digest()
- assert hexdigest == h2.hexdigest()
- assert len(digest) == h.digest_size
- assert len(hexdigest) == h.digest_size * 2
- c_digest = digest
- c_hexdigest = hexdigest
-
-
- def test_shortcut(self):
- import hashlib
- assert repr(hashlib.md5()).startswith("<md5 HASH object")
-
- def test_uppercase(self):
- import _hashlib
- h = _hashlib.new('MD5')
- assert h.digest_size == 16
- assert len(h.hexdigest()) == 32
-
- def test_buffer(self):
- import _hashlib, array
- b = array.array('b', b'x' * 10)
- h = _hashlib.new('md5', b)
- h.update(b)
- assert h.digest() == _hashlib.openssl_md5(b'x' * 20).digest()
- _hashlib.openssl_sha1(b).digest()
-
- def test_extra_algorithms(self):
- expected_results = {
- "md5": "bb649c83dd1ea5c9d9dec9a18df0ffe9",
- "md4": "c275b8454684ea416b93d7a418b43176",
- "mdc2": None, # XXX find the correct expected value
- "sha": "e2b0a8609b47c58e5d984c9ccfe69f9b654b032b",
- "ripemd160": "cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc",
- "whirlpool": ("1a22b79fe5afda02c63a25927193ed01dc718b74"
- "026e597608ce431f9c3d2c9e74a7350b7fbb7c5d"
- "4effe5d7a31879b8b7a10fd2f544c4ca268ecc6793923583"),
- }
- import _hashlib
- test_string = b"Nobody inspects the spammish repetition"
- for hash_name, expected in sorted(expected_results.items()):
- try:
- m = _hashlib.new(hash_name)
- except ValueError as e:
- print('skipped %s: %s' % (hash_name, e))
- continue
- m.update(test_string)
- got = m.hexdigest()
- assert got and type(got) is str and len(got) % 2 == 0
- if expected is not None:
- assert got == expected
-
- def test_pbkdf2(self):
- try:
- from _hashlib import pbkdf2_hmac
- except ImportError:
- skip("Requires OpenSSL >= 1.1")
- out = pbkdf2_hmac('sha1', b'password', b'salt', 1)
- assert type(out) is bytes
- assert out == '0c60c80f961f0e71f3a9b524af6012062fe037a6'.decode('hex')
- out = pbkdf2_hmac('sha1', b'password', b'salt', 2, None)
- assert out == 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'.decode('hex')
- raises(TypeError, pbkdf2_hmac, 'sha1', 'password', b'salt', 1)
- raises(TypeError, pbkdf2_hmac, 'sha1', b'password', 'salt', 1)
diff --git a/pypy/module/_hashlib/test/test_ztranslation.py b/pypy/module/_hashlib/test/test_ztranslation.py
deleted file mode 100644
--- a/pypy/module/_hashlib/test/test_ztranslation.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from pypy.objspace.fake.checkmodule import checkmodule
-
-def test_checkmodule():
- checkmodule('_hashlib')
diff --git a/pypy/tool/build_cffi_imports.py b/pypy/tool/build_cffi_imports.py
--- a/pypy/tool/build_cffi_imports.py
+++ b/pypy/tool/build_cffi_imports.py
@@ -18,6 +18,7 @@
"lzma": "_lzma_build.py",
"_decimal": "_decimal_build.py",
"ssl": "_ssl_build.py",
+ # hashlib does not need to be built! It uses API calls from ssl
"xx": None, # for testing: 'None' should be completely ignored
}
More information about the pypy-commit
mailing list