- """
- 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))
+ """
+ Represents EVP_MD_CTX object which actually used to calculate
+ digests.
+ """
+
+ def __init__(self, digest_type):
+ """
+ Initializes digest using given type.
+ """
+ self.ctx = self.newctx()
+ if self.ctx is None:
+ raise DigestError("Unable to create digest context")
+ self.digest_out = None
+ self.digest_finalized = False
+ 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):
+ """ Uses _clean_ctx internal method """
+ 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):
+ """
+ Clears and deallocates context
+ """
+ try:
+ if self.ctx is not None:
+ libcrypto.EVP_MD_CTX_free(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))