]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - ctypescrypto/pkey.py
Make setup actually run tests
[oss/ctypescrypto.git] / ctypescrypto / pkey.py
1 from ctypes import c_char_p,c_void_p,byref,c_int,c_long, c_longlong, create_string_buffer,CFUNCTYPE,POINTER
2 from ctypescrypto import libcrypto
3 from ctypescrypto.exception import LibCryptoError,clear_err_stack
4 from ctypescrypto.bio import Membio
5
6 class PKeyError(LibCryptoError):
7         pass
8
9 CALLBACK_FUNC=CFUNCTYPE(c_int,c_char_p,c_int,c_int,c_char_p)
10 def password_callback(buf,length,rwflag,u):
11         cnt=len(u)
12         if length<cnt:
13                 cnt=length
14         memmove(buf,u,cnt)
15         return cnt
16
17 _cb=CALLBACK_FUNC(password_callback)
18
19 class PKey:
20         def __init__(self,ptr=None,privkey=None,pubkey=None,format="PEM",cansign=False,password=None):
21                 if not ptr is None:
22                         self.key=ptr
23                         self.cansign=cansign
24                         if not privkey is None or not pubkey is None:
25                                 raise TypeError("Just one of pubkey or privkey can be specified")
26                 elif not privkey is None:
27                         if not pubkey is None:
28                                 raise TypeError("Just one of pubkey or privkey can be specified")
29                         b=Membio(privkey)
30                         self.cansign=True
31                         if format == "PEM":
32                                 self.key=libcrypto.PEM_read_bio_PrivateKey(b.bio,None,_cb,c_char_p(password))
33                         else: 
34                                 self.key=libcrypto.d2i_PKCS8PrivateKey_bio(b.bio,None,_cb,c_char_p(password))
35                         if self.key is None:
36                                 raise PKeyError("error parsing private key")
37                 elif not pubkey is None:
38                         b=Membio(pubkey)
39                         self.cansign=False
40                         if format == "PEM":
41                                 self.key=libcrypto.PEM_read_bio_PUBKEY(b.bio,None,_cb,None)
42                         else:
43                                 self.key=libcrypto.d2i_PUBKEY_bio(b.bio,None)
44                         if self.key is None:
45                                 raise PKeyError("error parsing public key")
46                 else:
47                         raise TypeError("Neither public, nor private key is specified")
48                         
49
50         def __del__(self):
51                 libcrypto.EVP_PKEY_free(self.key)
52         def __eq__(self,other):
53                 """ Compares two public keys. If one has private key and other
54                         doesn't it doesn't affect result of comparation
55                 """
56                 return libcrypto.EVP_PKEY_cmp(self.key,other.key)==1
57         def __ne__(self,other):
58                 return not self.__eq__(other)
59         def __str__(self):
60                 """ printable representation of public key """  
61                 b=Membio()
62                 libcrypto.EVP_PKEY_print_public(b.bio,self.key,0,None)
63                 return str(b)
64
65         def sign(self,digest,**kwargs):
66                 """
67                         Signs given digest and retirns signature
68                         Keyword arguments allows to set various algorithm-specific
69                         parameters. See pkeyutl(1) manual.
70                 """
71                 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
72                 if ctx is None:
73                         raise PKeyError("Initailizing sign context")
74                 if libcrypto.EVP_PKEY_sign_init(ctx)<1:
75                         raise PKeyError("sign_init")
76                 for oper in kwargs:
77                         rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
78                         if rw==-2:
79                                 raise PKeyError("Parameter %s is not supported by key"%(oper))
80                         if rv<1:
81                                 raise PKeyError("Error setting parameter %s"(oper))
82                 # Find out signature size
83                 siglen=c_long(0)
84                 if libcrypto.EVP_PKEY_sign(ctx,None,byref(siglen),digest,len(digest))<1:
85                         raise PKeyError("signing")      
86                 sig=create_string_buffer(siglen.value)
87                 libcrypto.EVP_PKEY_sign(ctx,sig,byref(signlen),digest,len(digest))
88                 libcrypto.EVP_PKEY_CTX_free(ctx)
89                 return sig.value[:siglen.value]
90
91         def verify(self,digest,signature,**kwargs):
92                 """
93                         Verifies given signature on given digest
94                         Returns True if Ok, False if don't match
95                 """
96                 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
97                 if ctx is None:
98                         raise PKeyError("Initailizing verify context")
99                 if libcrypto.EVP_PKEY_verify_init(ctx)<1:
100                         raise PKeyError("verify_init")
101                 for oper in kwargs:
102                         rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
103                         if rw==-2:
104                                 raise PKeyError("Parameter %s is not supported by key"%(oper))
105                         if rv<1:
106                                 raise PKeyError("Error setting parameter %s"(oper))
107                 rv=libcrypto.EVP_PKEY_verify(ctx,signature,len(signature),digest,len(digest))
108                 if rv<0:
109                         raise PKeyError("Signature verification")
110                 libcrypto=EVP_PKEY_CTX_free(ctx)
111                 return rv>0
112         def generate(algorithm,**kwargs):
113                 """
114                         Generates new private-public key pair for given algorithm
115                         (string like 'rsa','ec','gost2001') and algorithm-specific
116                         parameters
117                 """
118                 tmpeng=c_void_p(None)
119                 ameth=libcrypto.EVP_PKEY_asn1_find_str(byref(tmpeng),algorithm,-1)
120                 if ameth is None:
121                         raise PKeyError("Algorithm %s not foind\n"%(algname))
122                 clear_err_stack()
123                 pkey_id=c_int(0)
124                 libcrypto.EVP_PKEY_asn1_get0_info(byref(pkey_id),None,None,None,None,ameth)
125                 libcrypto.ENGINE_finish(tmpeng)
126                 ctx=libcrypto.EVP_PKEY_CTX_new_id(pkey_id)
127                 if ctx is None:
128                         raise PKeyError("Creating context for key type %d"%(pkey_id.value)) 
129                 if libcrypto.EVP_PKEY_keygen_init(ctx) <=0 :
130                         raise PKeyError("keygen_init")
131                 for oper in kwargs:
132                         rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
133                         if rw==-2:
134                                 raise PKeyError("Parameter %s is not supported by key"%(oper))
135                         if rv<1:
136                                 raise PKeyError("Error setting parameter %s"(oper))
137                 key=c_void_p(None)
138                 if libcrypto.EVP_PKEY_keygen(ctx,byref(key))<=0:
139                         raise PKeyError("Error generating key")
140                 libcrypto.EVP_PKEY_CTX_free(ctx)
141                 return PKey(ptr=key,cansign=True)
142                         
143 # Declare function prototypes
144 libcrypto.EVP_PKEY_cmp.argtypes=(c_void_p,c_void_p)
145 libcrypto.PEM_read_bio_PrivateKey.restype=c_void_p
146 libcrypto.PEM_read_bio_PrivateKey.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p) 
147 libcrypto.d2i_PKCS8PrivateKey_bio.restype=c_void_p
148 libcrypto.d2i_PKCS8PrivateKey_bio.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p)
149 libcrypto.PEM_read_bio_PUBKEY.restype=c_void_p
150 libcrypto.PEM_read_bio_PUBKEY.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p)