]> www.wagner.pp.ru Git - oss/ctypescrypto.git/commitdiff
Added more function declarations. Added @staticmethod to PKey.generate. Documented...
authorVictor Wagner <wagner@atlas-card.ru>
Fri, 6 Jun 2014 07:51:09 +0000 (11:51 +0400)
committerVictor Wagner <wagner@atlas-card.ru>
Fri, 6 Jun 2014 07:51:09 +0000 (11:51 +0400)
README.md
ctypescrypto/bio.py
ctypescrypto/cipher.py
ctypescrypto/engine.py
ctypescrypto/pkey.py

index dfcab2bd7d53abdd289ae9f9f5007fa17893d911..2054f7bc5730d733c3f3b3d202797e3a503a3a3a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -37,11 +37,12 @@ digests.py  - Interface  to EVP\_Digest\* family of functions.
        Status: fully implemented and covered by tests
 
 ciphers.py - Interface to EVP\_Cipher family of function. 
-       Status: Needs documenting and test coverage
+       Status: Needs test coverage
 
 pkey.py - Low-level private key operations (like pkey, genpkey and p
     keyutl command line ops), all via algorithm-agnostic EVP interface.
-       Status: Designed and started to implement but not yet covered by tests
+       Status: Designed and started to implement but most functionality 
+       not yet covered by tests
 
 exception.py OpenSSL error stack to python exception conversion
        Implemented.
index 92de35c5dd27fe4eba15966b038e6aa24590d732..642b96b72c140c5c74382bf01a1c5fd8823d6c55 100644 (file)
@@ -64,3 +64,6 @@ libcrypto.BIO_ctrl.restype=c_long
 libcrypto.BIO_ctrl.argtypes=(c_void_p,c_int,c_long,POINTER(c_char_p))
 libcrypto.BIO_read.argtypes=(c_void_p,c_char_p,c_int)
 libcrypto.BIO_write.argtypes=(c_void_p,c_char_p,c_int)
