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
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,cansign)
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
29 return libcrypto.EVP_PKEY_cmp(self.key,other.key)==1
30 def __ne__(self,other):
31 return not self.__eq__(other)
33 """ printable representation of public key """
35 libcrypto.EVP_PKEY_print_public(b.bio,self.key,0,NULL)
37 def privpem(s,password=None):
38 """ Class method for load from the pem string of private key """
40 return PKey(libcrypto.PEM_read_bio_PrivateKey(b.bio,NULL,_cb,c_char_p(password))
43 """ Class method for load from the binary ASN1 structure of private key """
45 return PKey(libcrypto.d2i_PrivateKey_bio(b.bio,NULL),True)
47 """ Class method for load from public key pem string"""
49 return PKey(libcrypto.PEM_read_bio_PUBKEY(b.bio,NULL,cb,c_char_p(password)),False)
51 """ Class method for load from the binary ASN1 structure """
53 return PKey(libcrypto.d2i_PUBKEY_bio(b.bio,NULL),False)
54 def sign(self,digest,**kwargs):
56 Signs given digest and retirns signature
57 Keyword arguments allows to set various algorithm-specific
58 parameters. See pkeyutl(1) manual.
60 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
62 raise PKeyError("Initailizing sign context")
63 if libcrypto.EVP_PKEY_sign_init(ctx)<1:
64 raise PKeyError("sign_init")
66 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
68 raise PKeyError("Parameter %s is not supported by key"%(oper))
70 raise PKeyError("Error setting parameter %s"(oper))
71 # Find out signature size
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]
80 def verify(self,digest,signature,**kwargs):
82 Verifies given signature on given digest
83 Returns True if Ok, False if don't match
85 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
87 raise PKeyError("Initailizing verify context")
88 if libcrypto.EVP_PKEY_verify_init(ctx)<1:
89 raise PKeyError("verify_init")
91 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
93 raise PKeyError("Parameter %s is not supported by key"%(oper))
95 raise PKeyError("Error setting parameter %s"(oper))
96 rv=libcrypto.EVP_PKEY_verify(ctx,signature,len(signature),digest,len(digest))
98 raise PKeyError("Signature verification")
99 libcrypto=EVP_PKEY_CTX_free(ctx)
101 def generate(algorithm,**kwargs):
103 Generates new private-public key pair for given algorithm
104 (string like 'rsa','ec','gost2001') and algorithm-specific
107 tmpeng=c_void_p(None)
108 ameth=libcrypto.EVP_PKEY_asn1_find_str(byref(tmpeng),algorithm,-1)
110 raise PKeyError("Algorithm %s not foind\n"%(algname))
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)
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")
121 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
123 raise PKeyError("Parameter %s is not supported by key"%(oper))
125 raise PKeyError("Error setting parameter %s"(oper))
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)