Skip to content

Commit 9e228eb

Browse files
committed
cipher: Do not keep and reuse the IV
The original IV was used for subsequent calls to encrypt or decrypt, which yields wrong results for some cipher modes. Closes #58.
1 parent 76b57a4 commit 9e228eb

File tree

2 files changed

+39
-31
lines changed

2 files changed

+39
-31
lines changed

src/mbedtls/cipher/_cipher.pxd

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,30 @@ cdef extern from "mbedtls/cipher.h" nogil:
9090
mbedtls_cipher_context_t* ctx,
9191
mbedtls_cipher_padding_t mode
9292
)
93-
# mbedtls_cipher_set_iv
94-
95-
# mbedtls_cipher_reset
96-
# mbedtls_cipher_update_ad
97-
# mbedtls_cipher_update
98-
# mbedtls_cipher_finish
93+
int mbedtls_cipher_set_iv(
94+
mbedtls_cipher_context_t* ctx,
95+
const unsigned char *iv, size_t iv_len
96+
)
97+
int mbedtls_cipher_reset(mbedtls_cipher_context_t* ctx)
98+
int mbedtls_cipher_update_ad(
99+
mbedtls_cipher_context_t* ctx,
100+
const unsigned char *ad, size_t ad_len)
101+
int mbedtls_cipher_update(
102+
mbedtls_cipher_context_t* ctx,
103+
const unsigned char *input, size_t ilen,
104+
unsigned char *output, size_t *olen)
105+
int mbedtls_cipher_finish(
106+
mbedtls_cipher_context_t* ctx,
107+
unsigned char *output, size_t *olen)
99108

100109
# mbedtls_cipher_write_tag
101110
# mbedtls_cipher_check_tag
102111

103-
int mbedtls_cipher_crypt(
104-
mbedtls_cipher_context_t* ctx,
105-
const unsigned char* iv, size_t iv_len,
106-
const unsigned char* input, size_t ilen,
107-
unsigned char* output, size_t* olen)
112+
# int mbedtls_cipher_crypt(
113+
# mbedtls_cipher_context_t* ctx,
114+
# const unsigned char* iv, size_t iv_len,
115+
# const unsigned char* input, size_t ilen,
116+
# unsigned char* output, size_t* olen)
108117

109118
int mbedtls_cipher_auth_encrypt(
110119
mbedtls_cipher_context_t* ctx,
@@ -127,20 +136,19 @@ cdef class _CipherBase:
127136
# Encapsulate two contexts to push the keys into mbedtls ASAP.
128137
cdef mbedtls_cipher_context_t _enc_ctx
129138
cdef mbedtls_cipher_context_t _dec_ctx
130-
cdef const unsigned char[:] _iv
131139

132140

133141
cdef class Cipher(_CipherBase):
134142
cdef _crypt(
135143
self,
136-
const unsigned char[:] iv,
144+
mbedtls_cipher_context_t *ctx,
137145
const unsigned char[:] input,
138-
const mbedtls_operation_t operation
139146
)
140147

141148

142149
cdef class AEADCipher(_CipherBase):
143150
cdef const unsigned char[:] _ad
151+
cdef const unsigned char[:] _iv
144152
cdef _aead_encrypt(self,
145153
const unsigned char[:] iv,
146154
const unsigned char[:] ad,

src/mbedtls/cipher/_cipher.pyx

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,18 @@ cdef class _CipherBase:
198198
_cipher.mbedtls_cipher_set_padding_mode(
199199
&self._dec_ctx, _cipher.MBEDTLS_PADDING_NONE)
200200

201-
202201
if key is not None:
203202
_exc.check_error(_cipher.mbedtls_cipher_setkey(
204203
&self._enc_ctx, &key[0], 8 * key.size,
205204
_cipher.MBEDTLS_ENCRYPT))
206205
_exc.check_error(_cipher.mbedtls_cipher_setkey(
207206
&self._dec_ctx, &key[0], 8 * key.size,
208207
_cipher.MBEDTLS_DECRYPT))
209-
self._iv = iv
208+
209+
_exc.check_error(_cipher.mbedtls_cipher_set_iv(
210+
&self._enc_ctx, &iv[0] if iv.size else NULL, iv.size))
211+
_exc.check_error(_cipher.mbedtls_cipher_set_iv(
212+
&self._dec_ctx, &iv[0] if iv.size else NULL, iv.size))
210213

211214
def __cinit__(self):
212215
"""Initialize a `cipher_context` (as NONE)."""
@@ -264,39 +267,35 @@ cdef class _CipherBase:
264267

265268

266269
cdef class Cipher(_CipherBase):
267-
cdef _crypt(self,
268-
const unsigned char[:] iv,
269-
const unsigned char[:] input,
270-
const _cipher.mbedtls_operation_t operation):
271-
"""Generic all-in-one encryption/decryption."""
270+
cdef _crypt(self,
271+
_cipher.mbedtls_cipher_context_t *ctx,
272+
const unsigned char[:] input):
272273
if input.size == 0:
273274
_exc.check_error(-0x6280) # Raise full block expected error.
274275
cdef size_t olen
276+
cdef size_t finish_olen
275277
cdef size_t sz = input.size + self.block_size
276278
cdef unsigned char* output = <unsigned char*>malloc(
277279
sz * sizeof(unsigned char))
278280
if not output:
279281
raise MemoryError()
280282
try:
281-
# We can call `check_error` directly here because we return a
282-
# python object.
283-
err = _cipher.mbedtls_cipher_crypt(
284-
&self._enc_ctx if operation is _cipher.MBEDTLS_ENCRYPT else
285-
&self._dec_ctx,
286-
&iv[0] if iv.size else NULL, iv.size,
287-
&input[0], input.size, output, &olen)
283+
_exc.check_error(_cipher.mbedtls_cipher_reset(ctx))
284+
_exc.check_error(_cipher.mbedtls_cipher_update(
285+
ctx, &input[0], input.size, output, &olen))
286+
err = _cipher.mbedtls_cipher_finish(ctx, output + olen, &finish_olen)
288287
if err == -0x6280:
289288
raise ValueError("expected a full block")
290289
_exc.check_error(err)
291-
return output[:olen]
290+
return output[:olen + finish_olen]
292291
finally:
293292
free(output)
294293

295294
def encrypt(self, const unsigned char[:] message not None):
296-
return self._crypt(self._iv, message, _cipher.MBEDTLS_ENCRYPT)
295+
return self._crypt(&self._enc_ctx, message)
297296

298297
def decrypt(self, const unsigned char[:] message not None):
299-
return self._crypt(self._iv, message, _cipher.MBEDTLS_DECRYPT)
298+
return self._crypt(&self._dec_ctx, message)
300299

301300

302301
cdef class AEADCipher(_CipherBase):
@@ -307,6 +306,7 @@ cdef class AEADCipher(_CipherBase):
307306
const unsigned char[:] iv not None,
308307
const unsigned char[:] ad not None):
309308
super().__init__(cipher_name, key, mode, iv)
309+
self._iv = iv
310310
self._ad = ad
311311

312312
cdef _aead_encrypt(self,

0 commit comments

Comments
 (0)