-"""\r
- Implements interface to OpenSSL EVP_Digest* functions.\r
-\r
- Interface made as close to hashlib as possible.\r
-\r
- This module is really an excess effort. Hashlib allows access to\r
- mostly same functionality except oids and nids of hashing\r
- algortithms (which might be needed for private key operations).\r
-\r
- hashlib even allows to use engine-provided digests if it is build\r
- with dinamically linked libcrypto - so use\r
- ctypescrypto.engine.set_default("gost",xFFFF) and md_gost94\r
- algorithm would be available both to this module and hashlib.\r
-\r
-"""\r
-from ctypes import c_int, c_char_p, c_void_p, POINTER, c_long,c_longlong, create_string_buffer,byref\r
-from ctypescrypto import libcrypto\r
-from ctypescrypto.exception import LibCryptoError\r
-from ctypescrypto.oid import Oid\r
-DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")\r
-\r
-__all__ = ['DigestError','Digest','DigestType','new']\r
-\r
-class DigestError(LibCryptoError):\r
- pass\r
-\r
-def new(algname):\r
- """\r
- Behaves just like hashlib.new. Creates digest object by\r
- algorithm name\r
- """\r
- md=DigestType(algname)\r
- return Digest(md)\r
-\r
-class DigestType(object):\r
- """\r
- \r
- Represents EVP_MD object - constant structure which describes\r
- digest algorithm\r
-\r
- """\r
- def __init__(self, digest_name):\r
- """\r
- Finds digest by its name. You can pass Oid object instead of\r
- name.\r
-\r
- Special case is when None is passed as name. In this case\r
- unitialized digest is created, and can be initalized later\r
- by setting its digest attribute to pointer to EVP_MD\r
- """\r
- if digest_name is None:\r
- return \r
- if isinstance(digest_name,Oid):\r
- self.digest_name=digest_name.longname()\r
- self.digest=libcrypto.EVP_get_digestbyname(self.digest_name)\r
- else:\r
- self.digest_name = str(digest_name)\r
- self.digest = libcrypto.EVP_get_digestbyname(self.digest_name)\r
- if self.digest is None:\r
- raise DigestError("Unknown digest: %s" % self.digest_name)\r
-\r
- @property\r
- def name(self):\r
- if not hasattr(self,'digest_name'):\r
- self.digest_name=Oid(libcrypto.EVP_MD_type(self.digest)).longname()\r
- return self.digest_name\r
- def __del__(self):\r
- pass\r
- def digest_size(self):\r
- return libcrypto.EVP_MD_size(self.digest)\r
- def block_size(self):\r
- return libcrypto.EVP_MD_block_size(self.digest)\r
- def oid(self):\r
- return Oid(libcrypto.EVP_MD_type(self.digest))\r
-\r
-class Digest(object):\r
- """\r
- Represents EVP_MD_CTX object which actually used to calculate\r
- digests.\r
-\r
- """\r
- def __init__(self,digest_type):\r
- """\r
- Initializes digest using given type.\r
- """\r
- self._clean_ctx()\r
- self.ctx = libcrypto.EVP_MD_CTX_create()\r
- if self.ctx is None:\r
- raise DigestError("Unable to create digest context")\r
- result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)\r
- if result == 0:\r
- self._clean_ctx()\r
- raise DigestError("Unable to initialize digest")\r
- self.digest_type = digest_type\r
- self.digest_size = self.digest_type.digest_size()\r
- self.block_size = self.digest_type.block_size()\r
-\r
- def __del__(self):\r
- self._clean_ctx()\r
-\r
- def update(self, data, length=None):\r
- """\r
- Hashes given byte string \r
-\r
- @param data - string to hash\r
- @param length - if not specifed, entire string is hashed,\r
- otherwise only first length bytes\r
- """\r
- if self.digest_finalized:\r
- raise DigestError("No updates allowed")\r
- if not isinstance(data,str):\r
- raise TypeError("A string is expected")\r
- if length is None:\r
- length = len(data)\r
- elif length > len(data):\r
- raise ValueError("Specified length is greater than length of data")\r
- result = libcrypto.EVP_DigestUpdate(self.ctx, c_char_p(data), length)\r
- if result != 1:\r
- raise DigestError, "Unable to update digest"\r
- \r
- def digest(self, data=None):\r
- """\r
- Finalizes digest operation and return digest value\r
- Optionally hashes more data before finalizing\r
- """\r
- if self.digest_finalized:\r
- return self.digest_out.raw[:self.digest_size]\r
- if data is not None:\r
- self.update(data)\r
- self.digest_out = create_string_buffer(256)\r
- length = c_long(0)\r
- result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out, byref(length))\r
- if result != 1 :\r
- raise DigestError("Unable to finalize digest")\r
- self.digest_finalized = True\r
- return self.digest_out.raw[:self.digest_size]\r
- def copy(self):\r
- """\r
- Creates copy of the digest CTX to allow to compute digest\r
- while being able to hash more data\r
- """\r
- new_digest=Digest(self.digest_type)\r
- libcrypto.EVP_MD_CTX_copy(new_digest.ctx,self.ctx)\r
- return new_digest\r
-\r
- def _clean_ctx(self):\r
- try:\r
- if self.ctx is not None:\r
- libcrypto.EVP_MD_CTX_destroy(self.ctx)\r
- del(self.ctx)\r
- except AttributeError:\r
- pass\r
- self.digest_out = None\r
- self.digest_finalized = False\r
-\r
- def hexdigest(self,data=None):\r
- """\r
- Returns digest in the hexadecimal form. For compatibility\r
- with hashlib\r
- """\r
- from base64 import b16encode\r
- return b16encode(self.digest(data))\r
-\r
-\r
-# Declare function result and argument types\r
-libcrypto.EVP_get_digestbyname.restype = c_void_p\r
-libcrypto.EVP_get_digestbyname.argtypes = (c_char_p,)\r
-libcrypto.EVP_MD_CTX_create.restype = c_void_p\r
-libcrypto.EVP_DigestInit_ex.argtypes = (c_void_p,c_void_p,c_void_p)\r
-libcrypto.EVP_DigestUpdate.argtypes = (c_void_p,c_char_p,c_longlong)\r
-libcrypto.EVP_DigestFinal_ex.argtypes = (c_void_p,c_char_p,POINTER(c_long))\r
-libcrypto.EVP_MD_CTX_destroy.argtypes = (c_void_p,)\r
-libcrypto.EVP_MD_CTX_copy.argtypes=(c_void_p, c_void_p)\r
-libcrypto.EVP_MD_type.argtypes=(c_void_p,)\r
-libcrypto.EVP_MD_size.argtypes=(c_void_p,)\r
-libcrypto.EVP_MD_block_size.argtypes=(c_void_p,)\r
+"""
+ Implements interface to OpenSSL EVP_Digest* functions.
+
+ Interface made as close to hashlib as possible.
+
+ This module is really an excess effort. Hashlib allows access to
+ mostly same functionality except oids and nids of hashing
+ algortithms (which might be needed for private key operations).
+
+ hashlib even allows to use engine-provided digests if it is build
+ with dinamically linked libcrypto - so use
+ ctypescrypto.engine.set_default("gost",xFFFF) and md_gost94
+ algorithm would be available both to this module and hashlib.
+
+"""
+from ctypes import c_int, c_char_p, c_void_p, POINTER, c_long,c_longlong, create_string_buffer,byref
+from ctypescrypto import libcrypto
+from ctypescrypto.exception import LibCryptoError
+from ctypescrypto.oid import Oid
+DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")
+
+__all__ = ['DigestError','Digest','DigestType','new']
+
+class DigestError(LibCryptoError):
+ pass
+
+def new(algname):
+ """
+ Behaves just like hashlib.new. Creates digest object by
+ algorithm name
+ """
+ md=DigestType(algname)
+ return Digest(md)
+
+class DigestType(object):
+ """
+
+ Represents EVP_MD object - constant structure which describes
+ digest algorithm
+
+ """
+ def __init__(self, digest_name):
+ """
+ Finds digest by its name. You can pass Oid object instead of
+ name.
+
+ Special case is when None is passed as name. In this case
+ unitialized digest is created, and can be initalized later
+ by setting its digest attribute to pointer to EVP_MD
+ """
+ if digest_name is None:
+ return
+ if isinstance(digest_name,Oid):
+ self.digest_name=digest_name.longname()
+ self.digest=libcrypto.EVP_get_digestbyname(self.digest_name)
+ else:
+ self.digest_name = str(digest_name)
+ self.digest = libcrypto.EVP_get_digestbyname(self.digest_name)
+ if self.digest is None:
+ raise DigestError("Unknown digest: %s" % self.digest_name)
+
+ @property
+ def name(self):
+ if not hasattr(self,'digest_name'):
+ self.digest_name=Oid(libcrypto.EVP_MD_type(self.digest)).longname()
+ return self.digest_name
+ def __del__(self):
+ pass
+ def digest_size(self):
+ return libcrypto.EVP_MD_size(self.digest)
+ def block_size(self):
+ return libcrypto.EVP_MD_block_size(self.digest)
+ def oid(self):
+ return Oid(libcrypto.EVP_MD_type(self.digest))
+
+class Digest(object):
+ """
+ Represents EVP_MD_CTX object which actually used to calculate
+ digests.
+
+ """
+ def __init__(self,digest_type):
+ """
+ Initializes digest using given type.
+ """
+ self._clean_ctx()
+ self.ctx = libcrypto.EVP_MD_CTX_create()
+ if self.ctx is None:
+ raise DigestError("Unable to create digest context")
+ result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)
+ if result == 0:
+ self._clean_ctx()
+ raise DigestError("Unable to initialize digest")
+ self.digest_type = digest_type
+ self.digest_size = self.digest_type.digest_size()
+ self.block_size = self.digest_type.block_size()
+
+ def __del__(self):
+ self._clean_ctx()
+
+ def update(self, data, length=None):
+ """
+ Hashes given byte string
+
+ @param data - string to hash
+ @param length - if not specifed, entire string is hashed,
+ otherwise only first length bytes
+ """
+ if self.digest_finalized:
+ raise DigestError("No updates allowed")
+ if not isinstance(data,str):
+ raise TypeError("A string is expected")
+ if length is None:
+ length = len(data)
+ elif length > len(data):
+ raise ValueError("Specified length is greater than length of data")
+ result = libcrypto.EVP_DigestUpdate(self.ctx, c_char_p(data), length)
+ if result != 1:
+ raise DigestError, "Unable to update digest"
+
+ def digest(self, data=None):
+ """
+ Finalizes digest operation and return digest value
+ Optionally hashes more data before finalizing
+ """
+ if self.digest_finalized:
+ return self.digest_out.raw[:self.digest_size]
+ if data is not None:
+ self.update(data)
+ self.digest_out = create_string_buffer(256)
+ length = c_long(0)
+ result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out, byref(length))
+ if result != 1 :
+ raise DigestError("Unable to finalize digest")
+ self.digest_finalized = True
+ return self.digest_out.raw[:self.digest_size]
+ def copy(self):
+ """
+ Creates copy of the digest CTX to allow to compute digest
+ while being able to hash more data
+ """
+ new_digest=Digest(self.digest_type)
+ libcrypto.EVP_MD_CTX_copy(new_digest.ctx,self.ctx)
+ return new_digest
+
+ def _clean_ctx(self):
+ try:
+ if self.ctx is not None:
+ libcrypto.EVP_MD_CTX_destroy(self.ctx)
+ del(self.ctx)
+ except AttributeError:
+ pass
+ self.digest_out = None
+ self.digest_finalized = False
+
+ def hexdigest(self,data=None):
+ """
+ Returns digest in the hexadecimal form. For compatibility
+ with hashlib
+ """
+ from base64 import b16encode
+ return b16encode(self.digest(data))
+
+
+# Declare function result and argument types
+libcrypto.EVP_get_digestbyname.restype = c_void_p
+libcrypto.EVP_get_digestbyname.argtypes = (c_char_p,)
+libcrypto.EVP_MD_CTX_create.restype = c_void_p
+libcrypto.EVP_DigestInit_ex.argtypes = (c_void_p,c_void_p,c_void_p)
+libcrypto.EVP_DigestUpdate.argtypes = (c_void_p,c_char_p,c_longlong)
+libcrypto.EVP_DigestFinal_ex.argtypes = (c_void_p,c_char_p,POINTER(c_long))
+libcrypto.EVP_MD_CTX_destroy.argtypes = (c_void_p,)
+libcrypto.EVP_MD_CTX_copy.argtypes=(c_void_p, c_void_p)
+libcrypto.EVP_MD_type.argtypes=(c_void_p,)
+libcrypto.EVP_MD_size.argtypes=(c_void_p,)
+libcrypto.EVP_MD_block_size.argtypes=(c_void_p,)