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().shortname()
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
120 enc=1 if encrypt else 0
121 if not iv is None and len(iv) != cipher_type.iv_length():
122 raise ValueError("Invalid IV length for this algorithm")
124 if len(key) != cipher_type.key_length():
125 if (cipher_type.flags() & 8) != 0:
126 # Variable key length cipher.
127 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, None, None, c_int(enc))
128 result = libcrypto.EVP_CIPHER_CTX_set_key_length(self.ctx,len(key))
131 raise CipherError("Unable to set key length")
132 result = libcrypto.EVP_CipherInit_ex(self.ctx, None, None, key_ptr, iv_ptr, c_int(enc))
134 raise ValueError("Invalid key length for this algorithm")
136 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
139 raise CipherError("Unable to initialize cipher")
140 self.cipher_type = cipher_type
141 self.block_size = self.cipher_type.block_size()
142 self.cipher_finalized = False
147 def padding(self, padding=True):
149 Sets padding mode of the cipher
151 padding_flag=1 if padding else 0
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 not isinstance(data,str):
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 libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
206 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)