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, create_string_buffer,byref
17 from ctypescrypto import libcrypto
18 from ctypescrypto.exception import LibCryptoError
19 from ctypescrypto.oid import Oid
20 DIGEST_ALGORITHMS = ("MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512")
22 __all__ = ['DigestError','Digest','DigestType','new']
24 class DigestError(LibCryptoError):
29 Behaves just like hashlib.new. Creates digest object by
32 md=DigestType(algname)
35 class DigestType(object):
38 Represents EVP_MD object - constant structure which describes
42 def __init__(self, digest_name):
44 Finds digest by its name. You can pass Oid object instead of
47 Special case is when None is passed as name. In this case
48 unitialized digest is created, and can be initalized later
49 by setting its digest attribute to pointer to EVP_MD
51 if digest_name is None:
53 if isinstance(digest_name,Oid):
54 self.digest_name=digest_name.longname()
55 self.digest=libcrypto.EVP_get_digestbyname(self.digest_name)
57 self.digest_name = str(digest_name)
58 self.digest = libcrypto.EVP_get_digestbyname(self.digest_name)
59 if self.digest is None:
60 raise DigestError("Unknown digest: %s" % self.digest_name)
64 if not hasattr(self,'digest_name'):
65 self.digest_name=Oid(libcrypto.EVP_MD_type(self.digest)).longname()
66 return self.digest_name
69 def digest_size(self):
70 return libcrypto.EVP_MD_size(self.digest)
72 return libcrypto.EVP_MD_block_size(self.digest)
74 return Oid(libcrypto.EVP_MD_type(self.digest))
78 Represents EVP_MD_CTX object which actually used to calculate
82 def __init__(self,digest_type):
84 Initializes digest using given type.
87 self.ctx = libcrypto.EVP_MD_CTX_create()
89 raise DigestError("Unable to create digest context")
90 result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)
93 raise DigestError("Unable to initialize digest")
94 self.digest_type = digest_type
95 self.digest_size = self.digest_type.digest_size()
96 self.block_size = self.digest_type.block_size()
101 def update(self, data, length=None):
103 Hashes given byte string
105 @param data - string to hash
106 @param length - if not specifed, entire string is hashed,
107 otherwise only first length bytes
109 if self.digest_finalized:
110 raise DigestError("No updates allowed")
111 if not isinstance(data,str):
112 raise TypeError("A string is expected")
115 elif length > len(data):
116 raise ValueError("Specified length is greater than length of data")
117 result = libcrypto.EVP_DigestUpdate(self.ctx, c_char_p(data), length)
119 raise DigestError, "Unable to update digest"
121 def digest(self, data=None):
123 Finalizes digest operation and return digest value
124 Optionally hashes more data before finalizing
126 if self.digest_finalized:
127 return self.digest_out.raw[:self.digest_size]
130 self.digest_out = create_string_buffer(256)
132 result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out, byref(length))
134 raise DigestError("Unable to finalize digest")
135 self.digest_finalized = True
136 return self.digest_out.raw[:self.digest_size]
139 Creates copy of the digest CTX to allow to compute digest
140 while being able to hash more data
142 new_digest=Digest(self.digest_type)
143 libcrypto.EVP_MD_CTX_copy(new_digest.ctx,self.ctx)
146 def _clean_ctx(self):
148 if self.ctx is not None:
149 libcrypto.EVP_MD_CTX_destroy(self.ctx)
151 except AttributeError:
153 self.digest_out = None
154 self.digest_finalized = False
156 def hexdigest(self,data=None):
158 Returns digest in the hexadecimal form. For compatibility
161 from base64 import b16encode
162 return b16encode(self.digest(data))
165 # Declare function result and argument types
166 libcrypto.EVP_get_digestbyname.restype = c_void_p
167 libcrypto.EVP_get_digestbyname.argtypes = (c_char_p,)
168 libcrypto.EVP_MD_CTX_create.restype = c_void_p
169 libcrypto.EVP_DigestInit_ex.argtypes = (c_void_p,c_void_p,c_void_p)
170 libcrypto.EVP_DigestUpdate.argtypes = (c_void_p,c_char_p,c_longlong)
171 libcrypto.EVP_DigestFinal_ex.argtypes = (c_void_p,c_char_p,POINTER(c_long))
172 libcrypto.EVP_MD_CTX_destroy.argtypes = (c_void_p,)
173 libcrypto.EVP_MD_CTX_copy.argtypes=(c_void_p, c_void_p)
174 libcrypto.EVP_MD_type.argtypes=(c_void_p,)
175 libcrypto.EVP_MD_size.argtypes=(c_void_p,)
176 libcrypto.EVP_MD_block_size.argtypes=(c_void_p,)