[pypy-svn] r77874 - in pypy/branch/fast-forward/pypy: module/_hashlib module/_hashlib/test rlib
afa at codespeak.net
afa at codespeak.net
Wed Oct 13 15:53:09 CEST 2010
Author: afa
Date: Wed Oct 13 15:53:07 2010
New Revision: 77874
Modified:
pypy/branch/fast-forward/pypy/module/_hashlib/interp_hashlib.py
pypy/branch/fast-forward/pypy/module/_hashlib/test/test_hashlib.py
pypy/branch/fast-forward/pypy/rlib/ropenssl.py
Log:
Implement the _hashlib module
Modified: pypy/branch/fast-forward/pypy/module/_hashlib/interp_hashlib.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_hashlib/interp_hashlib.py (original)
+++ pypy/branch/fast-forward/pypy/module/_hashlib/interp_hashlib.py Wed Oct 13 15:53:07 2010
@@ -1,9 +1,10 @@
from pypy.interpreter.gateway import unwrap_spec, interp2app
-from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.tool.sourcetools import func_renamer
from pypy.interpreter.baseobjspace import Wrappable, W_Root, ObjSpace
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib import ropenssl
+from pypy.rlib.rstring import StringBuilder
algorithms = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
@@ -12,37 +13,105 @@
self.name = name
self.ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, flavor='raw')
- @unwrap_spec('self', ObjSpace, str, str)
- def descr_init(self, space, name, buffer):
- digest = ropenssl.EVT_get_digestbyname(name)
+ digest = ropenssl.EVP_get_digestbyname(name)
if not digest:
raise OperationError(space.w_ValueError,
space.wrap("unknown hash function"))
ropenssl.EVP_DigestInit(self.ctx, digest)
- if buffer:
- self._hash(buffer)
-
@unwrap_spec('self', ObjSpace)
def descr_repr(self, space):
return space.wrap("<%s HASH object @ 0x%x>" % (self.name, id(self)))
@unwrap_spec('self', ObjSpace, str)
def update(self, space, buffer):
- self._hash(buffer)
-
- def _hash(self, buffer):
buf = rffi.str2charp(buffer)
try:
ropenssl.EVP_DigestUpdate(self.ctx, buf, len(buffer))
finally:
rffi.free_charp(buf)
+ @unwrap_spec('self', ObjSpace)
+ def copy(self, space):
+ "Return a copy of the hash object."
+ w_hash = W_Hash(self.name)
+ ropenssl.EVP_MD_CTX_copy(w_hash.ctx, self.ctx)
+ return w_hash
+
+ @unwrap_spec('self', ObjSpace)
+ def digest(self, space):
+ "Return the digest value as a string of binary data."
+ digest = self._digest(space)
+ return space.wrap(digest)
+
+ @unwrap_spec('self', ObjSpace)
+ 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(space, self):
+ return space.wrap(self._digest_size())
+
+ def get_block_size(space, self):
+ return space.wrap(self._block_size())
+
+ def _digest(self, space):
+ ctx = self.copy(space).ctx
+ digest_size = self._digest_size()
+ digest = lltype.malloc(rffi.CCHARP.TO, digest_size, flavor='raw')
+
+ try:
+ ropenssl.EVP_DigestFinal(ctx, digest, None)
+ return rffi.charp2strn(digest, digest_size)
+ finally:
+ lltype.free(digest, flavor='raw')
+
+
+ def _digest_size(self):
+ # XXX This isn't the nicest way, but the EVP_MD_size OpenSSL
+ # XXX function is defined as a C macro on OS X and would be
+ # XXX significantly harder to implement in another way.
+ # Values are digest sizes in bytes
+ return {
+ 'md5': 16,
+ 'sha1': 20,
+ 'sha224': 28,
+ 'sha256': 32,
+ 'sha384': 48,
+ 'sha512': 64,
+ }.get(self.name, 0)
+
+ def _block_size(self):
+ # XXX This isn't the nicest way, but the EVP_MD_CTX_block_size
+ # XXX OpenSSL function is defined as a C macro on some systems
+ # XXX and would be significantly harder to implement in
+ # XXX another way.
+ return {
+ 'md5': 64,
+ 'sha1': 64,
+ 'sha224': 64,
+ 'sha256': 64,
+ 'sha384': 128,
+ 'sha512': 128,
+ }.get(self.name, 0)
+
W_Hash.typedef = TypeDef(
'HASH',
- __init__=interp2app(W_Hash.descr_init),
__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),
+ digestsize=GetSetProperty(W_Hash.get_digest_size),
+ block_size=GetSetProperty(W_Hash.get_block_size),
)
@unwrap_spec(ObjSpace, str, str)
Modified: pypy/branch/fast-forward/pypy/module/_hashlib/test/test_hashlib.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_hashlib/test/test_hashlib.py (original)
+++ pypy/branch/fast-forward/pypy/module/_hashlib/test/test_hashlib.py Wed Oct 13 15:53:07 2010
@@ -10,7 +10,7 @@
assert isinstance(_hashlib.new('md5'), _hashlib.HASH)
def test_attributes(self):
- import _hashlib
+ import hashlib
for name, expected_size in {'md5': 16,
'sha1': 20,
'sha224': 28,
@@ -29,8 +29,12 @@
hexdigest = h.hexdigest()
h2.update('d')
h2.update('ef')
- assert digest == h.digest()
- assert hexdigest == h.hexdigest()
+ 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
# also test the pure Python implementation
h = hashlib.__get_builtin_constructor(name)('')
@@ -44,10 +48,14 @@
hexdigest = h.hexdigest()
h2.update('d')
h2.update('ef')
- assert digest == h.digest()
- assert hexdigest == h.hexdigest()
+ assert digest == h2.digest()
+ assert hexdigest == h2.hexdigest()
+
+ # compare both implementations
+ assert c_digest == digest
+ assert c_hexdigest == hexdigest
def test_unicode(self):
import _hashlib
- assert isinstance(hashlib.new('sha1', u'xxx'), _hashlib.HASH)
+ assert isinstance(_hashlib.new('sha1', u'xxx'), _hashlib.HASH)
Modified: pypy/branch/fast-forward/pypy/rlib/ropenssl.py
==============================================================================
--- pypy/branch/fast-forward/pypy/rlib/ropenssl.py (original)
+++ pypy/branch/fast-forward/pypy/rlib/ropenssl.py Wed Oct 13 15:53:07 2010
@@ -16,10 +16,12 @@
# so that openssl/ssl.h can repair this nonsense.
'wincrypt.h',
'openssl/ssl.h',
- 'openssl/err.h']
+ 'openssl/err.h',
+ 'openssl/evp.h']
else:
libraries = ['ssl', 'crypto']
- includes = ['openssl/ssl.h', 'openssl/err.h']
+ includes = ['openssl/ssl.h', 'openssl/err.h',
+ 'openssl/evp.h']
eci = ExternalCompilationInfo(
libraries = libraries,
@@ -176,7 +178,7 @@
ssl_external('SSL_read', [SSL, rffi.CCHARP, rffi.INT], rffi.INT)
-EVP_MD_CTX = rffi.COpaquePtr('EVP_MD_CTX')
+EVP_MD_CTX = rffi.COpaquePtr('EVP_MD_CTX', compilation_info=eci)
EVP_MD = rffi.COpaquePtr('EVP_MD')
EVP_get_digestbyname = external(
@@ -188,6 +190,13 @@
EVP_DigestUpdate = external(
'EVP_DigestUpdate',
[EVP_MD_CTX, rffi.CCHARP, rffi.SIZE_T], rffi.INT)
+EVP_DigestFinal = external(
+ 'EVP_DigestFinal',
+ [EVP_MD_CTX, rffi.CCHARP, rffi.VOIDP], rffi.INT)
+EVP_MD_CTX_copy = external(
+ 'EVP_MD_CTX_copy', [EVP_MD_CTX, EVP_MD_CTX], rffi.INT)
+EVP_MD_CTX_cleanup = external(
+ 'EVP_MD_CTX_cleanup', [EVP_MD_CTX], rffi.INT)
def _init_ssl():
libssl_SSL_load_error_strings()
More information about the Pypy-commit
mailing list