]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - ctypescrypto/mac.py
48ade0948f91c4e45d6fb4a764cb45a858db1ebe
[oss/ctypescrypto.git] / ctypescrypto / mac.py
1 # -*- encoding: utf-8 -*-
2 """
3 This module provides interface to OpenSSL MAC functions.
4
5 It has not only HMAC support, but can support other types of MAC.
6
7 """
8
9 from ctypescrypto.digest import Digest,DigestType,DigestError
10 from ctypescrypto.oid import Oid
11 from ctypescrypto import libcrypto
12 from ctypes import c_int,c_char_p, c_void_p, c_size_t,POINTER,create_string_buffer,pointer
13
14 __all__ = ['MAC','DigestError']
15 class MAC(Digest):
16         """
17                 This object represents MAC context. It is quite simular
18                 to digest algorithm. It is simular to hmac objects provided
19                 by standard library
20         """
21         def __init__(self,algorithm,key,digest=None,**kwargs):
22                 """
23                 Constructor has to obligatory arguments:
24                         
25                         @param algorithm - which is name of MAC algorithm i.e 'hmac' or 
26                                         'gost-mac' or equivalent Oid object
27                         @param key - byte buffer with key.
28
29                 Optional parameters are:
30                         digest - Oid or name of the digest algorithm to use. If none
31                                 specified, OpenSSL will try to derive one from the MAC
32                                 algorithm (or if algorithm is hmac, we'll substititute md5
33                                 for compatibility with standard hmac module
34
35                         any other keyword argument is passed to EVP_PKEY_CTX as string
36                         option.
37
38                 """
39                 if isinstance(algorithm,str):
40                         self.algorithm=Oid(algorithm)
41                 elif isinstance(algorithm,Oid):
42                         self.algorithm=algorithm
43                 else:
44                         raise TypeError("Algorthm must be string or Oid")
45                 if self.algorithm==Oid('hmac') and digest is None:
46                                 digest='md5'
47                 self.name=self.algorithm.shortname().lower()
48                 if digest is not None:
49                         self.digest_type=DigestType(digest)
50                         self.name+='-'+self.digest_type.digest_name
51                         d=self.digest_type.digest
52                 else:
53                         self.digest_type=None
54                         d=None
55                 self.key=libcrypto.EVP_PKEY_new_mac_key(self.algorithm.nid,None,key,len(key))
56                 if self.key is None:
57                         raise DigestError("EVP_PKEY_new_mac_key")
58                 pctx=c_void_p()
59                 self.ctx = libcrypto.EVP_MD_CTX_create()
60                 if self.ctx == 0:
61                         raise DigestError("Unable to create digest context")
62                 if libcrypto.EVP_DigestSignInit(self.ctx,pointer(pctx),d,None,self.key) <= 0:
63                         raise DigestError("Unable to intialize digest context")
64                 self.digest_finalized=False
65                 if self.digest_type is None:
66                         self.digest_type=DigestType(Oid(libcrypto.EVP_MD_type(libcrypto.EVP_MD_CTX_md(self.ctx))))
67                 for (name,val) in kwargs.items():
68                         if libcrypto.EVP_PKEY_CTX_ctrl_str(pctx,name,val)<=0:
69                                 raise DigestError("Unable to set mac parameter")
70                 self.digest_size = self.digest_type.digest_size()
71                 self.block_size = self.digest_type.block_size()
72         def digest(self,data=None):
73                 """
74                 Method digest is redefined to return keyed MAC value instead of
75                 just digest.
76                 """
77                 if data is not None:
78                         self.update(data)
79                 b=create_string_buffer(256)
80                 size=c_size_t(256)
81                 if libcrypto.EVP_DigestSignFinal(self.ctx,b,pointer(size))<=0:
82                         raise DigestError('SignFinal')
83                 self.digest_finalized=True
84                 return b.raw[:size.value]
85
86 libcrypto.EVP_DigestSignFinal.argtypes=(c_void_p,c_char_p,POINTER(c_size_t))
87 libcrypto.EVP_DigestSignFinal.restype=c_int
88 libcrypto.EVP_DigestSignInit.argtypes=(c_void_p,POINTER(c_void_p),c_void_p,c_void_p,c_void_p)
89 libcrypto.EVP_DigestSignInit.restype=c_int
90 libcrypto.EVP_PKEY_CTX_ctrl_str.argtypes=(c_void_p,c_char_p,c_char_p)
91 libcrypto.EVP_PKEY_CTX_ctrl_str.restype=c_int
92 libcrypto.EVP_PKEY_new_mac_key.argtypes=(c_int,c_void_p,c_char_p,c_int)
93 libcrypto.EVP_PKEY_new_mac_key.restype=c_void_p
94 libcrypto.EVP_MD_CTX_md.argtypes=(c_void_p,)
95 libcrypto.EVP_MD_CTX_md.restype=c_void_p