2 Implements interface to OpenSSL EVP_Digest* functions.
4 Interface made as close to hashlib as possible.
6 This module is really an excess effort. Hashlib allows access to
7 mostly same functionality except oids and nids of hashing
8 algortithms (which might be needed for private key operations).
10 hashlib even allows to use engine-provided digests if it is build
11 with dinamically linked libcrypto - so use
12 ctypescrypto.engine.set_default("gost",xFFFF) and md_gost94
13 algorithm would be available both to this module and hashlib.
16 from ctypes import c_int, c_char_p, c_void_p, POINTER, c_long, c_longlong
17 from ctypes import create_string_buffer, byref
18 from ctypescrypto import libcrypto
19 from ctypescrypto.exception import LibCryptoError
20 from ctypescrypto.oid import Oid
21 DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")
23 __all__ = ['DigestError', 'Digest', 'DigestType', 'new']
25 class DigestError(LibCryptoError):
26 """ Exception raised if some OpenSSL function returns error """
31 Behaves just like hashlib.new. Creates digest object by
35 digest_type = DigestType(algname)
36 return Digest(digest_type)
38 class DigestType(object):
40 Represents EVP_MD object - constant structure which describes
43 def __init__(self, digest_name):
45 Finds digest by its name. You can pass Oid object instead of
48 Special case is when None is passed as name. In this case
49 unitialized digest is created, and can be initalized later
50 by setting its digest attribute to pointer to EVP_MD
52 if digest_name is None:
55 if isinstance(digest_name, Oid):
56 self.digest_name = digest_name.longname()
58 self.digest_name = str(digest_name)
59 self.digest = libcrypto.EVP_get_digestbyname(self.digest_name)
60 if self.digest is None:
61 raise DigestError("Unknown digest: %s" % self.digest_name)
65 """ Returns name of the digest """
66 if not hasattr(self, 'digest_name'):
67 self.digest_name = Oid(libcrypto.EVP_MD_type(self.digest)
69 return self.digest_name
72 """ Empty destructor for constant object """
76 def digest_size(self):
77 """ Returns size of digest """
78 return libcrypto.EVP_MD_size(self.digest)
82 """ Returns block size of the digest """
83 return libcrypto.EVP_MD_block_size(self.digest)
87 """ Returns Oid object of digest type """
88 return Oid(libcrypto.EVP_MD_type(self.digest))
92 Represents EVP_MD_CTX object which actually used to calculate
96 def __init__(self, digest_type):
98 Initializes digest using given type.
100 self.ctx = libcrypto.EVP_MD_CTX_create()
102 raise DigestError("Unable to create digest context")
103 self.digest_out = None
104 self.digest_finalized = False
105 result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)
108 raise DigestError("Unable to initialize digest")
109 self.digest_type = digest_type
110 self.digest_size = self.digest_type.digest_size
111 self.block_size = self.digest_type.block_size
114 """ Uses _clean_ctx internal method """
117 def update(self, data, length=None):
119 Hashes given byte string
121 @param data - string to hash
122 @param length - if not specifed, entire string is hashed,
123 otherwise only first length bytes
125 if self.digest_finalized:
126 raise DigestError("No updates allowed")
127 if not isinstance(data, str):
128 raise TypeError("A string is expected")
131 elif length > len(data):
132 raise ValueError("Specified length is greater than length of data")
133 result = libcrypto.EVP_DigestUpdate(self.ctx, c_char_p(data), length)
135 raise DigestError("Unable to update digest")
137 def digest(self, data=None):
139 Finalizes digest operation and return digest value
140 Optionally hashes more data before finalizing
142 if self.digest_finalized:
143 return self.digest_out.raw[:self.digest_size]
146 self.digest_out = create_string_buffer(256)
148 result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out,
151 raise DigestError("Unable to finalize digest")
152 self.digest_finalized = True
153 return self.digest_out.raw[:self.digest_size]
156 Creates copy of the digest CTX to allow to compute digest
157 while being able to hash more data
160 new_digest = Digest(self.digest_type)
161 libcrypto.EVP_MD_CTX_copy(new_digest.ctx, self.ctx)
164 def _clean_ctx(self):
166 Clears and deallocates context
169 if self.ctx is not None:
170 libcrypto.EVP_MD_CTX_destroy(self.ctx)
172 except AttributeError:
174 self.digest_out = None
175 self.digest_finalized = False
177 def hexdigest(self, data=None):
179 Returns digest in the hexadecimal form. For compatibility
182 from base64 import b16encode
183 return b16encode(self.digest(data))
186 # Declare function result and argument types
187 libcrypto.EVP_get_digestbyname.restype = c_void_p
188 libcrypto.EVP_get_digestbyname.argtypes = (c_char_p, )
189 libcrypto.EVP_MD_CTX_create.restype = c_void_p
190 # libcrypto.EVP_MD_CTX_create has no arguments
191 libcrypto.EVP_DigestInit_ex.restupe = c_int
192 libcrypto.EVP_DigestInit_ex.argtypes = (c_void_p, c_void_p, c_void_p)
193 libcrypto.EVP_DigestUpdate.restype = c_int
194 libcrypto.EVP_DigestUpdate.argtypes = (c_void_p, c_char_p, c_longlong)
195 libcrypto.EVP_DigestFinal_ex.restype = c_int
196 libcrypto.EVP_DigestFinal_ex.argtypes = (c_void_p, c_char_p, POINTER(c_long))
197 libcrypto.EVP_MD_CTX_destroy.argtypes = (c_void_p, )
198 libcrypto.EVP_MD_CTX_copy.restype = c_int
199 libcrypto.EVP_MD_CTX_copy.argtypes = (c_void_p, c_void_p)
200 libcrypto.EVP_MD_type.argtypes = (c_void_p, )
201 libcrypto.EVP_MD_size.argtypes = (c_void_p, )
202 libcrypto.EVP_MD_block_size.restype = c_int
203 libcrypto.EVP_MD_block_size.argtypes = (c_void_p, )
204 libcrypto.EVP_MD_size.restype = c_int
205 libcrypto.EVP_MD_size.argtypes = (c_void_p, )
206 libcrypto.EVP_MD_type.restype = c_int
207 libcrypto.EVP_MD_type.argtypes = (c_void_p, )