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 class CipherError(LibCryptoError):
18 def new(algname,key,encrypt=True,iv=None):
20 Returns new cipher object ready to encrypt-decrypt data
22 @param algname - string algorithm name like in opemssl command
24 @param key - binary string representing ciher key
25 @param encrypt - if True (default) cipher would be initialized
26 for encryption, otherwise - for decrypton
27 @param iv - initialization vector
29 ct=CipherType(algname)
30 return Cipher(ct,key,iv,encrypt)
34 Describes cihper algorihm. Can be used to produce cipher
35 instance and to get various information about cihper
38 def __init__(self, cipher_name):
40 Constructs cipher algortihm using textual name as in openssl
43 self.cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
44 if self.cipher is None:
45 raise CipherError, "Unknown cipher: %s" % cipher_name
51 Returns block size of the cipher
53 return libcrypto.EVP_CIPHER_block_size(self.cipher)
56 Returns key length of the cipher
58 return libcrypto.EVP_CIPHER_key_length(self.cipher)
61 Returns initialization vector length of the cipher
63 return libcrypto.EVP_CIPHER_iv_length(self.cipher)
66 Return cipher flags. Low three bits of the flags encode
67 cipher mode (see mode). Higher bits is combinatuon of
68 EVP_CIPH* constants defined in the <openssl/evp.h>
70 return libcrypto.EVP_CIPHER_flags(self.cipher)
73 Returns cipher mode as string constant like CBC, OFB etc.
75 return CIPHER_MODES[self.flags() & 0x7]
78 Return cipher's algorithm name, derived from OID
80 return self.oid().short_name()
83 Returns ASN.1 object identifier of the cipher as
84 ctypescrypto.oid.Oid object
86 return Oid(libcrypto.EVP_CIPHER_nid(self.cipher))
90 Performs actual encrypton decryption
91 Note that object keeps some internal state.
92 To obtain full ciphertext (or plaintext during decihpering)
93 user should concatenate results of all calls of update with
96 def __init__(self, cipher_type, key, iv, encrypt=True):
98 Initializing cipher instance.
100 @param cipher_type - CipherType object
101 @param key = binary string representing the key
102 @param iv - binary string representing initializtion vector
103 @param encrypt - if True(default) we ere encrypting.
108 # Check key and iv length
110 raise ValueError("No key specified")
112 key_ptr = c_char_p(key)
113 iv_ptr = c_char_p(iv)
114 self.ctx = libcrypto.EVP_CIPHER_CTX_new()
116 raise CipherError, "Unable to create cipher context"
117 self.encrypt = encrypt
122 if not iv is None and len(iv) != cipher_type.iv_length():
123 raise ValueError("Invalid IV length for this algorithm")
125 if len(key) != cipher_type.key_length():
126 if (cipher_type.flags() & 8) != 0:
127 # Variable key length cipher.
128 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, None, None, c_int(enc))
129 result=libcrypto.EVP_CIPHER_CTX_set_key_length(self.ctx,len(key))
132 raise CipherError("Unable to set key length")
133 result = libcrypto.EVP_CipherInit_ex(self.ctx, None, None, key_ptr, iv_ptr, c_int(enc))
135 raise ValueError("Invalid key length for this algorithm")
137 result = libcrypto.EVP_CipherInit_ex(self.ctx, cipher_type.cipher, None, key_ptr, iv_ptr, c_int(enc))
140 raise CipherError, "Unable to initialize cipher"
141 self.cipher_type = cipher_type
142 self.block_size = self.cipher_type.block_size()
143 self.cipher_finalized = False
148 def padding(self, padding=True):
150 Sets padding mode of the cipher
156 libcrypto.EVP_CIPHER_CTX_set_padding(self.ctx, padding_flag)
158 def update(self, data):
160 Performs actual encrypton/decrypion
162 @param data - part of the plain text/ciphertext to process
163 @returns - part of ciphercext/plain text
165 Passd chunk of text doeesn't need to contain full ciher
166 blocks. If neccessery, part of passed data would be kept
167 internally until next data would be received or finish
170 if self.cipher_finalized :
171 raise CipherError, "No updates allowed"
172 if type(data) != type(""):
173 raise TypeError, "A string is expected"
176 outbuf=create_string_buffer(self.block_size+len(data))
178 ret=libcrypto.EVP_CipherUpdate(self.ctx,outbuf,byref(outlen),
182 self.cipher_finalized=True
184 raise CipherError("problem processing data")
185 return outbuf.raw[:outlen.value]
189 Finalizes processing. If some data are kept in the internal
190 state, they would be processed and returned.
192 if self.cipher_finalized :
193 raise CipherError, "Cipher operation is already completed"
194 outbuf=create_string_buffer(self.block_size)
195 self.cipher_finalized = True
197 result = libcrypto.EVP_CipherFinal_ex(self.ctx,outbuf , byref(outlen))
200 raise CipherError, "Unable to finalize cipher"
202 return outbuf.raw[:outlen.value]
206 def _clean_ctx(self):
208 if self.ctx is not None:
209 self.libcrypto.EVP_CIPHER_CTX_cleanup(self.ctx)
210 self.libcrypto.EVP_CIPHER_CTX_free(self.ctx)
212 except AttributeError:
214 self.cipher_finalized = True
218 # Used C function block_size
220 libcrypto.EVP_CIPHER_block_size.argtypes=(c_void_p,)
221 libcrypto.EVP_CIPHER_CTX_cleanup.argtypes=(c_void_p,)
222 libcrypto.EVP_CIPHER_CTX_free.argtypes=(c_void_p,)
223 libcrypto.EVP_CIPHER_CTX_new.restype=c_void_p
224 libcrypto.EVP_CIPHER_CTX_set_padding.argtypes=(c_void_p,c_int)
225 libcrypto.EVP_CipherFinal_ex.argtypes=(c_void_p,c_char_p,POINTER(c_int))
226 libcrypto.EVP_CIPHER_flags.argtypes=(c_void_p,)
227 libcrypto.EVP_CipherInit_ex.argtypes=(c_void_p,c_void_p,c_void_p,c_char_p,c_char_p,c_int)
228 libcrypto.EVP_CIPHER_iv_length.argtypes=(c_void_p,)
229 libcrypto.EVP_CIPHER_key_length.argtypes=(c_void_p,)
230 libcrypto.EVP_CIPHER_nid.argtypes=(c_void_p,)
231 libcrypto.EVP_CipherUpdate.argtypes=(c_void_p,c_char_p,POINTER(c_int),c_char_p,c_int)
232 libcrypto.EVP_get_cipherbyname.restype=c_void_p
233 libcrypto.EVP_get_cipherbyname.argtypes=(c_char_p,)
234 libcrypto.EVP_CIPHER_CTX_set_key_length.argtypes=(c_void_p,c_int)