1 from ctypes import create_string_buffer,c_char_p,c_void_p,c_int,c_long,byref,POINTER
2 from ctypescrypto import libcrypto
3 from ctypescrypto.exception import LibCryptoError
4 from ctypescrypto.oid import Oid
6 CIPHER_ALGORITHMS = ("DES", "DES-EDE3", "BF", "AES-128", "AES-192", "AES-256")
7 CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")
11 class CipherError(LibCryptoError):
14 def new(algname,key,encrypt=True,iv=None):
16 Returns new cipher object ready to encrypt-decrypt data
18 @param algname - string algorithm name like in opemssl command
20 @param key - binary string representing ciher key
21 @param encrypt - if True (default) cipher would be initialized
22 for encryption, otherwise - for decrypton
23 @param iv - initialization vector
25 ct=CipherType(algname)
26 return Cipher(ct,key,iv,encrypt)
30 Describes cihper algorihm. Can be used to produce cipher
31 instance and to get various information about cihper
34 def __init__(self, cipher_name):
36 Constructs cipher algortihm using textual name as in openssl
39 self.cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
40 if self.cipher is None:
41 raise CipherError, "Unknown cipher: %s" % cipher_name
47 Returns block size of the cipher
49 return libcrypto.EVP_CIPHER_block_size(self.cipher)
52 Returns key length of the cipher
54 return libcrypto.EVP_CIPHER_key_length(self.cipher)
57 Returns initialization vector length of the cipher
59 return libcrypto.EVP_CIPHER_iv_length(self.cipher)
62 Return cipher flags. Low three bits of the flags encode
63 cipher mode (see mode). Higher bits is combinatuon of
64 EVP_CIPH* constants defined in the <openssl/evp.h>
66 return libcrypto.EVP_CIPHER_flags(self.cipher)
69 Returns cipher mode as string constant like CBC, OFB etc.
71 return CIPHER_MODES[self.flags() & 0x7]
74 Return cipher's algorithm name, derived from OID
76 return self.oid().short_name()
79 Returns ASN.1 object identifier of the cipher as
80 ctypescrypto.oid.Oid object
82 return Oid(libcrypto.EVP_CIPHER_nid(self.cipher))
86 Performs actual encrypton decryption
87 Note that object keeps some internal state.
88 To obtain full ciphertext (or plaintext during decihpering)
89 user should concatenate results of all calls of update with
92 def __init__(self, cipher_type, key, iv, encrypt=True):
94 Initializing cipher instance.
96 @param cipher_type - CipherType object
97 @param key = binary string representing the key
98 @param iv - binary string representing initializtion vector
99 @param encrypt - if True(default) we ere encrypting.
104 # Check key and iv length
106 raise ValueError("No key specified")
108 key_ptr = c_char_p(key)
109 iv_ptr = c_char_p(iv)
110 self.ctx = libcrypto.EVP_CIPHER_CTX_new()
112 raise CipherError, "Unable to create cipher context"
113 self.encrypt = encrypt
118 if not iv is None and len(iv) != cipher_type.iv_length():
119 raise ValueError("Invalid IV length for this algorithm")
121 if len(key) != cipher_type.key_length():
122 if (cipher_type.flags() & 8) != 0:
123 # Variable key length cipher.
124 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
125 result=libcrypto.EVP_CIPHER_CTX_set_key_length(self.ctx,len(key))
128 raise CipherError("Unable to set key length")
130 raise ValueError("Invalid key length for this algorithm")
131 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
134 raise CipherError, "Unable to initialize cipher"
135 self.cipher_type = cipher_type
136 self.block_size = self.cipher_type.block_size()
137 self.cipher_finalized = False
142 def padding(self, padding=True):
144 Sets padding mode of the cipher
150 libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
152 def update(self, data):
154 Performs actual encrypton/decrypion
156 @param data - part of the plain text/ciphertext to process
157 @returns - part of ciphercext/plain text
159 Passd chunk of text doeesn't need to contain full ciher
160 blocks. If neccessery, part of passed data would be kept
161 internally until next data would be received or finish
164 if self.cipher_finalized :
165 raise CipherError, "No updates allowed"
166 if type(data) != type(""):
167 raise TypeError, "A string is expected"
170 outbuf=create_string_buffer(self.block_size+len(data))
172 ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),
176 self.cipher_finalized=True
178 raise CipherError("problem processing data")
179 return outbuf.raw[:outlen.value]
183 Finalizes processing. If some data are kept in the internal
184 state, they would be processed and returned.
186 if self.cipher_finalized :
187 raise CipherError, "Cipher operation is already completed"
188 outbuf=create_string_buffer(self.block_size)
189 self.cipher_finalized = True
191 result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
194 raise CipherError, "Unable to finalize cipher"
196 return outbuf.raw[:outlen.value]
200 def _clean_ctx(self):
202 if self.ctx is not None:
203 self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
204 self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)
206 except AttributeError:
208 self.cipher_finalized = True
212 # Used C function block_size
214 libcrypto.EVP_CIPHER_block_size.argtypes=(c_void_p,)
215 libcrypto.EVP_CIPHER_CTX_cleanup.argtypes=(c_void_p,)
216 libcrypto.EVP_CIPHER_CTX_free.argtypes=(c_void_p,)
217 libcrypto.EVP_CIPHER_CTX_new.restype=c_void_p
218 libcrypto.EVP_CIPHER_CTX_set_padding.argtypes=(c_void_p,c_int)
219 libcrypto.EVP_CipherFinal_ex.argtypes=(c_void_p,c_char_p,POINTER(c_int))
220 libcrypto.EVP_CIPHER_flags.argtypes=(c_void_p,)
221 libcrypto.EVP_CipherInit_ex.argtypes=(c_void_p,c_void_p,c_void_p,c_char_p,c_char_p,c_int)
222 libcrypto.EVP_CIPHER_iv_length.argtypes=(c_void_p,)
223 libcrypto.EVP_CIPHER_key_length.argtypes=(c_void_p,)
224 libcrypto.EVP_CIPHER_nid.argtypes=(c_void_p,)
225 libcrypto.EVP_CipherUpdate.argtypes=(c_void_p,c_char_p,POINTER(c_int),c_char_p,c_int)
226 libcrypto.EVP_get_cipherbyname.restype=c_void_p
227 libcrypto.EVP_get_cipherbyname.argtypes=(c_char_p,)
228 libcrypto.EVP_CIPHER_CTX_set_key_length.argtypes=(c_void_p,c_int)