]> wagner.pp.ru Git - oss/ctypescrypto.git/blobdiff - ctypescrypto/cipher.py
Initial commit of modules
[oss/ctypescrypto.git] / ctypescrypto / cipher.py
diff --git a/ctypescrypto/cipher.py b/ctypescrypto/cipher.py
new file mode 100644 (file)
index 0000000..73a14ce
--- /dev/null
@@ -0,0 +1,102 @@
+from ctypes import *\r
+\r
+CIPHER_ALGORITHMS = ("DES", "DES-EDE3", "BF", "AES-128", "AES-192", "AES-256")\r
+CIPHER_MODES = ("CBC", "CFB", "OFB", "ECB")\r
+\r
+class CipherError(Exception):\r
+    pass\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
+            raise CipherError, "Unknown cipher: %s" % cipher_name\r
+\r
+    def __del__(self):\r
+        pass\r
+\r
+    def algo(self):\r
+        return self.cipher_algo\r
+\r
+    def mode(self):\r
+        return self.cipher_mode\r
+\r
+class Cipher:\r
+\r
+    def __init__(self, libcrypto, cipher_type, key, iv, encrypt=True):\r
+        self.libcrypto = libcrypto\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
+        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 = self.libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))\r
+        self.cipher_type = cipher_type\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
+        self.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
+        self.data = self.data + data\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
+        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
+        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
+        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
+        \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_out = None\r
+        self.cipher_out_len = c_long(0)\r
+        self.data = ""\r
+        self.cipher_finalized = False
\ No newline at end of file