2 Implmenets interface to OpenSSL EVP_Digest* functions.
\r
3 Interface made as close to hashlib as possible
\r
5 from ctypes import c_int, c_char_p, c_void_p, POINTER, c_long_long
\r
6 from ctypescrypto import libcrypto
\r
7 from ctypescrypto.exception import LibCryptoError
\r
8 DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")
\r
11 class DigestError(LibCryptoError):
\r
15 md=DigestType(algname)
\r
21 Represents EVP_MD object - constant structure which describes
\r
25 def __init__(self, digest_name):
\r
27 Finds digest by its name
\r
29 self.digest_name = digest_name
\r
30 self.digest = libcrypto.EVP_get_digestbyname(self.digest_name)
\r
31 if self.digest == 0:
\r
32 raise DigestError, "Unknown digest: %s" % self.digest_name
\r
36 def digest_size(self):
\r
37 return libcrypto.EVP_MD_size(self.digest)
\r
38 def block_size(self):
\r
39 return libcrypto.EVP_MD_block_size(self.digest)
\r
43 # return Oid(nid=libcrypto.EVP_MD_type(self.digest)
\r
46 Represents EVP_MD_CTX object which actually used to calculate
\r
50 def __init__(self, digest_type):
\r
52 Initializes digest using given type.
\r
55 self.ctx = libcrypto.EVP_MD_CTX_create()
\r
57 raise DigestError, "Unable to create digest context"
\r
58 result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)
\r
61 raise DigestError, "Unable to initialize digest"
\r
62 self.digest_type = digest_type
\r
63 self.digest_size = self.digest_type.digest_size()
\r
64 self.block_size = self.digest_type.block_size()
\r
69 def update(self, data):
\r
71 Hashes given byte string as data
\r
73 if self.digest_finalized:
\r
74 raise DigestError, "No updates allowed"
\r
75 if type(data) != type(""):
\r
76 raise TypeError, "A string is expected"
\r
77 result = libcrypto.EVP_DigestUpdate(self.ctx, c_char_p(data), len(data))
\r
79 raise DigestError, "Unable to update digest"
\r
81 def digest(self, data=None):
\r
83 Finalizes digest operation and return digest value
\r
84 Optionally hashes data before finalizing
\r
86 if self.digest_finalized:
\r
87 return self.digest_out.raw[:self.digest_size]
\r
88 if data is not None:
\r
90 self.digest_out = create_string_buffer(256)
\r
92 result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out, byref(length))
\r
94 raise DigestError, "Unable to finalize digest"
\r
95 self.digest_finalized = True
\r
96 return self.digest_out.raw[:self.digest_size]
\r
99 Creates copy of the digest CTX to allow to compute digest
\r
100 while being able to hash more data
\r
102 new_digest=Digest(self.digest_type)
\r
103 libcrypto.EVP_MD_CTX_copy(new_digest.ctx,self.ctx)
\r
106 def _clean_ctx(self):
\r
108 if self.ctx is not None:
\r
109 libcrypto.EVP_MD_CTX_destroy(self.ctx)
\r
111 except AttributeError:
\r
113 self.digest_out = None
\r
114 self.digest_finalized = False
\r
116 def hexdigest(self,data=None):
\r
118 Returns digest in the hexadecimal form. For compatibility
\r
121 from base64 import b16encode
\r
122 return b16encode(self.digest(data)
\r
125 # Declare function result and argument types
\r
126 libcrypto.EVP_get_digestbyname.restype = c_void_p
\r
127 libcrypto.EVP_MD_CTX_create.restype = c_void_p
\r
128 libcrypto.EVP_DigestInit_ex.argtypes = (c_void_p,c_void_p,c_void_p)
\r
129 libcrypto.EVP_DigestUpdate.argtypes = (c_void_p,c_char_p,c_longlong)
\r
130 libcrypto.EVP_DigestFinal_ex.argtypes = (c_void_p,c_char_p,POINTER(c_long))
\r
131 libcrypto.EVP_MD_CTX_destroy.argtypes = (c_void_p,)
\r
132 libcrypto.EVP_MD_CTX_copy.argtypes=(c_void_p, c_void_p)
\r
133 libcrypto.EVP_MD_type.argtypes=(c_void_p,)
\r
134 libcrypto.EVP_MD_size.argtypes=(c_void_p,)
\r
135 libcrypto.EVP_MD_block_size.argtypes=(c_void_p,)
\r