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 key_ptr = c_char_p(key)
105 iv_ptr = c_char_p(iv)
106 self.ctx = libcrypto.EVP_CIPHER_CTX_new()
108 raise CipherError, "Unable to create cipher context"
109 self.encrypt = encrypt
114 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
117 raise CipherError, "Unable to initialize cipher"
118 self.cipher_type = cipher_type
119 self.block_size = self.cipher_type.block_size()
120 self.cipher_finalized = False
125 def padding(self, padding=True):
127 Sets padding mode of the cipher
133 libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
135 def update(self, data):
137 Performs actual encrypton/decrypion
139 @param data - part of the plain text/ciphertext to process
140 @returns - part of ciphercext/plain text
142 Passd chunk of text doeesn't need to contain full ciher
143 blocks. If neccessery, part of passed data would be kept
144 internally until next data would be received or finish
147 if self.cipher_finalized :
148 raise CipherError, "No updates allowed"
149 if type(data) != type(""):
150 raise TypeError, "A string is expected"
153 outbuf=create_string_buffer(self.block_size+len(data))
155 ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),
159 self.cipher_finalized=True
161 raise CipherError("problem processing data")
162 return outbuf.raw[:outlen.value]
166 Finalizes processing. If some data are kept in the internal
167 state, they would be processed and returned.
169 if self.cipher_finalized :
170 raise CipherError, "Cipher operation is already completed"
171 outbuf=create_string_buffer(self.block_size)
172 self.cipher_finalized = True
174 result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
177 raise CipherError, "Unable to finalize cipher"
179 return outbuf.raw[:outlen.value]
183 def _clean_ctx(self):
185 if self.ctx is not None:
186 self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
187 self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)
189 except AttributeError:
191 self.cipher_finalized = True
195 # Used C function block_size
197 libcrypto.EVP_CIPHER_block_size.argtypes=(c_void_p,)
198 libcrypto.EVP_CIPHER_CTX_cleanup.argtypes=(c_void_p,)
199 libcrypto.EVP_CIPHER_CTX_free.argtypes=(c_void_p,)
200 libcrypto.EVP_CIPHER_CTX_new.restype=c_void_p
201 libcrypto.EVP_CIPHER_CTX_set_padding.argtypes=(c_void_p,c_int)
202 libcrypto.EVP_CipherFinal_ex.argtypes=(c_void_p,c_char_p,POINTER(c_int))
203 libcrypto.EVP_CIPHER_flags.argtypes=(c_void_p,)
204 libcrypto.EVP_CipherInit_ex.argtypes=(c_void_p,c_void_p,c_void_p,c_char_p,c_char_p,c_int)
205 libcrypto.EVP_CIPHER_iv_length.argtypes=(c_void_p,)
206 libcrypto.EVP_CIPHER_key_length.argtypes=(c_void_p,)
207 libcrypto.EVP_CIPHER_nid.argtypes=(c_void_p,)
208 libcrypto.EVP_CipherUpdate.argtypes=(c_void_p,c_char_p,POINTER(c_int),c_char_p,c_int)
209 libcrypto.EVP_get_cipherbyname.restype=c_void_p
210 libcrypto.EVP_get_cipherbyname.argtypes=(c_char_p,)