+"""
+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
#
+__all__ = ['CipherError','new','Cipher','CipherType']
+
class CipherError(LibCryptoError):
pass
"""
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
"""
Return cipher's algorithm name, derived from OID
"""
- return self.oid().short_name()
+ return self.oid().shortname()
def oid(self):
"""
Returns ASN.1 object identifier of the cipher as
"""
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))
+ enc=1 if encrypt else 0
+ 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
"""
Sets padding mode of the cipher
"""
- if padding:
- padding_flag = 1
- else:
- padding_flag = 0
+ padding_flag=1 if padding else 0
libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
def update(self, data):
called
"""
if self.cipher_finalized :
- raise CipherError, "No updates allowed"
- if type(data) != type(""):
- raise TypeError, "A string is expected"
- if len(data) <= 0:
+ raise CipherError("No updates allowed")
+ if not isinstance(data,str):
+ raise TypeError("A string is expected")
+ if len(data) == 0:
return ""
outbuf=create_string_buffer(self.block_size+len(data))
outlen=c_int(0)
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:
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)
+ libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
+ libcrypto.EVP_CIPHER_CTX_free(self.ctx)
del(self.ctx)
except AttributeError:
pass
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)