+libcrypto.BIO_free.argtypes=(c_void_p,)
+libcrypto.BIO_new_mem_buf.restype=c_void_p
+libcrypto.BIO_new_mem_buf.argtypes=(c_char_p,c_int)
index 4fb576773a603529a40eb08156c1269039322cd9..1ea4f797d7f4d87e88e86832ae438651d18dde68 100644 (file)
-from ctypes import create_string_buffer,c_char_p,c_void_p,c_int,c_long,byref\r
-from ctypescrypto import libcrypto\r
-from ctypescryto.exception import LibCrytoError\r
-\r
-CIPHER_ALGORITHMS = ("DES", "DES-EDE3", "BF", "AES-128", "AES-192", "AES-256")\r
-CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")\r
-\r
-#\r
-\r
-class CipherError(LibCryptoError):\r
-    pass\r
-\r
-def new(algname,key,encrypt=True,iv=None):\r
-       ct=CipherType(algname)\r
-       return Cipher(ct,key,iv,encrypt)\r
-\r
-class CipherType:\r
-\r
-    def __init__(self, cipher_name):\r
-        self.cipher = libcrypto.EVP_get_cipherbyname(cipher_name)\r
-        if self.cipher is None:\r
-            raise CipherError, "Unknown cipher: %s" % cipher_name\r
-\r
-    def __del__(self):\r
-        pass\r
-       def block_size(self):\r
-               return libcrypto.EVP_CIHPER_block_size(self.cipher)\r
-       def key_length(self):\r
-               return libcrypto.EVP_CIPHER_key_length(self.cipher)\r
-       def iv_length(self):\r
-               return libcrypto.EVP_CIPHER_iv_length(self.cipher)\r
-       def flags(self):\r
-               return libcrypto.EVP_CIPHER_flags(self.cipher)\r
-       def mode(self):\r
-               return CIPHER_MODES[self.flags & 0x7]\r
-    def algo(self):\r
-        return self.oid().short_name() \r
-    def mode(self):\r
-        return self.cipher_mode\r
-       def oid(self):\r
-               return Oid(libcrypto.EVP_CIPHER_nid(self.cipher))\r
-\r
-class Cipher:\r
-\r
-    def __init__(self,  cipher_type, key, iv, encrypt=True):\r
-        self._clean_ctx()\r
-        key_ptr = c_char_p(key)\r
-        iv_ptr = c_char_p(iv)\r
-        self.ctx = libcrypto.EVP_CIPHER_CTX_new(cipher_type.cipher, None, key_ptr, iv_ptr)\r
-        if self.ctx == 0:\r
-            raise CipherError, "Unable to create cipher context"\r
-        self.encrypt = encrypt\r
-        if encrypt: \r
-            enc = 1\r
-        else: \r
-            enc = 0\r
-        result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))\r
-        self.cipher_type = cipher_type\r
-               self.block_size = self.cipher_type.block_size()\r
-        if result == 0:\r
-            self._clean_ctx()\r
-            raise CipherError, "Unable to initialize cipher"\r
-\r
-    def __del__(self):\r
-        self._clean_ctx()\r
-\r
-    def enable_padding(self, padding=True):\r
-        if padding:\r
-            padding_flag = 1\r
-        else:\r
-            padding_flag = 0\r
-        libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)\r
-\r
-    def update(self, data):\r
-        if self.cipher_finalized :\r
-            raise CipherError, "No updates allowed"\r
-        if type(data) != type(""):\r
-            raise TypeError, "A string is expected"\r
-        if len(data) <= 0:\r
-            return ""\r
-               outbuf=string_buffer_create(self.blocsize+len(data))\r
-               outlen=c_int(0)\r
-               ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),\r
-                       data,len(data))\r
-               if ret <=0:\r
-                       self._clean_ctx()\r
-                       self.cipher_finalized=True\r
-                       del self.ctx\r
-                       raise CipherError("problem processing data")\r
-               return outbuf.raw[:outlen]\r
-    \r
-    def finish(self):\r
-        if self.cipher_finalized :\r
-            raise CipherError, "Cipher operation is already completed"\r
-               outbuf=create_string_buffer(self.block_size)\r
-        self.cipher_finalized = True\r
-        result = self.libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))\r
-        if result == 0:\r
-            self._clean_ctx()\r
-            raise CipherError, "Unable to finalize cipher"\r
-               if outlen>0:\r
-               return outbuf.raw[:outlen]\r
-               else\r
-                       return ""\r
-        \r
-    def _clean_ctx(self):\r
-        try:\r
-            if self.ctx is not None:\r
-                self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)\r
-                self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)\r
-                del(self.ctx)\r
-        except AttributeError:\r
-            pass\r
-        self.cipher_finalized = True\r
+from ctypes import create_string_buffer,c_char_p,c_void_p,c_int,c_long,byref,POINTER
+from ctypescrypto import libcrypto
+from ctypescrypto.exception import LibCryptoError
+from ctypescrypto.oid import Oid
+
+CIPHER_ALGORITHMS = ("DES", "DES-EDE3", "BF", "AES-128", "AES-192", "AES-256")
+CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")
+
+#
+
+class CipherError(LibCryptoError):
+       pass
+
+def new(algname,key,encrypt=True,iv=None):
+       """
+               Returns new cipher object ready to encrypt-decrypt data
+
+               @param algname - string algorithm name like in opemssl command
+                                               line
+               @param key - binary string representing ciher key
+               @param encrypt - if True (default) cipher would be initialized
+                                       for encryption, otherwise - for decrypton
+               @param iv - initialization vector
+       """
+       ct=CipherType(algname)
+       return Cipher(ct,key,iv,encrypt)
+
+class CipherType:
+       """
+               Describes cihper algorihm. Can be used to produce cipher
+               instance and to get various information about cihper
+       """
+
+       def __init__(self, cipher_name):
+               """
+                       Constructs cipher algortihm using textual name as in openssl
+                       command line
+               """
+               self.cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
+               if self.cipher is None:
+                       raise CipherError, "Unknown cipher: %s" % cipher_name
+
+       def __del__(self):
+               pass
+       def block_size(self):
+               """
+                       Returns block size of the cipher
+               """
+               return libcrypto.EVP_CIPHER_block_size(self.cipher)
+       def key_length(self):
+               """
+                       Returns key length of the cipher
+               """
+               return libcrypto.EVP_CIPHER_key_length(self.cipher)
+       def iv_length(self):
+               """
+                       Returns initialization vector length of the cipher
+               """
+               return libcrypto.EVP_CIPHER_iv_length(self.cipher)
+       def flags(self):
+               """
+                       Return cipher flags. Low three bits of the flags encode 
+                       cipher mode (see mode). Higher bits  is combinatuon of
+                       EVP_CIPH* constants defined in the <openssl/evp.h>
+               """
+               return libcrypto.EVP_CIPHER_flags(self.cipher)
+       def mode(self):
+               """
+                       Returns cipher mode as string constant like CBC, OFB etc.
+               """
+               return CIPHER_MODES[self.flags() & 0x7]
+       def algo(self):
+               """
+                       Return cipher's algorithm name, derived from OID
+               """
+               return self.oid().short_name() 
+       def oid(self):
+               """
+                       Returns ASN.1 object identifier of the cipher as
+                       ctypescrypto.oid.Oid object
+               """
+               return Oid(libcrypto.EVP_CIPHER_nid(self.cipher))
+
+class Cipher:
+       """
+               Performs actual encrypton decryption
+               Note that object keeps some internal state. 
+               To obtain full ciphertext (or plaintext during decihpering)
+               user should concatenate results of all calls of update with
+               result of finish
+       """
+       def __init__(self,      cipher_type, key, iv, encrypt=True):
+               """
+                       Initializing cipher instance.
+
+                       @param  cipher_type - CipherType object
+                       @param key = binary string representing the key
+                       @param iv - binary string representing initializtion vector
+                       @param encrypt - if True(default) we ere encrypting.
+                                       Otherwise decrypting
+
+               """
+               self._clean_ctx()
+               key_ptr = c_char_p(key)
+               iv_ptr = c_char_p(iv)
+               self.ctx = libcrypto.EVP_CIPHER_CTX_new()
+               if self.ctx == 0:
+                       raise CipherError, "Unable to create cipher context"
+               self.encrypt = encrypt
+               if encrypt: 
+                       enc = 1
+               else: 
+                       enc = 0
+               result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
+               if result == 0:
+                       self._clean_ctx()
+                       raise CipherError, "Unable to initialize cipher"
+               self.cipher_type = cipher_type
+               self.block_size = self.cipher_type.block_size()
+               self.cipher_finalized = False
+
+       def __del__(self):
+               self._clean_ctx()
+
+       def padding(self, padding=True):
+               """
+                       Sets padding mode of the cipher
+               """
+               if padding:
+                       padding_flag = 1
+               else:
+                       padding_flag = 0
+               libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
+
+       def update(self, data):
+               """
+                       Performs actual encrypton/decrypion
+
+                       @param data - part of the plain text/ciphertext to process
+                       @returns - part of ciphercext/plain text
+
+                       Passd chunk of text doeesn't need to contain full ciher
+                       blocks. If neccessery, part of passed data would be kept
+                       internally until next data would be received or finish
+                       called
+               """
+               if self.cipher_finalized :
+                       raise CipherError, "No updates allowed"
+               if type(data) != type(""):
+                       raise TypeError, "A string is expected"
+               if len(data) <= 0:
+                       return ""
+               outbuf=create_string_buffer(self.block_size+len(data))
+               outlen=c_int(0)
+               ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),
+                       data,len(data))
+               if ret <=0:
+                       self._clean_ctx()
+                       self.cipher_finalized=True
+                       del self.ctx
+                       raise CipherError("problem processing data")
+               return outbuf.raw[:outlen.value]
+       
+       def finish(self):
+               """
+                       Finalizes processing. If some data are kept in the internal
+                       state, they would be processed and returned.
+               """
+               if self.cipher_finalized :
+                       raise CipherError, "Cipher operation is already completed"
+               outbuf=create_string_buffer(self.block_size)
+               self.cipher_finalized = True
+               outlen=c_int()
+               result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
+               if result == 0:
+                       self._clean_ctx()
+                       raise CipherError, "Unable to finalize cipher"
+               if outlen.value>0:
+                       return outbuf.raw[:outlen.value]
+               else:
+                       return ""
+               
+       def _clean_ctx(self):
+               try:
+                       if self.ctx is not None:
+                               self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
+                               self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)
+                               del(self.ctx)
+               except AttributeError:
+                       pass
+               self.cipher_finalized = True
+
+
+#
+# Used C function block_size
+#
+libcrypto.EVP_CIPHER_block_size.argtypes=(c_void_p,)
+libcrypto.EVP_CIPHER_CTX_cleanup.argtypes=(c_void_p,)
+libcrypto.EVP_CIPHER_CTX_free.argtypes=(c_void_p,)
+libcrypto.EVP_CIPHER_CTX_new.restype=c_void_p
+libcrypto.EVP_CIPHER_CTX_set_padding.argtypes=(c_void_p,c_int)
+libcrypto.EVP_CipherFinal_ex.argtypes=(c_void_p,c_char_p,POINTER(c_int))
+libcrypto.EVP_CIPHER_flags.argtypes=(c_void_p,)
+libcrypto.EVP_CipherInit_ex.argtypes=(c_void_p,c_void_p,c_void_p,c_char_p,c_char_p,c_int)
+libcrypto.EVP_CIPHER_iv_length.argtypes=(c_void_p,)
+libcrypto.EVP_CIPHER_key_length.argtypes=(c_void_p,)
+libcrypto.EVP_CIPHER_nid.argtypes=(c_void_p,)
+libcrypto.EVP_CipherUpdate.argtypes=(c_void_p,c_char_p,POINTER(c_int),c_char_p,c_int)
+libcrypto.EVP_get_cipherbyname.restype=c_void_p
+libcrypto.EVP_get_cipherbyname.argtypes=(c_char_p,)
+
index 47f4878d72d9c542a5659002302d72375c46c5b5..f05fcb0a49200e2d65149d9166983e6b024f05ab 100644 (file)
@@ -25,3 +25,4 @@ libcrypto.ENGINE_by_id.restype=c_void_p
 libcrypto.ENGINE_by_id.argtypes=(c_char_p,)
 libcrypto.ENGINE_set_default.argtypes=(c_void_p,c_int)
 libcrypto.ENGINE_ctrl_cmd_string.argtypes=(c_void_p,c_char_p,c_char_p,c_int)
