]> www.wagner.pp.ru Git - oss/ctypescrypto.git/blobdiff - ctypescrypto/cipher.py
Merge branch 'master' of https://github.com/vbwagner/ctypescrypto
[oss/ctypescrypto.git] / ctypescrypto / cipher.py
index 1ea4f797d7f4d87e88e86832ae438651d18dde68..332272570f824c9830dbe003a09c123f138b5aa7 100644 (file)
@@ -1,3 +1,7 @@
+"""
+access to symmetric ciphers from libcrypto
+
+"""
 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
@@ -8,6 +12,8 @@ CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")
 
 #
 
+__all__ = ['CipherError','new','Cipher','CipherType']
+
 class CipherError(LibCryptoError):
        pass
 
@@ -38,7 +44,7 @@ class CipherType:
                """
                self.cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
                if self.cipher is None:
-                       raise CipherError, "Unknown cipher: %s" % cipher_name
+                       raise CipherError("Unknown cipher: %s" % cipher_name)
 
        def __del__(self):
                pass
@@ -101,20 +107,39 @@ class Cipher:
 
                """
                self._clean_ctx()
+               # Check key and iv length
+               if key is None:
+                       raise ValueError("No key specified")
+
                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"
+                       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 not iv is None and len(iv) != cipher_type.iv_length():
+                       raise ValueError("Invalid IV length for this algorithm")
+                       
+               if len(key) != cipher_type.key_length():
+                       if (cipher_type.flags() & 8) != 0:
+                               # Variable key length cipher.
+                               result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, None, None, c_int(enc))
+                               result=libcrypto.EVP_CIPHER_CTX_set_key_length(self.ctx,len(key))
+                               if result == 0:
+                                       self._clean_ctx()
+                                       raise CipherError("Unable to set key length")
+                               result = libcrypto.EVP_CipherInit_ex(self.ctx, None, None, key_ptr, iv_ptr, c_int(enc))
+                       else:
+                               raise ValueError("Invalid key length for this algorithm")
+               else:
+                       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"
+                       raise CipherError("Unable to initialize cipher")
                self.cipher_type = cipher_type
                self.block_size = self.cipher_type.block_size()
                self.cipher_finalized = False
@@ -145,9 +170,9 @@ class Cipher:
                        called
                """
                if self.cipher_finalized :
-                       raise CipherError, "No updates allowed"
+                       raise CipherError("No updates allowed")
                if type(data) != type(""):
-                       raise TypeError, "A string is expected"
+                       raise TypeError("A string is expected")
                if len(data) <= 0:
                        return ""
                outbuf=create_string_buffer(self.block_size+len(data))
@@ -167,14 +192,14 @@ class Cipher:
                        state, they would be processed and returned.
                """
                if self.cipher_finalized :
-                       raise CipherError, "Cipher operation is already completed"
+                       raise CipherError("Cipher operation is already completed")
                outbuf=create_string_buffer(self.block_size)
                self.cipher_finalized = True
-               outlen=c_int()
+               outlen=c_int(0)
                result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
                if result == 0:
                        self._clean_ctx()
-                       raise CipherError, "Unable to finalize cipher"
+                       raise CipherError("Unable to finalize cipher")
                if outlen.value>0:
                        return outbuf.raw[:outlen.value]
                else:
@@ -208,4 +233,4 @@ 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,)
-
+libcrypto.EVP_CIPHER_CTX_set_key_length.argtypes=(c_void_p,c_int)