33#include <string.h>
44#include <stdlib.h>
55
6- /* XOR helper */
6+ /* ===============================
7+ * Helper
8+ * =============================== */
79static inline void xor_block (uint8_t out [AES_BLOCK ],
810 const uint8_t a [AES_BLOCK ],
911 const uint8_t b [AES_BLOCK ])
@@ -12,41 +14,38 @@ static inline void xor_block(uint8_t out[AES_BLOCK],
1214 out [i ] = a [i ] ^ b [i ];
1315}
1416
15- int aes_cbc_encrypt (const uint8_t * in , size_t in_len ,
16- uint8_t * out , size_t * out_len ,
17- const uint8_t iv [AES_BLOCK ],
18- encrypt_block_fn encrypt , const void * ctx )
17+ /* ===============================
18+ * Core CBC (unpadded)
19+ * =============================== */
20+ int aes_cbc_encrypt_unpadded (const uint8_t * in , size_t in_len ,
21+ uint8_t * out , size_t * out_len ,
22+ const uint8_t iv [AES_BLOCK ],
23+ encrypt_block_fn encrypt ,
24+ const void * ctx )
1925{
20- if (!out || !out_len || !iv || !encrypt ) return -1 ;
21- if (!in && in_len > 0 ) return -1 ; // NULL only allowed if in_len==0
22- if (!in ) in = (const uint8_t * )"" ; // empty input is valid
23-
24- uint8_t * padded = NULL ;
25- size_t padded_len = 0 ;
26- if (pkcs7_pad (in , in_len , AES_BLOCK , & padded , & padded_len ) != PADDING_OK )
27- return -2 ;
26+ if (!in || !out || !out_len || !iv || !encrypt ) return -1 ;
27+ if ((in_len % AES_BLOCK ) != 0 ) return -2 ;
2828
2929 uint8_t prev [AES_BLOCK ];
3030 memcpy (prev , iv , AES_BLOCK );
3131
32- for (size_t off = 0 ; off < padded_len ; off += AES_BLOCK ) {
32+ for (size_t off = 0 ; off < in_len ; off += AES_BLOCK ) {
3333 uint8_t block [AES_BLOCK ];
34- xor_block (block , padded + off , prev );
34+ xor_block (block , in + off , prev );
3535 encrypt (block , out + off , ctx );
3636 memcpy (prev , out + off , AES_BLOCK );
3737 }
3838
39- * out_len = padded_len ;
39+ * out_len = in_len ;
4040 memset (prev , 0 , AES_BLOCK );
41- memset (padded , 0 , padded_len );
42- free (padded );
4341 return 0 ;
4442}
4543
46- int aes_cbc_decrypt (const uint8_t * in , size_t in_len ,
47- uint8_t * out , size_t * out_len ,
48- const uint8_t iv [AES_BLOCK ],
49- decrypt_block_fn decrypt , const void * ctx )
44+ int aes_cbc_decrypt_unpadded (const uint8_t * in , size_t in_len ,
45+ uint8_t * out , size_t * out_len ,
46+ const uint8_t iv [AES_BLOCK ],
47+ decrypt_block_fn decrypt ,
48+ const void * ctx )
5049{
5150 if (!in || !out || !out_len || !iv || !decrypt ) return -1 ;
5251 if ((in_len % AES_BLOCK ) != 0 ) return -2 ;
@@ -61,19 +60,57 @@ int aes_cbc_decrypt(const uint8_t *in, size_t in_len,
6160 memcpy (prev , in + off , AES_BLOCK );
6261 }
6362
64- /* Unpad using reusable PKCS#7 function */
63+ * out_len = in_len ;
64+ memset (prev , 0 , AES_BLOCK );
65+ return 0 ;
66+ }
67+
68+ /* ===============================
69+ * CBC with PKCS#7 padding
70+ * =============================== */
71+ int aes_cbc_encrypt_padded (const uint8_t * in , size_t in_len ,
72+ uint8_t * out , size_t * out_len ,
73+ const uint8_t iv [AES_BLOCK ],
74+ encrypt_block_fn encrypt ,
75+ const void * ctx )
76+ {
77+ uint8_t * padded = NULL ;
78+ size_t padded_len = 0 ;
79+
80+ // Allow NULL input only if length is zero
81+ const uint8_t * ptr = in_len > 0 ? in : (const uint8_t * )"\0" ;
82+
83+ if (pkcs7_pad (ptr , in_len , AES_BLOCK , & padded , & padded_len ) != PADDING_OK )
84+ return -1 ;
85+
86+ int ret = aes_cbc_encrypt_unpadded (padded , padded_len , out , out_len , iv , encrypt , ctx );
87+
88+ memset (padded , 0 , padded_len );
89+ free (padded );
90+ return ret ;
91+ }
92+
93+
94+ int aes_cbc_decrypt_padded (const uint8_t * in , size_t in_len ,
95+ uint8_t * out , size_t * out_len ,
96+ const uint8_t iv [AES_BLOCK ],
97+ decrypt_block_fn decrypt ,
98+ const void * ctx )
99+ {
100+ if ((in_len % AES_BLOCK ) != 0 ) return -1 ;
101+
102+ size_t tmp_len = 0 ;
103+ int ret = aes_cbc_decrypt_unpadded (in , in_len , out , & tmp_len , iv , decrypt , ctx );
104+ if (ret != 0 ) return ret ;
105+
65106 uint8_t * unpadded = NULL ;
66107 size_t plain_len = 0 ;
67- if (pkcs7_unpad (out , in_len , AES_BLOCK , & unpadded , & plain_len ) != PADDING_OK ) {
68- memset (out , 0 , in_len );
69- memset (prev , 0 , AES_BLOCK );
70- return -3 ;
71- }
108+ if (pkcs7_unpad (out , tmp_len , AES_BLOCK , & unpadded , & plain_len ) != PADDING_OK )
109+ return -2 ;
72110
111+ if (out_len ) * out_len = plain_len ;
73112 memcpy (out , unpadded , plain_len );
74- * out_len = plain_len ;
75113 memset (unpadded , 0 , plain_len );
76114 free (unpadded );
77- memset (prev , 0 , AES_BLOCK );
78115 return 0 ;
79116}
0 commit comments