Skip to content

Commit 0355086

Browse files
Merge pull request #32 from jacksonwalters/add_cavp_test_vectors_for_cbc_mode
add CAVP vectors for CBC mode
2 parents 8e36ce3 + 54d6e64 commit 0355086

File tree

4 files changed

+296
-116
lines changed

4 files changed

+296
-116
lines changed

include/cbc.h

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
#ifndef CBC_H
22
#define CBC_H
33

4-
#include <stdint.h>
54
#include <stddef.h>
6-
7-
#ifdef __cplusplus
8-
extern "C" {
9-
#endif
5+
#include <stdint.h>
6+
#include "aes_wrapper.h" // provides encrypt_block_fn and decrypt_block_fn
107

118
#define AES_BLOCK 16
129

13-
/* encryption / decryption function types (adapter style):
14-
* encrypt_fn: encrypt one 16-byte block
15-
* decrypt_fn: decrypt one 16-byte block
16-
*
17-
* Both follow the pattern:
18-
* void fn(const uint8_t in[16], uint8_t out[16], const void *ctx);
19-
* where ctx is a pointer to the AES context (round keys + sbox).
20-
*/
10+
/* ===============================
11+
* Block function typedefs
12+
* =============================== */
2113
typedef void (*encrypt_block_fn)(const uint8_t in[AES_BLOCK],
2214
uint8_t out[AES_BLOCK],
2315
const void *ctx);
@@ -26,38 +18,34 @@ typedef void (*decrypt_block_fn)(const uint8_t in[AES_BLOCK],
2618
uint8_t out[AES_BLOCK],
2719
const void *ctx);
2820

29-
/* AES-CBC encrypt: pads with PKCS#7 to a multiple of 16 bytes.
30-
* - in: plaintext
31-
* - in_len: plaintext length
32-
* - out: buffer to receive ciphertext; must be at least ((in_len / 16) + 1) * 16 bytes
33-
* - out_len: pointer to store resulting ciphertext length
34-
* - iv: 16-byte initialization vector
35-
* - encrypt: block encrypt function
36-
* - ctx: pointer to AES context (round keys + sbox)
37-
*/
38-
int aes_cbc_encrypt(const uint8_t *in, size_t in_len,
39-
uint8_t *out, size_t *out_len,
40-
const uint8_t iv[AES_BLOCK],
41-
encrypt_block_fn encrypt, const void *ctx);
42-
43-
/* AES-CBC decrypt:
44-
* - in: ciphertext (multiple of 16 bytes)
45-
* - in_len: ciphertext length (must be multiple of 16)
46-
* - out: buffer to receive plaintext; must be at least in_len bytes
47-
* - out_len: pointer to store resulting plaintext length
48-
* - iv: 16-byte IV used during encryption
49-
* - decrypt: block decrypt function
50-
* - ctx: pointer to AES context
51-
*
52-
* Returns 0 on success, non-zero on failure (e.g., invalid padding).
53-
*/
54-
int aes_cbc_decrypt(const uint8_t *in, size_t in_len,
55-
uint8_t *out, size_t *out_len,
56-
const uint8_t iv[AES_BLOCK],
57-
decrypt_block_fn decrypt, const void *ctx);
58-
59-
#ifdef __cplusplus
60-
}
61-
#endif
62-
63-
#endif /* CBC_H */
21+
/* ===============================
22+
* Unpadded CBC (raw block-wise)
23+
* =============================== */
24+
int aes_cbc_encrypt_unpadded(const uint8_t *in, size_t in_len,
25+
uint8_t *out, size_t *out_len,
26+
const uint8_t iv[AES_BLOCK],
27+
encrypt_block_fn encrypt,
28+
const void *ctx);
29+
30+
int aes_cbc_decrypt_unpadded(const uint8_t *in, size_t in_len,
31+
uint8_t *out, size_t *out_len,
32+
const uint8_t iv[AES_BLOCK],
33+
decrypt_block_fn decrypt,
34+
const void *ctx);
35+
36+
/* ===============================
37+
* Padded CBC (PKCS#7)
38+
* =============================== */
39+
int aes_cbc_encrypt_padded(const uint8_t *in, size_t in_len,
40+
uint8_t *out, size_t *out_len,
41+
const uint8_t iv[AES_BLOCK],
42+
encrypt_block_fn encrypt,
43+
const void *ctx);
44+
45+
int aes_cbc_decrypt_padded(const uint8_t *in, size_t in_len,
46+
uint8_t *out, size_t *out_len,
47+
const uint8_t iv[AES_BLOCK],
48+
decrypt_block_fn decrypt,
49+
const void *ctx);
50+
51+
#endif /* CBC_H */

src/cbc.c

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
#include <string.h>
44
#include <stdlib.h>
55

6-
/* XOR helper */
6+
/* ===============================
7+
* Helper
8+
* =============================== */
79
static 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

Comments
 (0)