2 access to symmetric ciphers from libcrypto
5 from ctypes import create_string_buffer,c_char_p,c_void_p,c_int,c_long,byref,POINTER
6 from ctypescrypto import libcrypto
7 from ctypescrypto.exception import LibCryptoError
8 from ctypescrypto.oid import Oid
10 CIPHER_ALGORITHMS = ("DES", "DES-EDE3", "BF", "AES-128", "AES-192", "AES-256")
11 CIPHER_MODES = ("STREAM","ECB","CBC", "CFB", "OFB", "CTR","GCM")
15 __all__ = ['CipherError','new','Cipher','CipherType']
17 class CipherError(LibCryptoError):
20 def new(algname,key,encrypt=True,iv=None):
22 Returns new cipher object ready to encrypt-decrypt data
24 @param algname - string algorithm name like in opemssl command
26 @param key - binary string representing ciher key
27 @param encrypt - if True (default) cipher would be initialized
28 for encryption, otherwise - for decrypton
29 @param iv - initialization vector
31 ct=CipherType(algname)
32 return Cipher(ct,key,iv,encrypt)
36 Describes cihper algorihm. Can be used to produce cipher
37 instance and to get various information about cihper
40 def __init__(self, cipher_name):
42 Constructs cipher algortihm using textual name as in openssl
45 self.cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
46 if self.cipher is None:
47 raise CipherError("Unknown cipher: %s" % cipher_name)
53 Returns block size of the cipher
55 return libcrypto.EVP_CIPHER_block_size(self.cipher)
58 Returns key length of the cipher
60 return libcrypto.EVP_CIPHER_key_length(self.cipher)
63 Returns initialization vector length of the cipher
65 return libcrypto.EVP_CIPHER_iv_length(self.cipher)
68 Return cipher flags. Low three bits of the flags encode
69 cipher mode (see mode). Higher bits is combinatuon of
70 EVP_CIPH* constants defined in the <openssl/evp.h>
72 return libcrypto.EVP_CIPHER_flags(self.cipher)
75 Returns cipher mode as string constant like CBC, OFB etc.
77 return CIPHER_MODES[self.flags() & 0x7]
80 Return cipher's algorithm name, derived from OID
82 return self.oid().short_name()
85 Returns ASN.1 object identifier of the cipher as
86 ctypescrypto.oid.Oid object
88 return Oid(libcrypto.EVP_CIPHER_nid(self.cipher))
92 Performs actual encrypton decryption
93 Note that object keeps some internal state.
94 To obtain full ciphertext (or plaintext during decihpering)
95 user should concatenate results of all calls of update with
98 def __init__(self, cipher_type, key, iv, encrypt=True):
100 Initializing cipher instance.
102 @param cipher_type - CipherType object
103 @param key = binary string representing the key
104 @param iv - binary string representing initializtion vector
105 @param encrypt - if True(default) we ere encrypting.
110 # Check key and iv length
112 raise ValueError("No key specified")
114 key_ptr = c_char_p(key)
115 iv_ptr = c_char_p(iv)
116 self.ctx = libcrypto.EVP_CIPHER_CTX_new()
118 raise CipherError("Unable to create cipher context")
119 self.encrypt = encrypt
124 if not iv is None and len(iv) != cipher_type.iv_length():
125 raise ValueError("Invalid IV length for this algorithm")
127 if len(key) != cipher_type.key_length():
128 if (cipher_type.flags() & 8) != 0:
129 # Variable key length cipher.
130 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, None, None, c_int(enc))
131 result=libcrypto.EVP_CIPHER_CTX_set_key_length(self.ctx,len(key))
134 raise CipherError("Unable to set key length")
135 result = libcrypto.EVP_CipherInit_ex(self.ctx, None, None, key_ptr, iv_ptr, c_int(enc))
137 raise ValueError("Invalid key length for this algorithm")
139 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
142 raise CipherError("Unable to initialize cipher")
143 self.cipher_type = cipher_type
144 self.block_size = self.cipher_type.block_size()
145 self.cipher_finalized = False
150 def padding(self, padding=True):
152 Sets padding mode of the cipher
158 libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
160 def update(self, data):
162 Performs actual encrypton/decrypion
164 @param data - part of the plain text/ciphertext to process
165 @returns - part of ciphercext/plain text
167 Passd chunk of text doeesn't need to contain full ciher
168 blocks. If neccessery, part of passed data would be kept
169 internally until next data would be received or finish
172 if self.cipher_finalized :
173 raise CipherError("No updates allowed")
174 if type(data) != type(""):
175 raise TypeError("A string is expected")
178 outbuf=create_string_buffer(self.block_size+len(data))
180 ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),
184 self.cipher_finalized=True
186 raise CipherError("problem processing data")
187 return outbuf.raw[:outlen.value]
191 Finalizes processing. If some data are kept in the internal
192 state, they would be processed and returned.
194 if self.cipher_finalized :
195 raise CipherError("Cipher operation is already completed")
196 outbuf=create_string_buffer(self.block_size)
197 self.cipher_finalized = True
199 result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
202 raise CipherError("Unable to finalize cipher")
204 return outbuf.raw[:outlen.value]
208 def _clean_ctx(self):
210 if self.ctx is not None:
211 self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
212 self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)
214 except AttributeError:
216 self.cipher_finalized = True
220 # Used C function block_size
222 libcrypto.EVP_CIPHER_block_size.argtypes=(c_void_p,)
223 libcrypto.EVP_CIPHER_CTX_cleanup.argtypes=(c_void_p,)
224 libcrypto.EVP_CIPHER_CTX_free.argtypes=(c_void_p,)
225 libcrypto.EVP_CIPHER_CTX_new.restype=c_void_p
226 libcrypto.EVP_CIPHER_CTX_set_padding.argtypes=(c_void_p,c_int)
227 libcrypto.EVP_CipherFinal_ex.argtypes=(c_void_p,c_char_p,POINTER(c_int))
228 libcrypto.EVP_CIPHER_flags.argtypes=(c_void_p,)
229 libcrypto.EVP_CipherInit_ex.argtypes=(c_void_p,c_void_p,c_void_p,c_char_p,c_char_p,c_int)
230 libcrypto.EVP_CIPHER_iv_length.argtypes=(c_void_p,)
231 libcrypto.EVP_CIPHER_key_length.argtypes=(c_void_p,)
232 libcrypto.EVP_CIPHER_nid.argtypes=(c_void_p,)
233 libcrypto.EVP_CipherUpdate.argtypes=(c_void_p,c_char_p,POINTER(c_int),c_char_p,c_int)
234 libcrypto.EVP_get_cipherbyname.restype=c_void_p
235 libcrypto.EVP_get_cipherbyname.argtypes=(c_char_p,)
236 libcrypto.EVP_CIPHER_CTX_set_key_length.argtypes=(c_void_p,c_int)