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_PKCS8PrivateKey_bio(b.bio,None,_cb,c_char_p(password))
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")
77 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
79 raise PKeyError("Parameter %s is not supported by key"%(oper))
81 raise PKeyError("Error setting parameter %s"(oper))
82 # Find out signature size
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]
91 def verify(self,digest,signature,**kwargs):
93 Verifies given signature on given digest
94 Returns True if Ok, False if don't match
96 ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None)
98 raise PKeyError("Initailizing verify context")
99 if libcrypto.EVP_PKEY_verify_init(ctx)<1:
100 raise PKeyError("verify_init")
102 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
104 raise PKeyError("Parameter %s is not supported by key"%(oper))
106 raise PKeyError("Error setting parameter %s"(oper))
107 rv=libcrypto.EVP_PKEY_verify(ctx,signature,len(signature),digest,len(digest))
109 raise PKeyError("Signature verification")
110 libcrypto=EVP_PKEY_CTX_free(ctx)
112 def generate(algorithm,**kwargs):
114 Generates new private-public key pair for given algorithm
115 (string like 'rsa','ec','gost2001') and algorithm-specific
118 tmpeng=c_void_p(None)
119 ameth=libcrypto.EVP_PKEY_asn1_find_str(byref(tmpeng),algorithm,-1)
121 raise PKeyError("Algorithm %s not foind\n"%(algname))
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)
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")
132 rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper])
134 raise PKeyError("Parameter %s is not supported by key"%(oper))
136 raise PKeyError("Error setting parameter %s"(oper))
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)
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)