2 Implements interface to OpenSSL EVP_Digest* functions.
\r
4 Interface made as close to hashlib as possible.
\r
6 This module is really an excess effort. Hashlib allows access to
\r
7 mostly same functionality except oids and nids of hashing
\r
8 algortithms (which might be needed for private key operations).
\r
10 hashlib even allows to use engine-provided digests if it is build
\r
11 with dinamically linked libcrypto - so use
\r
12 ctypescrypto.engine.set_default("gost",xFFFF) and md_gost94
\r
13 algorithm would be available both to this module and hashlib.
\r
16 from ctypes import c_int, c_char_p, c_void_p, POINTER, c_long,c_longlong, create_string_buffer,byref
\r
17 from ctypescrypto import libcrypto
\r
18 from ctypescrypto.exception import LibCryptoError
\r
19 from ctypescrypto.oid import Oid
\r
20 DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")
\r
23 class DigestError(LibCryptoError):
\r
28 Behaves just like hashlib.new. Creates digest object by
\r
31 md=DigestType(algname)
\r
37 Represents EVP_MD object - constant structure which describes
\r
41 def __init__(self, digest_name):
\r
43 Finds digest by its name
\r
45 self.digest_name = digest_name
\r
46 self.digest = libcrypto.EVP_get_digestbyname(self.digest_name)
\r
47 if self.digest is None:
\r
48 raise DigestError, "Unknown digest: %s" % self.digest_name
\r
52 def digest_size(self):
\r
53 return libcrypto.EVP_MD_size(self.digest)
\r
54 def block_size(self):
\r
55 return libcrypto.EVP_MD_block_size(self.digest)
\r
57 return Oid(libcrypto.EVP_MD_type(self.digest))
\r
61 Represents EVP_MD_CTX object which actually used to calculate
\r
65 def __init__(self,digest_type):
\r
67 Initializes digest using given type.
\r
70 self.ctx = libcrypto.EVP_MD_CTX_create()
\r
72 raise DigestError, "Unable to create digest context"
\r
73 result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)
\r
76 raise DigestError, "Unable to initialize digest"
\r
77 self.digest_type = digest_type
\r
78 self.digest_size = self.digest_type.digest_size()
\r
79 self.block_size = self.digest_type.block_size()
\r
84 def update(self, data):
\r
86 Hashes given byte string as data
\r
88 if self.digest_finalized:
\r
89 raise DigestError, "No updates allowed"
\r
90 if type(data) != type(""):
\r
91 raise TypeError, "A string is expected"
\r
92 result = libcrypto.EVP_DigestUpdate(self.ctx, c_char_p(data), len(data))
\r
94 raise DigestError, "Unable to update digest"
\r
96 def digest(self, data=None):
\r
98 Finalizes digest operation and return digest value
\r
99 Optionally hashes more data before finalizing
\r
101 if self.digest_finalized:
\r
102 return self.digest_out.raw[:self.digest_size]
\r
103 if data is not None:
\r
105 self.digest_out = create_string_buffer(256)
\r
107 result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out, byref(length))
\r
109 raise DigestError, "Unable to finalize digest"
\r
110 self.digest_finalized = True
\r
111 return self.digest_out.raw[:self.digest_size]
\r
114 Creates copy of the digest CTX to allow to compute digest
\r
115 while being able to hash more data
\r
117 new_digest=Digest(self.digest_type)
\r
118 libcrypto.EVP_MD_CTX_copy(new_digest.ctx,self.ctx)
\r
121 def _clean_ctx(self):
\r
123 if self.ctx is not None:
\r
124 libcrypto.EVP_MD_CTX_destroy(self.ctx)
\r
126 except AttributeError:
\r
128 self.digest_out = None
\r
129 self.digest_finalized = False
\r
131 def hexdigest(self,data=None):
\r
133 Returns digest in the hexadecimal form. For compatibility
\r
136 from base64 import b16encode
\r
137 return b16encode(self.digest(data))
\r
140 # Declare function result and argument types
\r
141 libcrypto.EVP_get_digestbyname.restype = c_void_p
\r
142 libcrypto.EVP_get_digestbyname.argtypes = (c_char_p,)
\r
143 libcrypto.EVP_MD_CTX_create.restype = c_void_p
\r
144 libcrypto.EVP_DigestInit_ex.argtypes = (c_void_p,c_void_p,c_void_p)
\r
145 libcrypto.EVP_DigestUpdate.argtypes = (c_void_p,c_char_p,c_longlong)
\r
146 libcrypto.EVP_DigestFinal_ex.argtypes = (c_void_p,c_char_p,POINTER(c_long))
\r
147 libcrypto.EVP_MD_CTX_destroy.argtypes = (c_void_p,)
\r
148 libcrypto.EVP_MD_CTX_copy.argtypes=(c_void_p, c_void_p)
\r
149 libcrypto.EVP_MD_type.argtypes=(c_void_p,)
\r
150 libcrypto.EVP_MD_size.argtypes=(c_void_p,)
\r
151 libcrypto.EVP_MD_block_size.argtypes=(c_void_p,)
\r