]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blob - ctypescrypto/pkey.py
676d324fb1cda61eb885f677189da3f010f3a9f0
[oss/ctypescrypto.git] / ctypescrypto / pkey.py
1 from ctypes import byref,c_int,c_long, c_longlong, create_string_buffer
2 from ctypescrypto import libcrypto
3 from ctypescrypto.exception import LibCryptoErrors,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,cansign)
21                 self.key=ptr:
22                 self.cansign=cansign
23         def __del__(self):
24                 libcrypto.EVP_PKEY_free(self.key)
25         def __eq__(self,other):
26                 """ Compares two public keys. If one has private key and other
27                         doesn't it doesn't affect result of comparation
28                 """
29                 return libcrypto.EVP_PKEY_cmp(self.key,other.key)==1
30         def __ne__(self,other):
31                 return not self.__eq__(other)
32         def __str__(self):
33                 """ printable representation of public key """  
34                 b=Membio()
35                 libcrypto.EVP_PKEY_print_public(b.bio,self.key,0,NULL)
36                 return str(b)
37         def privpem(s,password=None):
38                 """ Class method for load from the pem string of private key """
39                 b=Membio(s)
40                 return PKey(libcrypto.PEM_read_bio_PrivateKey(b.bio,NULL,_cb,c_char_p(password))
41
42         def privder(s):
43                 """ Class method for load from the binary ASN1 structure of private key """
44                 b=Membio(s)
45                 return PKey(libcrypto.d2i_PrivateKey_bio(b.bio,NULL),True)
46         def pubpem(s):
47                 """ Class method for load from public key pem string"""
48                 b=Membio(s)
49                 return PKey(libcrypto.PEM_read_bio_PUBKEY(b.bio,NULL,cb,c_char_p(password)),False)
50         def pubder(s):
51                 """ Class method for load from the binary ASN1 structure """
52                 b=Membio(s)
53                 return PKey(libcrypto.d2i_PUBKEY_bio(b.bio,NULL),False)
54         def sign(self,digest,**kwargs):
55                 """
56                         Signs given digest and retirns signature
57                         Keyword arguments allows to set various algorithm-specific
58                         parameters. See pkeyutl(1) manual.
59                 """
60                 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
61                 if ctx is None:
62                         raise PKeyError("Initailizing sign context")
63                 if libcrypto.EVP_PKEY_sign_init(ctx)<1:
64                         raise PKeyError("sign_init")
65                 for oper in kwargs:
66                         rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
67                         if rw=-2:
68                                 raise PKeyError("Parameter %s is not supported by key"%(oper))
69                         if rv<1:
70                                 raise PKeyError("Error setting parameter %s"(oper))
71                 # Find out signature size
72                 siglen=c_long(0)
73                 if libcrypto.EVP_PKEY_sign(ctx,None,byref(siglen),digest,len(digest))<1:
74                         raise PKeyError("signing")      
75                 sig=create_string_buffer(siglen.value)
76                 libcrypto.EVP_PKEY_sign(ctx,sig,byref(signlen),digest,len(digest)
77                 libcrypto.EVP_PKEY_CTX_free(ctx)
78                 return sig.value[:siglen.value]
79
80         def verify(self,digest,signature,**kwargs):
81                 """
82                         Verifies given signature on given digest
83                         Returns True if Ok, False if don't match
84                 """
85                 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
86                 if ctx is None:
87                         raise PKeyError("Initailizing verify context")
88                 if libcrypto.EVP_PKEY_verify_init(ctx)<1:
89                         raise PKeyError("verify_init")
90                 for oper in kwargs:
91                         rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
92                         if rw=-2:
93                                 raise PKeyError("Parameter %s is not supported by key"%(oper))
94                         if rv<1:
95                                 raise PKeyError("Error setting parameter %s"(oper))
96                 rv=libcrypto.EVP_PKEY_verify(ctx,signature,len(signature),digest,len(digest))
97                 if rv<0:
98                         raise PKeyError("Signature verification")
99                 libcrypto=EVP_PKEY_CTX_free(ctx)
100                 return rv>0
101         def generate(algorithm,**kwargs):
102                 """
103                         Generates new private-public key pair for given algorithm
104                         (string like 'rsa','ec','gost2001') and algorithm-specific
105                         parameters
106                 """
107                 tmpeng=c_void_p(None)
108                 ameth=libcrypto.EVP_PKEY_asn1_find_str(byref(tmpeng),algorithm,-1)
109                 if ameth is None:
110                         raise PKeyError("Algorithm %s not foind\n"%(algname))
111                 clear_err_stack()
112                 pkey_id=c_int(0)
113                 libcrypto.EVP_PKEY_asn1_get0_info(byref(pkey_id),None,None,None,None,ameth)
114                 libcrypto.ENGINE_finish(tmpeng)
115                 ctx=libcrypto.EVP_PKEY_CTX_new_id(pkey_id)
116                 if ctx is None:
117                         raise PKeyError("Creating context for key type %d"%(pkey_id.value)) 
118                 if libcrypto.EVP_PKEY_keygen_init(ctx) <=0 :
119                         raise PKeyError("keygen_init")
120                 for oper in kwargs:
121                         rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
122                         if rw=-2:
123                                 raise PKeyError("Parameter %s is not supported by key"%(oper))
124                         if rv<1:
125                                 raise PKeyError("Error setting parameter %s"(oper))
126                 key=c_void_p(None)
127                 if libcrypto.EVP_PKEY_keygen(ctx,byref(key))<=0:
128                         raise PKeyError("Error generating key")
129                 libcrypto.EVP_PKEY_CTX_free(ctx)
130                 return PKey(key,True)
131