From 2f721f8751a08e35ae3a8a63dd53e2d9ab216c47 Mon Sep 17 00:00:00 2001 From: Victor Wagner Date: Fri, 6 Jun 2014 15:32:47 +0400 Subject: [PATCH] pkey generation testsd --- .gitignore | 1 + ctypescrypto/pkey.py | 109 ++++++++++++++++++++++++++++++++----------- tests/testpkey.py | 19 +++++++- 3 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ee5fdf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pic diff --git a/ctypescrypto/pkey.py b/ctypescrypto/pkey.py index 50dccd0..a561ddf 100644 --- a/ctypescrypto/pkey.py +++ b/ctypescrypto/pkey.py @@ -2,7 +2,7 @@ from ctypes import c_char_p,c_void_p,byref,c_int,c_long, c_longlong, create_stri from ctypescrypto import libcrypto from ctypescrypto.exception import LibCryptoError,clear_err_stack from ctypescrypto.bio import Membio - +import sys class PKeyError(LibCryptoError): pass @@ -73,12 +73,7 @@ class PKey: raise PKeyError("Initailizing sign context") if libcrypto.EVP_PKEY_sign_init(ctx)<1: raise PKeyError("sign_init") - for oper in kwargs: - rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper]) - if rv==-2: - raise PKeyError("Parameter %s is not supported by key"%(oper)) - if rv<1: - raise PKeyError("Error setting parameter %s"(oper)) + self._configure_context(ctx,kwargs) # Find out signature size siglen=c_long(0) if libcrypto.EVP_PKEY_sign(ctx,None,byref(siglen),digest,len(digest))<1: @@ -92,18 +87,15 @@ class PKey: """ Verifies given signature on given digest Returns True if Ok, False if don't match + Keyword arguments allows to set algorithm-specific + parameters """ ctx=libcrypto.EVP_PKEY_CTX_new(self.key,None) if ctx is None: raise PKeyError("Initailizing verify context") if libcrypto.EVP_PKEY_verify_init(ctx)<1: raise PKeyError("verify_init") - for oper in kwargs: - rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper]) - if rv==-2: - raise PKeyError("Parameter %s is not supported by key"%(oper)) - if rv<1: - raise PKeyError("Error setting parameter %s"(oper)) + self._configure_context(ctx,kwargs) rv=libcrypto.EVP_PKEY_verify(ctx,signature,len(signature),digest,len(digest)) if rv<0: raise PKeyError("Signature verification") @@ -123,12 +115,7 @@ class PKey: raise PKeyError("Initailizing derive context") if libcrypto.EVP_PKEY_derive_init(ctx)<1: raise PKeyError("derive_init") - for oper in kwargs: - rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper]) - if rv==-2: - raise PKeyError("Parameter %s is not supported by key"%(oper)) - if rv<1: - raise PKeyError("Error setting parameter %s"(oper)) + self._configure_context(self,ctx,kwargs) if libcrypto.EVP_PKEY_derive_set_peer(ctx,peerkey.key)<=0: raise PKeyError("Cannot set peer key") keylen=c_long(0) @@ -144,7 +131,25 @@ class PKey: """ Generates new private-public key pair for given algorithm (string like 'rsa','ec','gost2001') and algorithm-specific - parameters + parameters. + + Algorithm specific paramteers for RSA: + + rsa_keygen_bits=number - size of key to be generated + rsa_keygen_pubexp - RSA public expontent(default 65537) + + Algorithn specific parameters for DSA,DH and EC + + paramsfrom=PKey object + + copy parameters of newly generated key from existing key + + Algorithm specific parameters for GOST2001 + + paramset= paramset name where name is one of + 'A','B','C','XA','XB','test' + + paramsfrom does work too """ tmpeng=c_void_p(None) ameth=libcrypto.EVP_PKEY_asn1_find_str(byref(tmpeng),algorithm,-1) @@ -154,23 +159,41 @@ class PKey: pkey_id=c_int(0) libcrypto.EVP_PKEY_asn1_get0_info(byref(pkey_id),None,None,None,None,ameth) libcrypto.ENGINE_finish(tmpeng) - ctx=libcrypto.EVP_PKEY_CTX_new_id(pkey_id) + if "paramsfrom" in kwargs: + ctx=libcrypto.EVP_PKEY_CTX_new(kwargs["paramsfrom"].key,None) + else: + ctx=libcrypto.EVP_PKEY_CTX_new_id(pkey_id,None) + # FIXME support EC curve as keyword param by invoking paramgen + # operation if ctx is None: raise PKeyError("Creating context for key type %d"%(pkey_id.value)) if libcrypto.EVP_PKEY_keygen_init(ctx) <=0 : raise PKeyError("keygen_init") - for oper in kwargs: - rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,kwargs[oper]) - if rw==-2: - raise PKeyError("Parameter %s is not supported by key"%(oper)) - if rv<1: - raise PKeyError("Error setting parameter %s"(oper)) + PKey._configure_context(ctx,kwargs,["paramsfrom"]) key=c_void_p(None) if libcrypto.EVP_PKEY_keygen(ctx,byref(key))<=0: raise PKeyError("Error generating key") libcrypto.EVP_PKEY_CTX_free(ctx) return PKey(ptr=key,cansign=True) + @staticmethod + def _configure_context(ctx,opts,skip=[]): + """ + Configures context of public key operations + @param ctx - context to configure + @param opts - dictionary of options (from kwargs of calling + function) + @param skip - list of options which shouldn't be passed to + context + """ + for oper in opts: + if oper in skip: + continue + rv=libcrypto.EVP_PKEY_CTX_ctrl_str(ctx,oper,str(opts[oper])) + if rv==-2: + raise PKeyError("Parameter %s is not supported by key"%(oper)) + if rv<1: + raise PKeyError("Error setting parameter %s"(oper)) # Declare function prototypes libcrypto.EVP_PKEY_cmp.argtypes=(c_void_p,c_void_p) libcrypto.PEM_read_bio_PrivateKey.restype=c_void_p @@ -182,4 +205,36 @@ libcrypto.d2i_PUBKEY_bio.argtypes=(c_void_p,c_void_p) libcrypto.d2i_PrivateKey_bio.restype=c_void_p libcrypto.d2i_PrivateKey_bio.argtypes=(c_void_p,c_void_p) libcrypto.EVP_PKEY_print_public.argtypes=(c_void_p,c_void_p,c_int,c_void_p) +libcrypto.EVP_PKEY_asn1_find_str.restype=c_void_p +libcrypto.EVP_PKEY_asn1_find_str.argtypes=(c_void_p,c_char_p,c_int) +libcrypto.EVP_PKEY_asn1_get0_info.restype=c_int +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) +libcrypto.EVP_PKEY_cmp.restype=c_int +libcrypto.EVP_PKEY_cmp.argtypes=(c_void_p,c_void_p) +libcrypto.EVP_PKEY_CTX_ctrl_str.restype=c_int +libcrypto.EVP_PKEY_CTX_ctrl_str.argtypes=(c_void_p,) +libcrypto.EVP_PKEY_CTX_free.argtypes=(c_void_p,) +libcrypto.EVP_PKEY_CTX_new.restype=c_void_p +libcrypto.EVP_PKEY_CTX_new.argtypes=(c_void_p,c_void_p) +libcrypto.EVP_PKEY_CTX_new_id.restype=c_void_p +libcrypto.EVP_PKEY_CTX_new_id.argtypes=(c_int,c_void_p) +libcrypto.EVP_PKEY_derive.restype=c_int +libcrypto.EVP_PKEY_derive.argtypes=(c_void_p,c_char_p,POINTER(c_long)) +libcrypto.EVP_PKEY_derive_init.restype=c_int +libcrypto.EVP_PKEY_derive_init.argtypes=(c_void_p,) +libcrypto.EVP_PKEY_derive_set_peer.restype=c_int +libcrypto.EVP_PKEY_derive_set_peer.argtypes=(c_void_p,c_void_p) +libcrypto.EVP_PKEY_free.argtypes=(c_void_p,) +libcrypto.EVP_PKEY_keygen.restype=c_int +libcrypto.EVP_PKEY_keygen.argtypes=(c_void_p,c_void_p) +libcrypto.EVP_PKEY_keygen_init.restype=c_int +libcrypto.EVP_PKEY_keygen_init.argtypes=(c_void_p,) +libcrypto.EVP_PKEY_sign.restype=c_int +libcrypto.EVP_PKEY_sign.argtypes=(c_void_p,c_char_p,POINTER(c_long),c_char_p,c_long) +libcrypto.EVP_PKEY_sign_init.restype=c_int +libcrypto.EVP_PKEY_sign_init.argtypes=(c_void_p,) +libcrypto.EVP_PKEY_verify.restype=c_int +libcrypto.EVP_PKEY_verify.argtypes=(c_void_p,c_char_p,c_long,c_char_p,c_long) +libcrypto.EVP_PKEY_verify_init.restype=c_int +libcrypto.EVP_PKEY_verify_init.argtypes=(c_void_p,) diff --git a/tests/testpkey.py b/tests/testpkey.py index 4b55603..c54b3e1 100644 --- a/tests/testpkey.py +++ b/tests/testpkey.py @@ -8,7 +8,7 @@ def pem2der(s): data=s[start+6:finish] return b64decode(data) -class TestReadPkey(unittest.TestCase): +class TestPKey(unittest.TestCase): rsa="""-----BEGIN PRIVATE KEY----- MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAL9CzVZu9bczTmB8 776pPUoPo6WbAfwQqqiGrj91bk2mYE+MNLo4yIQH45IcwGzkyS8+YyQJf8Bux5BC @@ -93,5 +93,22 @@ AvhqdgCWLMG0D4Rj4oCqJcyG2WH8J5+0DnGujfEA4TwJ90ECvLa2SA== self.assertTrue(len(signature)>0) verifier=PKey(pubkey=self.ec1pub) self.assertTrue(verifier.verify(digest,signature)) + def test_generate(self): + newkey=PKey.generate("rsa") + self.assertIsNotNone(newkey.key) + s=str(newkey) + self.assertEqual(s[:s.find("\n")],"Public-Key: (1024 bit)") + def test_generate_params(self): + newkey=PKey.generate("rsa",rsa_keygen_bits=2048) + self.assertIsNotNone(newkey.key) + s=str(newkey) + self.assertEqual(s[:s.find("\n")],"Public-Key: (2048 bit)") + def test_generate_ec(self): + templkey=PKey(pubkey=self.ec1pub) + newkey=PKey.generate("ec",paramsfrom=templkey) + self.assertIsNotNone(newkey.key) + s=str(newkey) + self.assertEqual(s[:s.find("\n")],"Public-Key: (256 bit)") + self.assertNotEqual(str(templkey),str(newkey)) if __name__ == "__main__": unittest.main() -- 2.39.5