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, None, None, c_int(enc))
125 result=libcrypto.EVP_CIPHER_CTX_set_key_length(self.ctx,len(key))
128 raise CipherError("Unable to set key length")
129 result = libcrypto.EVP_CipherInit_ex(self.ctx, None, None, key_ptr, iv_ptr, c_int(enc))
131 raise ValueError("Invalid key length for this algorithm")
133 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
136 raise CipherError, "Unable to initialize cipher"
137 self.cipher_type = cipher_type
138 self.block_size = self.cipher_type.block_size()
139 self.cipher_finalized = False
144 def padding(self, padding=True):
146 Sets padding mode of the cipher
152 libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
154 def update(self, data):
156 Performs actual encrypton/decrypion
158 @param data - part of the plain text/ciphertext to process
159 @returns - part of ciphercext/plain text
161 Passd chunk of text doeesn't need to contain full ciher
162 blocks. If neccessery, part of passed data would be kept
163 internally until next data would be received or finish
166 if self.cipher_finalized :
167 raise CipherError, "No updates allowed"
168 if type(data) != type(""):
169 raise TypeError, "A string is expected"
172 outbuf=create_string_buffer(self.block_size+len(data))
174 ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),
178 self.cipher_finalized=True
180 raise CipherError("problem processing data")
181 return outbuf.raw[:outlen.value]
185 Finalizes processing. If some data are kept in the internal
186 state, they would be processed and returned.
188 if self.cipher_finalized :
189 raise CipherError, "Cipher operation is already completed"
190 outbuf=create_string_buffer(self.block_size)
191 self.cipher_finalized = True
193 result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
196 raise CipherError, "Unable to finalize cipher"
198 return outbuf.raw[:outlen.value]
202 def _clean_ctx(self):
204 if self.ctx is not None:
205 self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
206 self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)
208 except AttributeError:
210 self.cipher_finalized = True
214 # Used C function block_size
216 libcrypto.EVP_CIPHER_block_size.argtypes=(c_void_p,)
217 libcrypto.EVP_CIPHER_CTX_cleanup.argtypes=(c_void_p,)
218 libcrypto.EVP_CIPHER_CTX_free.argtypes=(c_void_p,)
219 libcrypto.EVP_CIPHER_CTX_new.restype=c_void_p
220 libcrypto.EVP_CIPHER_CTX_set_padding.argtypes=(c_void_p,c_int)
221 libcrypto.EVP_CipherFinal_ex.argtypes=(c_void_p,c_char_p,POINTER(c_int))
222 libcrypto.EVP_CIPHER_flags.argtypes=(c_void_p,)
223 libcrypto.EVP_CipherInit_ex.argtypes=(c_void_p,c_void_p,c_void_p,c_char_p,c_char_p,c_int)
224 libcrypto.EVP_CIPHER_iv_length.argtypes=(c_void_p,)
225 libcrypto.EVP_CIPHER_key_length.argtypes=(c_void_p,)
226 libcrypto.EVP_CIPHER_nid.argtypes=(c_void_p,)
227 libcrypto.EVP_CipherUpdate.argtypes=(c_void_p,c_char_p,POINTER(c_int),c_char_p,c_int)
228 libcrypto.EVP_get_cipherbyname.restype=c_void_p
229 libcrypto.EVP_get_cipherbyname.argtypes=(c_char_p,)
230 libcrypto.EVP_CIPHER_CTX_set_key_length.argtypes=(c_void_p,c_int)