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