]> www.wagner.pp.ru Git - oss/ctypescrypto.git/commitdiff
rewrote cipher module
authorVictor Wagner <wagner@atlas-card.ru>
Thu, 5 Jun 2014 14:11:37 +0000 (18:11 +0400)
committerVictor Wagner <wagner@atlas-card.ru>
Thu, 5 Jun 2014 14:11:37 +0000 (18:11 +0400)
README.md
ctypescrypto/cipher.py

index 9abd63b5d14175d49d7c4e11c4e36fda71bcef6e..dfcab2bd7d53abdd289ae9f9f5007fa17893d911 100644 (file)
--- a/README.md
+++ b/README.md
@@ -37,13 +37,11 @@ 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: fully implemented and covered by tests
 
 ciphers.py - Interface to EVP\_Cipher family of function. 
-       Status: Needs complete rewriting and test coverage. Idea to keep
-       cleartext in python variable until entire text would be passed to
-       update is EVIL.
+       Status: Needs documenting and test coverage
 
 pkey.py - Low-level private key operations (like pkey, genpkey and p
     keyutl command line ops), all via algorithm-agnostic EVP interface.
 
 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 mostly implemented but not yet covered by tests
+       Status: Designed and started to implement but not yet covered by tests
 
 exception.py OpenSSL error stack to python exception conversion
        Implemented.
 
 exception.py OpenSSL error stack to python exception conversion
        Implemented.
index 73a14ce1de988e1c993991b3afb77ad4a729cf32..4fb576773a603529a40eb08156c1269039322cd9 100644 (file)
@@ -1,39 +1,52 @@
-from ctypes import *\r
+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
 \r
 CIPHER_ALGORITHMS = ("DES", "DES-EDE3", "BF", "AES-128", "AES-192", "AES-256")\r
-CIPHER_MODES = ("CBC", "CFB", "OFB", "ECB")\r
+CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")\r
 \r
 \r
-class CipherError(Exception):\r
+#\r
+\r
+class CipherError(LibCryptoError):\r
     pass\r
 \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
 class CipherType:\r
 \r
-    def __init__(self, libcrypto, cipher_algo, cipher_mode):\r
-        self.libcrypto = libcrypto\r
-        self.cipher_algo = cipher_algo\r
-        self.cipher_mode = cipher_mode\r
-        cipher_name = "-".join([self.cipher_algo, self.cipher_mode])\r
-        self.cipher = self.libcrypto.EVP_get_cipherbyname(cipher_name)\r
-        if self.cipher == 0:\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
             raise CipherError, "Unknown cipher: %s" % cipher_name\r
 \r
     def __del__(self):\r
         pass\r
-\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
     def algo(self):\r
-        return self.cipher_algo\r
-\r
+        return self.oid().short_name() \r
     def mode(self):\r
         return self.cipher_mode\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
 \r
 class Cipher:\r
 \r
-    def __init__(self, libcrypto, cipher_type, key, iv, encrypt=True):\r
-        self.libcrypto = libcrypto\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._clean_ctx()\r
         key_ptr = c_char_p(key)\r
         iv_ptr = c_char_p(iv)\r
-        self.ctx = self.libcrypto.EVP_CIPHER_CTX_new(cipher_type.cipher, None, key_ptr, iv_ptr)\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 self.ctx == 0:\r
             raise CipherError, "Unable to create cipher context"\r
         self.encrypt = encrypt\r
@@ -41,8 +54,9 @@ class Cipher:
             enc = 1\r
         else: \r
             enc = 0\r
             enc = 1\r
         else: \r
             enc = 0\r
-        result = self.libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))\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.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
         if result == 0:\r
             self._clean_ctx()\r
             raise CipherError, "Unable to initialize cipher"\r
@@ -55,7 +69,7 @@ class Cipher:
             padding_flag = 1\r
         else:\r
             padding_flag = 0\r
             padding_flag = 1\r
         else:\r
             padding_flag = 0\r
-        self.libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)\r
+        libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)\r
 \r
     def update(self, data):\r
         if self.cipher_finalized :\r
 \r
     def update(self, data):\r
         if self.cipher_finalized :\r
@@ -64,29 +78,30 @@ class Cipher:
             raise TypeError, "A string is expected"\r
         if len(data) <= 0:\r
             return ""\r
             raise TypeError, "A string is expected"\r
         if len(data) <= 0:\r
             return ""\r
-        self.data = self.data + data\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
     \r
-    def finish(self, data=None):\r
-        if data is not None:\r
-            self.update(data)\r
-        return self._finish()\r
-        \r
-    def _finish(self):\r
+    def finish(self):\r
         if self.cipher_finalized :\r
             raise CipherError, "Cipher operation is already completed"\r
         if self.cipher_finalized :\r
             raise CipherError, "Cipher operation is already completed"\r
-        self.cipher_out = create_string_buffer(len(self.data) + 32)\r
-        result = self.libcrypto.EVP_CipherUpdate(self.ctx, byref(self.cipher_out), byref(self.cipher_out_len), c_char_p(self.data), len(self.data))\r
-        if result == 0:\r
-            self._clean_ctx()\r
-            raise CipherError, "Unable to update cipher"\r
+               outbuf=create_string_buffer(self.block_size)\r
         self.cipher_finalized = True\r
         self.cipher_finalized = True\r
-        update_data = self.cipher_out.raw[:self.cipher_out_len.value]\r
-        result = self.libcrypto.EVP_CipherFinal_ex(self.ctx, byref(self.cipher_out), byref(self.cipher_out_len))\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 result == 0:\r
             self._clean_ctx()\r
             raise CipherError, "Unable to finalize cipher"\r
-        final_data = self.cipher_out.raw[:self.cipher_out_len.value]\r
-        return update_data + final_data\r
+               if outlen>0:\r
+               return outbuf.raw[:outlen]\r
+               else\r
+                       return ""\r
         \r
     def _clean_ctx(self):\r
         try:\r
         \r
     def _clean_ctx(self):\r
         try:\r
@@ -96,7 +111,4 @@ class Cipher:
                 del(self.ctx)\r
         except AttributeError:\r
             pass\r
                 del(self.ctx)\r
         except AttributeError:\r
             pass\r
-        self.cipher_out = None\r
-        self.cipher_out_len = c_long(0)\r
-        self.data = ""\r
-        self.cipher_finalized = False
\ No newline at end of file
+        self.cipher_finalized = True\r