]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - ctypescrypto/digest.py
Initial commit of modules
[oss/ctypescrypto.git] / ctypescrypto / digest.py
1 """\r
2         Implmenets interface to OpenSSL EVP_Digest* functions.\r
3         Interface  made as close to hashlib as possible\r
4 """\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
9 \r
10 \r
11 class DigestError(LibCryptoError):\r
12     pass\r
13 \r
14 def new(algname):\r
15         md=DigestType(algname)\r
16         return Digest(md)\r
17 \r
18 class DigestType:\r
19         """\r
20                 \r
21                 Represents EVP_MD object - constant structure which describes\r
22                 digest algorithm\r
23 \r
24         """\r
25     def __init__(self,  digest_name):\r
26                 """\r
27                         Finds digest by its name\r
28                 """\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
33 \r
34     def __del__(self):\r
35         pass\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
40         def oid(self):\r
41                 pass\r
42                 #FIXME TBD\r
43                 # return Oid(nid=libcrypto.EVP_MD_type(self.digest)\r
44 class Digest:\r
45         """\r
46                 Represents EVP_MD_CTX object which actually used to calculate\r
47                 digests.\r
48 \r
49         """\r
50     def __init__(self,  digest_type):\r
51                 """\r
52                         Initializes digest using given type.\r
53                 """\r
54         self._clean_ctx()\r
55         self.ctx = libcrypto.EVP_MD_CTX_create()\r
56         if self.ctx == 0:\r
57             raise DigestError, "Unable to create digest context"\r
58         result = libcrypto.EVP_DigestInit_ex(self.ctx, digest_type.digest, None)\r
59         if result == 0:\r
60             self._clean_ctx()\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
65 \r
66     def __del__(self):\r
67         self._clean_ctx()\r
68 \r
69     def update(self, data):\r
70                 """\r
71                         Hashes given byte string as data\r
72                 """\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
78         if result != 1:\r
79             raise DigestError, "Unable to update digest"\r
80         \r
81     def digest(self, data=None):\r
82                 """\r
83                         Finalizes digest operation and return digest value\r
84                         Optionally hashes data before finalizing\r
85                 """\r
86         if self.digest_finalized:\r
87                         return self.digest_out.raw[:self.digest_size]\r
88         if data is not None:\r
89             self.update(data)\r
90         self.digest_out = create_string_buffer(256)\r
91         length = c_long(0)\r
92         result = libcrypto.EVP_DigestFinal_ex(self.ctx, self.digest_out, byref(length))\r
93         if result != 1 :\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
97         def copy(self):\r
98                 """\r
99                         Creates copy of the digest CTX to allow to compute digest\r
100                         while being able to hash more data\r
101                 """\r
102                 new_digest=Digest(self.digest_type)\r
103                 libcrypto.EVP_MD_CTX_copy(new_digest.ctx,self.ctx)\r
104                 return new_digest\r
105 \r
106     def _clean_ctx(self):\r
107         try:\r
108             if self.ctx is not None:\r
109                 libcrypto.EVP_MD_CTX_destroy(self.ctx)\r
110                 del(self.ctx)\r
111         except AttributeError:\r
112             pass\r
113         self.digest_out = None\r
114         self.digest_finalized = False\r
115 \r
116         def hexdigest(self,data=None):\r
117                 """\r
118                         Returns digest in the hexadecimal form. For compatibility\r
119                         with hashlib\r
120                 """\r
121                 from base64 import b16encode\r
122                 return b16encode(self.digest(data)\r
123 \r
124 \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