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
6 class PKeyError(LibCryptoError):
9 CALLBACK_FUNC=CFUNCTYPE(c_int,c_char_p,c_int,c_int,c_char_p)
10 def password_callback(buf,length,rwflag,u):
17 _cb=CALLBACK_FUNC(password_callback)
20 def __init__(self,ptr=None,privkey=None,pubkey=None,format="PEM",cansign=False,password=None):
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")
32 self.key=libcrypto.PEM_read_bio_PrivateKey(b.bio,None,_cb,c_char_p(password))
34 self.key=libcrypto.d2i_PrivateKey_bio(b.bio,None)
36 raise PKeyError("error parsing private key")
37 elif not pubkey is None:
41 self.key=libcrypto.PEM_read_bio_PUBKEY(b.bio,None,_cb,None)
43 self.key=libcrypto.d2i_PUBKEY_bio(b.bio,None)
45 raise PKeyError("error parsing public key")
47 raise TypeError("Neither public, nor private key is specified")
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
56 return libcrypto.EVP_PKEY_cmp(self.key,other.key)==1
57 def __ne__(self,other):
58 return not self.__eq__(other)
60 """ printable representation of public key """
62 libcrypto.EVP_PKEY_print_public(b.bio,self.key,0,None)
65 def sign(self,digest,**kwargs):
67 Signs given digest and retirns signature
68 Keyword arguments allows to set various algorithm-specific
69 parameters. See pkeyutl(1) manual.
71 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
73 raise PKeyError("Initailizing sign context")
74 if libcrypto.EVP_PKEY_sign_init(ctx)<1:
75 raise PKeyError("sign_init")
76 self._configure_context(ctx,kwargs)
77 # Find out signature size
79 if libcrypto.EVP_PKEY_sign(ctx,None,byref(siglen),digest,len(digest))<1:
80 raise PKeyError("signing")
81 sig=create_string_buffer(siglen.value)
82 libcrypto.EVP_PKEY_sign(ctx,sig,byref(siglen),digest,len(digest))
83 libcrypto.EVP_PKEY_CTX_free(ctx)
84 return sig.raw[:siglen.value]
86 def verify(self,digest,signature,**kwargs):
88 Verifies given signature on given digest
89 Returns True if Ok, False if don't match
90 Keyword arguments allows to set algorithm-specific
93 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
95 raise PKeyError("Initailizing verify context")
96 if libcrypto.EVP_PKEY_verify_init(ctx)<1:
97 raise PKeyError("verify_init")
98 self._configure_context(ctx,kwargs)
99 rv=libcrypto.EVP_PKEY_verify(ctx,signature,len(signature),digest,len(digest))
101 raise PKeyError("Signature verification")
102 libcrypto.EVP_PKEY_CTX_free(ctx)
104 def derive(self,peerkey,**kwargs):
106 Derives shared key (DH,ECDH,VKO 34.10). Requires
107 private key available
109 @param peerkey - other key (may be public only)
111 Keyword parameters are algorithm-specific
113 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
115 raise PKeyError("Initailizing derive context")
116 if libcrypto.EVP_PKEY_derive_init(ctx)<1:
117 raise PKeyError("derive_init")
118 self._configure_context(self,ctx,kwargs)
119 if libcrypto.EVP_PKEY_derive_set_peer(ctx,peerkey.key)<=0:
120 raise PKeyError("Cannot set peer key")
122 if libcrypto.EVP_PKEY_derive(ctx,None,byref(keylen))<=0:
123 raise PKeyError("computing shared key length")
124 buf=create_string_buffer(keylen)
125 if libcrypto.EVP_PKEY_derive(ctx,buf,byref(keylen))<=0:
126 raise PKeyError("computing actual shared key")
127 libcrypto.EVP_PKEY_CTX_free(ctx)
128 return buf.raw[:keylen]
130 def generate(algorithm,**kwargs):
132 Generates new private-public key pair for given algorithm
133 (string like 'rsa','ec','gost2001') and algorithm-specific
136 Algorithm specific paramteers for RSA:
138 rsa_keygen_bits=number - size of key to be generated
139 rsa_keygen_pubexp - RSA public expontent(default 65537)
141 Algorithn specific parameters for DSA,DH and EC
143 paramsfrom=PKey object
145 copy parameters of newly generated key from existing key
147 Algorithm specific parameters for GOST2001
149 paramset= paramset name where name is one of
150 'A','B','C','XA','XB','test'
152 paramsfrom does work too
154 tmpeng=c_void_p(None)
155 ameth=libcrypto.EVP_PKEY_asn1_find_str(byref(tmpeng),algorithm,-1)
157 raise PKeyError("Algorithm %s not foind\n"%(algname))
160 libcrypto.EVP_PKEY_asn1_get0_info(byref(pkey_id),None,None,None,None,ameth)
161 libcrypto.ENGINE_finish(tmpeng)
162 if "paramsfrom" in kwargs:
163 ctx=libcrypto.EVP_PKEY_CTX_new(kwargs["paramsfrom"].key,None)
165 ctx=libcrypto.EVP_PKEY_CTX_new_id(pkey_id,None)
166 # FIXME support EC curve as keyword param by invoking paramgen
169 raise PKeyError("Creating context for key type %d"%(pkey_id.value))
170 if libcrypto.EVP_PKEY_keygen_init(ctx) <=0 :
171 raise PKeyError("keygen_init")
172 PKey._configure_context(ctx,kwargs,["paramsfrom"])
174 if libcrypto.EVP_PKEY_keygen(ctx,byref(key))<=0:
175 raise PKeyError("Error generating key")
176 libcrypto.EVP_PKEY_CTX_free(ctx)
177 return PKey(ptr=key,cansign=True)
179 def _configure_context(ctx,opts,skip=[]):
181 Configures context of public key operations
182 @param ctx - context to configure
183 @param opts - dictionary of options (from kwargs of calling
185 @param skip - list of options which shouldn't be passed to
192 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,str(opts[oper]))
194 raise PKeyError("Parameter %s is not supported by key"%(oper))
196 raise PKeyError("Error setting parameter %s"(oper))
197 # Declare function prototypes
198 libcrypto.EVP_PKEY_cmp.argtypes=(c_void_p,c_void_p)
199 libcrypto.PEM_read_bio_PrivateKey.restype=c_void_p
200 libcrypto.PEM_read_bio_PrivateKey.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p)
201 libcrypto.PEM_read_bio_PUBKEY.restype=c_void_p
202 libcrypto.PEM_read_bio_PUBKEY.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p)
203 libcrypto.d2i_PUBKEY_bio.restype=c_void_p
204 libcrypto.d2i_PUBKEY_bio.argtypes=(c_void_p,c_void_p)
205 libcrypto.d2i_PrivateKey_bio.restype=c_void_p
206 libcrypto.d2i_PrivateKey_bio.argtypes=(c_void_p,c_void_p)
207 libcrypto.EVP_PKEY_print_public.argtypes=(c_void_p,c_void_p,c_int,c_void_p)
208 libcrypto.EVP_PKEY_asn1_find_str.restype=c_void_p
209 libcrypto.EVP_PKEY_asn1_find_str.argtypes=(c_void_p,c_char_p,c_int)
210 libcrypto.EVP_PKEY_asn1_get0_info.restype=c_int
211 libcrypto.EVP_PKEY_asn1_get0_info.argtypes=(POINTER(c_int),POINTER(c_int),POINTER(c_int),POINTER(c_char_p), POINTER(c_char_p),c_void_p)
212 libcrypto.EVP_PKEY_cmp.restype=c_int
213 libcrypto.EVP_PKEY_cmp.argtypes=(c_void_p,c_void_p)
214 libcrypto.EVP_PKEY_CTX_ctrl_str.restype=c_int
215 libcrypto.EVP_PKEY_CTX_ctrl_str.argtypes=(c_void_p,)
216 libcrypto.EVP_PKEY_CTX_free.argtypes=(c_void_p,)
217 libcrypto.EVP_PKEY_CTX_new.restype=c_void_p
218 libcrypto.EVP_PKEY_CTX_new.argtypes=(c_void_p,c_void_p)
219 libcrypto.EVP_PKEY_CTX_new_id.restype=c_void_p
220 libcrypto.EVP_PKEY_CTX_new_id.argtypes=(c_int,c_void_p)
221 libcrypto.EVP_PKEY_derive.restype=c_int
222 libcrypto.EVP_PKEY_derive.argtypes=(c_void_p,c_char_p,POINTER(c_long))
223 libcrypto.EVP_PKEY_derive_init.restype=c_int
224 libcrypto.EVP_PKEY_derive_init.argtypes=(c_void_p,)
225 libcrypto.EVP_PKEY_derive_set_peer.restype=c_int
226 libcrypto.EVP_PKEY_derive_set_peer.argtypes=(c_void_p,c_void_p)
227 libcrypto.EVP_PKEY_free.argtypes=(c_void_p,)
228 libcrypto.EVP_PKEY_keygen.restype=c_int
229 libcrypto.EVP_PKEY_keygen.argtypes=(c_void_p,c_void_p)
230 libcrypto.EVP_PKEY_keygen_init.restype=c_int
231 libcrypto.EVP_PKEY_keygen_init.argtypes=(c_void_p,)
232 libcrypto.EVP_PKEY_sign.restype=c_int
233 libcrypto.EVP_PKEY_sign.argtypes=(c_void_p,c_char_p,POINTER(c_long),c_char_p,c_long)
234 libcrypto.EVP_PKEY_sign_init.restype=c_int
235 libcrypto.EVP_PKEY_sign_init.argtypes=(c_void_p,)
236 libcrypto.EVP_PKEY_verify.restype=c_int
237 libcrypto.EVP_PKEY_verify.argtypes=(c_void_p,c_char_p,c_long,c_char_p,c_long)
238 libcrypto.EVP_PKEY_verify_init.restype=c_int
239 libcrypto.EVP_PKEY_verify_init.argtypes=(c_void_p,)