+libcrypto.ENGINE_finish.argtypes=(c_char_p,)
index bb995331bb8d4a757b7a9db149399e7a4a55a21e..50dccd059a349b54e07a64c6bf1f59254e92e7b0 100644 (file)
@@ -139,6 +139,7 @@ class PKey:
                        raise PKeyError("computing actual shared key")
                libcrypto.EVP_PKEY_CTX_free(ctx)
                return buf.raw[:keylen]
+       @staticmethod
        def generate(algorithm,**kwargs):
                """
                        Generates new private-public key pair for given algorithm
@@ -174,11 +175,11 @@ class PKey:
 libcrypto.EVP_PKEY_cmp.argtypes=(c_void_p,c_void_p)
 libcrypto.PEM_read_bio_PrivateKey.restype=c_void_p
 libcrypto.PEM_read_bio_PrivateKey.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p) 
-libcrypto.d2i_PKCS8PrivateKey_bio.restype=c_void_p
-libcrypto.d2i_PKCS8PrivateKey_bio.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p)
 libcrypto.PEM_read_bio_PUBKEY.restype=c_void_p
 libcrypto.PEM_read_bio_PUBKEY.argtypes=(c_void_p,POINTER(c_void_p),CALLBACK_FUNC,c_char_p)
 libcrypto.d2i_PUBKEY_bio.restype=c_void_p
 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)